Various Playergroup fixes (#2444)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Wed, 1 Oct 2025 11:11:26 +0000 (13:11 +0200)
committerGitHub <noreply@github.com>
Wed, 1 Oct 2025 11:11:26 +0000 (13:11 +0200)
37 files changed:
music_assistant/controllers/music.py
music_assistant/controllers/players.py [deleted file]
music_assistant/controllers/players/__init__.py [new file with mode: 0644]
music_assistant/controllers/players/player_controller.py [new file with mode: 0644]
music_assistant/controllers/players/sync_groups.py [new file with mode: 0644]
music_assistant/controllers/streams.py
music_assistant/helpers/audio.py
music_assistant/mass.py
music_assistant/models/player.py
music_assistant/models/player_provider.py
music_assistant/providers/_demo_player_provider/__init__.py
music_assistant/providers/airplay/__init__.py
music_assistant/providers/bluesound/__init__.py
music_assistant/providers/deezer/__init__.py
music_assistant/providers/musiccast/__init__.py
music_assistant/providers/podcast-index/__init__.py [deleted file]
music_assistant/providers/podcast-index/constants.py [deleted file]
music_assistant/providers/podcast-index/helpers.py [deleted file]
music_assistant/providers/podcast-index/icon.svg [deleted file]
music_assistant/providers/podcast-index/icon_monochrome.svg [deleted file]
music_assistant/providers/podcast-index/manifest.json [deleted file]
music_assistant/providers/podcast-index/provider.py [deleted file]
music_assistant/providers/podcast_index/__init__.py [new file with mode: 0644]
music_assistant/providers/podcast_index/constants.py [new file with mode: 0644]
music_assistant/providers/podcast_index/helpers.py [new file with mode: 0644]
music_assistant/providers/podcast_index/icon.svg [new file with mode: 0644]
music_assistant/providers/podcast_index/icon_monochrome.svg [new file with mode: 0644]
music_assistant/providers/podcast_index/manifest.json [new file with mode: 0644]
music_assistant/providers/podcast_index/provider.py [new file with mode: 0644]
music_assistant/providers/resonate/provider.py
music_assistant/providers/snapcast/__init__.py
music_assistant/providers/sonos/__init__.py
music_assistant/providers/sonos/player.py
music_assistant/providers/sonos_s1/__init__.py
music_assistant/providers/squeezelite/__init__.py
music_assistant/providers/universal_group/player.py
pyproject.toml

index 33e609d05347a01637af3e598f20fbfb4bbca4c6..a5e79c0a139ce124512c4ecd01f046fd28fb47bc 100644 (file)
@@ -170,6 +170,18 @@ class MusicController(CoreController):
         if self.database:
             await self.database.close()
 
+    async def on_provider_loaded(self, provider: MusicProvider) -> None:
+        """Handle logic when a provider is loaded."""
+        await self.schedule_provider_sync(provider.instance_id)
+
+    async def on_provider_unload(self, provider: MusicProvider) -> None:
+        """Handle logic when a provider is (about to get) unloaded."""
+        # make sure to stop any running sync tasks first
+        for sync_task in self.in_progress_syncs:
+            if sync_task.provider_instance == provider.instance_id:
+                if sync_task.task:
+                    sync_task.task.cancel()
+
     @property
     def providers(self) -> list[MusicProvider]:
         """Return all loaded/running MusicProviders (instances)."""
diff --git a/music_assistant/controllers/players.py b/music_assistant/controllers/players.py
deleted file mode 100644 (file)
index f81b91d..0000000
+++ /dev/null
@@ -1,2060 +0,0 @@
-"""
-MusicAssistant PlayerController.
-
-Handles all logic to control supported players,
-which are provided by Player Providers.
-
-Note that the PlayerController has a concept of a 'player' and a 'playerstate'.
-The Player is the actual object that is provided by the provider,
-which incorporates the actual state of the player (e.g. volume, state, etc)
-and functions for controlling the player (e.g. play, pause, etc).
-
-The playerstate is the (final) state of the player, including any user customizations
-and transformations that are applied to the player.
-The playerstate is the object that is exposed to the outside world (via the API).
-"""
-
-from __future__ import annotations
-
-import asyncio
-import functools
-import time
-from contextlib import suppress
-from typing import TYPE_CHECKING, Any, Concatenate, ParamSpec, TypeVar, cast
-
-from music_assistant_models.constants import (
-    PLAYER_CONTROL_FAKE,
-    PLAYER_CONTROL_NATIVE,
-    PLAYER_CONTROL_NONE,
-)
-from music_assistant_models.enums import (
-    EventType,
-    MediaType,
-    PlaybackState,
-    PlayerFeature,
-    PlayerType,
-    ProviderFeature,
-    ProviderType,
-)
-from music_assistant_models.errors import (
-    AlreadyRegisteredError,
-    MusicAssistantError,
-    PlayerCommandFailed,
-    PlayerUnavailableError,
-    ProviderUnavailableError,
-    UnsupportedFeaturedException,
-)
-from music_assistant_models.player_control import PlayerControl  # noqa: TC002
-
-from music_assistant.constants import (
-    ANNOUNCE_ALERT_FILE,
-    ATTR_ANNOUNCEMENT_IN_PROGRESS,
-    ATTR_FAKE_MUTE,
-    ATTR_FAKE_POWER,
-    ATTR_FAKE_VOLUME,
-    ATTR_GROUP_MEMBERS,
-    ATTR_LAST_POLL,
-    ATTR_PREVIOUS_VOLUME,
-    CONF_AUTO_PLAY,
-    CONF_ENTRY_ANNOUNCE_VOLUME,
-    CONF_ENTRY_ANNOUNCE_VOLUME_MAX,
-    CONF_ENTRY_ANNOUNCE_VOLUME_MIN,
-    CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY,
-    CONF_ENTRY_TTS_PRE_ANNOUNCE,
-    CONF_PLAYER_DSP,
-    CONF_PLAYERS,
-    CONF_PRE_ANNOUNCE_CHIME_URL,
-)
-from music_assistant.controllers.streams import AnnounceData
-from music_assistant.helpers.api import api_command
-from music_assistant.helpers.tags import async_parse_tags
-from music_assistant.helpers.throttle_retry import Throttler
-from music_assistant.helpers.util import TaskManager, validate_announcement_chime_url
-from music_assistant.models.core_controller import CoreController
-from music_assistant.models.player import Player, PlayerMedia, PlayerState
-from music_assistant.models.player_provider import PlayerProvider
-from music_assistant.models.plugin import PluginProvider, PluginSource
-
-if TYPE_CHECKING:
-    from collections.abc import Awaitable, Callable, Coroutine, Iterator
-
-    from music_assistant_models.config_entries import CoreConfig, PlayerConfig
-    from music_assistant_models.player_queue import PlayerQueue
-
-CACHE_CATEGORY_PLAYER_POWER = 1
-
-
-_PlayerControllerT = TypeVar("_PlayerControllerT", bound="PlayerController")
-_R = TypeVar("_R")
-_P = ParamSpec("_P")
-
-
-def handle_player_command[PlayerControllerT: "PlayerController", **P, R](
-    func: Callable[Concatenate[_PlayerControllerT, _P], Awaitable[_R]],
-) -> Callable[Concatenate[_PlayerControllerT, _P], Coroutine[Any, Any, _R | None]]:
-    """Check and log commands to players."""
-
-    @functools.wraps(func)
-    async def wrapper(self: _PlayerControllerT, *args: _P.args, **kwargs: _P.kwargs) -> _R | None:
-        """Log and handle_player_command commands to players."""
-        player_id = kwargs["player_id"] if "player_id" in kwargs else args[0]
-        if (player := self._players.get(player_id)) is None or not player.available:
-            # player not existent
-            self.logger.warning(
-                "Ignoring command %s for unavailable player %s",
-                func.__name__,
-                player_id,
-            )
-            return
-
-        self.logger.debug(
-            "Handling command %s for player %s",
-            func.__name__,
-            player.display_name,
-        )
-        try:
-            await func(self, *args, **kwargs)
-        except Exception as err:
-            raise PlayerCommandFailed(str(err)) from err
-
-    return wrapper
-
-
-class PlayerController(CoreController):
-    """Controller holding all logic to control registered players."""
-
-    domain: str = "players"
-
-    def __init__(self, *args, **kwargs) -> None:
-        """Initialize core controller."""
-        super().__init__(*args, **kwargs)
-        self._players: dict[str, Player] = {}
-        self._controls: dict[str, PlayerControl] = {}
-        self.manifest.name = "Player Controller"
-        self.manifest.description = (
-            "Music Assistant's core controller which manages all players from all providers."
-        )
-        self.manifest.icon = "speaker-multiple"
-        self._poll_task: asyncio.Task | None = None
-        self._player_throttlers: dict[str, Throttler] = {}
-        self._announce_locks: dict[str, asyncio.Lock] = {}
-
-    async def setup(self, config: CoreConfig) -> None:
-        """Async initialize of module."""
-        self._poll_task = self.mass.create_task(self._poll_players())
-
-    async def close(self) -> None:
-        """Cleanup on exit."""
-        if self._poll_task and not self._poll_task.done():
-            self._poll_task.cancel()
-
-    @property
-    def providers(self) -> list[PlayerProvider]:
-        """Return all loaded/running MusicProviders."""
-        return self.mass.get_providers(ProviderType.PLAYER)  # type: ignore=return-value
-
-    def all(
-        self,
-        return_unavailable: bool = True,
-        return_disabled: bool = False,
-        provider_filter: str | None = None,
-    ) -> list[Player]:
-        """
-        Return all registered players.
-
-        :param return_unavailable [bool]: Include unavailable players.
-        :param return_disabled [bool]: Include disabled players.
-        :param provider_filter [str]: Optional filter by provider lookup key.
-
-        :return: List of Player objects.
-        """
-        return [
-            player
-            for player in self._players.values()
-            if (player.available or return_unavailable)
-            and (player.enabled or return_disabled)
-            and (provider_filter is None or player.provider.lookup_key == provider_filter)
-        ]
-
-    @api_command("players/all")
-    def all_states(
-        self,
-        return_unavailable: bool = True,
-        return_disabled: bool = False,
-        provider_filter: str | None = None,
-    ) -> list[PlayerState]:
-        """
-        Return PlayerState for all registered players.
-
-        :param return_unavailable [bool]: Include unavailable players.
-        :param return_disabled [bool]: Include disabled players.
-        :param provider_filter [str]: Optional filter by provider lookup key.
-
-        :return: List of PlayerState objects.
-        """
-        return [
-            player.state
-            for player in self.all(
-                return_unavailable=return_unavailable,
-                return_disabled=return_disabled,
-                provider_filter=provider_filter,
-            )
-        ]
-
-    def get(
-        self,
-        player_id: str,
-        raise_unavailable: bool = False,
-    ) -> Player | None:
-        """
-        Return Player by player_id.
-
-        :param player_id [str]: ID of the player.
-        :param raise_unavailable [bool]: Raise if player is unavailable.
-
-        :raises PlayerUnavailableError: If player is unavailable and raise_unavailable is True.
-        :return: Player object or None.
-        """
-        if player := self._players.get(player_id):
-            if (not player.available or not player.enabled) and raise_unavailable:
-                msg = f"Player {player_id} is not available"
-                raise PlayerUnavailableError(msg)
-            return player
-        if raise_unavailable:
-            msg = f"Player {player_id} is not available"
-            raise PlayerUnavailableError(msg)
-        return None
-
-    @api_command("players/get")
-    def get_state(
-        self,
-        player_id: str,
-        raise_unavailable: bool = False,
-    ) -> PlayerState | None:
-        """
-        Return PlayerState by player_id.
-
-        :param player_id [str]: ID of the player.
-        :param raise_unavailable [bool]: Raise if player is unavailable.
-
-        :raises PlayerUnavailableError: If player is unavailable and raise_unavailable is True.
-        :return: Player object or None.
-        """
-        if player := self.get(player_id, raise_unavailable):
-            return player.state
-        return None
-
-    def get_player_by_name(self, name: str) -> Player | None:
-        """
-        Return Player by name.
-
-        :param name: Name of the player.
-        :return: Player object or None.
-        """
-        return next((x for x in self._players.values() if x.name == name), None)
-
-    @api_command("players/get_by_name")
-    def get_player_state_by_name(self, name: str) -> PlayerState | None:
-        """
-        Return PlayerState by name.
-
-        :param name: Name of the player.
-        :return: PlayerState object or None.
-        """
-        if player := self.get_player_by_name(name):
-            return player.state
-        return None
-
-    @api_command("players/player_controls")
-    def player_controls(
-        self,
-    ) -> list[PlayerControl]:
-        """Return all registered playercontrols."""
-        return list(self._controls.values())
-
-    @api_command("players/player_control")
-    def get_player_control(
-        self,
-        control_id: str,
-    ) -> PlayerControl | None:
-        """
-        Return PlayerControl by control_id.
-
-        :param control_id: ID of the player control.
-        :return: PlayerControl object or None.
-        """
-        if control := self._controls.get(control_id):
-            return control
-        return None
-
-    @api_command("players/plugin_sources")
-    def get_plugin_sources(self) -> list[PluginSource]:
-        """Return all available plugin sources."""
-        return [
-            plugin_prov.get_source()
-            for plugin_prov in self.mass.get_providers(ProviderType.PLUGIN)
-            if isinstance(plugin_prov, PluginProvider)
-            and ProviderFeature.AUDIO_SOURCE in plugin_prov.supported_features
-        ]
-
-    @api_command("players/plugin_source")
-    def get_plugin_source(
-        self,
-        source_id: str,
-    ) -> PluginSource | None:
-        """
-        Return PluginSource by source_id.
-
-        :param source_id: ID of the plugin source.
-        :return: PluginSource object or None.
-        """
-        for plugin_prov in self.mass.get_providers(ProviderType.PLUGIN):
-            assert isinstance(plugin_prov, PluginProvider)  # for type checking
-            if ProviderFeature.AUDIO_SOURCE not in plugin_prov.supported_features:
-                continue
-            if (source := plugin_prov.get_source()) and source.id == source_id:
-                return source
-        return None
-
-    # Player commands
-
-    @api_command("players/cmd/stop")
-    @handle_player_command
-    async def cmd_stop(self, player_id: str) -> None:
-        """Send STOP command to given player.
-
-        - player_id: player_id of the player to handle the command.
-        """
-        player = self._get_player_with_redirect(player_id)
-        # Redirect to queue controller if it is active
-        if active_queue := self.get_active_queue(player):
-            await self.mass.player_queues.stop(active_queue.queue_id)
-            return
-        # handle command on player directly
-        async with self._player_throttlers[player.player_id]:
-            await player.stop()
-
-    @api_command("players/cmd/play")
-    @handle_player_command
-    async def cmd_play(self, player_id: str) -> None:
-        """Send PLAY (unpause) command to given player.
-
-        - player_id: player_id of the player to handle the command.
-        """
-        player = self._get_player_with_redirect(player_id)
-        if player.playback_state == PlaybackState.PLAYING:
-            self.logger.info(
-                "Ignore PLAY request to player %s: player is already playing", player.display_name
-            )
-            return
-        # Redirect to queue controller if it is active
-        if active_queue := self.get_active_queue(player):
-            await self.mass.player_queues.play(active_queue.queue_id)
-            return
-        # handle command on player directly
-        async with self._player_throttlers[player.player_id]:
-            await player.play()
-
-    @api_command("players/cmd/pause")
-    @handle_player_command
-    async def cmd_pause(self, player_id: str) -> None:
-        """Send PAUSE command to given player.
-
-        - player_id: player_id of the player to handle the command.
-        """
-        player = self._get_player_with_redirect(player_id)
-        # Redirect to queue controller if it is active
-        if active_queue := self.get_active_queue(player):
-            await self.mass.player_queues.pause(active_queue.queue_id)
-            return
-        if PlayerFeature.PAUSE not in player.supported_features:
-            # if player does not support pause, we need to send stop
-            self.logger.debug(
-                "Player %s does not support pause, using STOP instead",
-                player.display_name,
-            )
-            await self.cmd_stop(player.player_id)
-            return
-        # handle command on player directly
-        await player.pause()
-
-    @api_command("players/cmd/play_pause")
-    async def cmd_play_pause(self, player_id: str) -> None:
-        """Toggle play/pause on given player.
-
-        - player_id: player_id of the player to handle the command.
-        """
-        player = self._get_player_with_redirect(player_id)
-        if player.playback_state == PlaybackState.PLAYING:
-            await self.cmd_pause(player.player_id)
-        else:
-            await self.cmd_play(player.player_id)
-
-    @api_command("players/cmd/seek")
-    async def cmd_seek(self, player_id: str, position: int) -> None:
-        """Handle SEEK command for given player.
-
-        - player_id: player_id of the player to handle the command.
-        - position: position in seconds to seek to in the current playing item.
-        """
-        player = self._get_player_with_redirect(player_id)
-        # Redirect to queue controller if it is active
-        if active_queue := self.get_active_queue(player):
-            await self.mass.player_queues.seek(active_queue.queue_id, position)
-            return
-        if PlayerFeature.SEEK not in player.supported_features:
-            msg = f"Player {player.display_name} does not support seeking"
-            raise UnsupportedFeaturedException(msg)
-        # handle command on player directly
-        await player.seek(position)
-
-    @api_command("players/cmd/next")
-    async def cmd_next_track(self, player_id: str) -> None:
-        """Handle NEXT TRACK command for given player."""
-        player = self._get_player_with_redirect(player_id)
-        active_source_id = player.active_source or player.player_id
-
-        # Redirect to queue controller if it is active
-        if active_queue := self.get_active_queue(player):
-            await self.mass.player_queues.next(active_queue.queue_id)
-            return
-
-        if PlayerFeature.NEXT_PREVIOUS in player.supported_features:
-            # player has some other source active and native next/previous support
-            active_source = next((x for x in player.source_list if x.id == active_source_id), None)
-            if active_source and active_source.can_next_previous:
-                await player.next_track()
-                return
-            msg = "This action is (currently) unavailable for this source."
-            raise PlayerCommandFailed(msg)
-
-        msg = f"Player {player.display_name} does not support skipping to the next track."
-        raise UnsupportedFeaturedException(msg)
-
-    @api_command("players/cmd/previous")
-    async def cmd_previous_track(self, player_id: str) -> None:
-        """Handle PREVIOUS TRACK command for given player."""
-        player = self._get_player_with_redirect(player_id)
-        active_source_id = player.active_source or player.player_id
-        # Redirect to queue controller if it is active
-        if active_queue := self.get_active_queue(player):
-            await self.mass.player_queues.previous(active_queue.queue_id)
-            return
-
-        if PlayerFeature.NEXT_PREVIOUS in player.supported_features:
-            # player has some other source active and native next/previous support
-            active_source = next((x for x in player.source_list if x.id == active_source_id), None)
-            if active_source and active_source.can_next_previous:
-                await player.previous_track()
-                return
-            msg = "This action is (currently) unavailable for this source."
-            raise PlayerCommandFailed(msg)
-
-        msg = f"Player {player.display_name} does not support skipping to the previous track."
-        raise UnsupportedFeaturedException(msg)
-
-    @api_command("players/cmd/power")
-    @handle_player_command
-    async def cmd_power(self, player_id: str, powered: bool, skip_update: bool = False) -> None:
-        """Send POWER command to given player.
-
-        - player_id: player_id of the player to handle the command.
-        - powered: bool if player should be powered on or off.
-        """
-        player = self.get(player_id, True)
-        assert player is not None  # for type checking
-        player_state = player.state
-
-        if player_state.powered == powered:
-            self.logger.debug(
-                "Ignoring power %s command for player %s: already in state %s",
-                "ON" if powered else "OFF",
-                player_state.name,
-                "ON" if player_state.powered else "OFF",
-            )
-            return  # nothing to do
-
-        # ungroup player at power off
-        player_was_synced = player.synced_to is not None
-        if player.type == PlayerType.PLAYER and not powered:
-            # ungroup player if it is synced (or is a sync leader itself)
-            # NOTE: ungroup will be ignored if the player is not grouped or synced
-            await self.cmd_ungroup(player_id)
-
-        # always stop player at power off
-        if (
-            not powered
-            and not player_was_synced
-            and player.playback_state in (PlaybackState.PLAYING, PlaybackState.PAUSED)
-        ):
-            await self.cmd_stop(player_id)
-            # short sleep: allow the stop command to process and prevent race conditions
-            await asyncio.sleep(0.2)
-
-        # power off all synced childs when player is a sync leader
-        elif not powered and player.type == PlayerType.PLAYER and player.group_members:
-            async with TaskManager(self.mass) as tg:
-                for member in self.iter_group_members(player, True):
-                    if member.power_control == PLAYER_CONTROL_NONE:
-                        continue
-                    tg.create_task(self.cmd_power(member.player_id, False))
-
-        # handle actual power command
-        if player.power_control == PLAYER_CONTROL_NONE:
-            raise UnsupportedFeaturedException(
-                f"Player {player.display_name} does not support power control"
-            )
-        if player.power_control == PLAYER_CONTROL_NATIVE:
-            # player supports power command natively: forward to player provider
-            async with self._player_throttlers[player_id]:
-                await player.power(powered)
-        elif player.power_control == PLAYER_CONTROL_FAKE:
-            # user wants to use fake power control - so we (optimistically) update the state
-            # and store the state in the cache
-            player.extra_data[ATTR_FAKE_POWER] = powered
-            await self.mass.cache.set(
-                key=player_id,
-                data=powered,
-                provider=self.domain,
-                category=CACHE_CATEGORY_PLAYER_POWER,
-            )
-        else:
-            # handle external player control
-            player_control = self._controls.get(player.power_control)
-            control_name = player_control.name if player_control else player.power_control
-            self.logger.debug("Redirecting power command to PlayerControl %s", control_name)
-            if not player_control or not player_control.supports_power:
-                raise UnsupportedFeaturedException(
-                    f"Player control {control_name} is not available"
-                )
-            if powered:
-                assert player_control.power_on is not None  # for type checking
-                await player_control.power_on()
-            else:
-                assert player_control.power_off is not None  # for type checking
-                await player_control.power_off()
-
-        # always optimistically set the power state to update the UI
-        # as fast as possible and prevent race conditions
-        player_state.powered = powered
-        # reset active source on power off
-        if not powered:
-            player_state.active_source = None
-
-        if not skip_update:
-            player.update_state()
-
-        # handle 'auto play on power on' feature
-        if (
-            not player.active_group
-            and powered
-            and player.config.get_value(CONF_AUTO_PLAY)
-            and player.active_source in (None, player_id)
-            and not player.extra_data.get(ATTR_ANNOUNCEMENT_IN_PROGRESS)
-        ):
-            await self.mass.player_queues.resume(player_id)
-
-    @api_command("players/cmd/volume_set")
-    @handle_player_command
-    async def cmd_volume_set(self, player_id: str, volume_level: int) -> None:
-        """Send VOLUME_SET command to given player.
-
-        - player_id: player_id of the player to handle the command.
-        - volume_level: volume level (0..100) to set on the player.
-        """
-        player = self.get(player_id, True)
-        assert player is not None  # for type checker
-        if player.type == PlayerType.GROUP:
-            # redirect to special group volume control
-            await self.cmd_group_volume(player_id, volume_level)
-            return
-
-        if player.volume_control == PLAYER_CONTROL_NONE:
-            raise UnsupportedFeaturedException(
-                f"Player {player.display_name} does not support volume control"
-            )
-
-        if player.mute_control != PLAYER_CONTROL_NONE and player.volume_muted:
-            # if player is muted, we unmute it first
-            self.logger.debug(
-                "Unmuting player %s before setting volume",
-                player.display_name,
-            )
-            await self.cmd_volume_mute(player_id, False)
-
-        if player.volume_control == PLAYER_CONTROL_NATIVE:
-            # player supports volume command natively: forward to player
-            async with self._player_throttlers[player_id]:
-                await player.volume_set(volume_level)
-            return
-        if player.volume_control == PLAYER_CONTROL_FAKE:
-            # user wants to use fake volume control - so we (optimistically) update the state
-            # and store the state in the cache
-            player.extra_data[ATTR_FAKE_VOLUME] = volume_level
-            # trigger update
-            player.update_state()
-            return
-        # else: handle external player control
-        player_control = self._controls.get(player.volume_control)
-        control_name = player_control.name if player_control else player.volume_control
-        self.logger.debug("Redirecting volume command to PlayerControl %s", control_name)
-        if not player_control or not player_control.supports_volume:
-            raise UnsupportedFeaturedException(f"Player control {control_name} is not available")
-        async with self._player_throttlers[player_id]:
-            assert player_control.volume_set is not None
-            await player_control.volume_set(volume_level)
-
-    @api_command("players/cmd/volume_up")
-    @handle_player_command
-    async def cmd_volume_up(self, player_id: str) -> None:
-        """Send VOLUME_UP command to given player.
-
-        - player_id: player_id of the player to handle the command.
-        """
-        if not (player := self.get(player_id)):
-            return
-        current_volume = player.volume_state or 0
-        if current_volume < 5 or current_volume > 95:
-            step_size = 1
-        elif current_volume < 20 or current_volume > 80:
-            step_size = 2
-        else:
-            step_size = 5
-        new_volume = min(100, current_volume + step_size)
-        await self.cmd_volume_set(player_id, new_volume)
-
-    @api_command("players/cmd/volume_down")
-    @handle_player_command
-    async def cmd_volume_down(self, player_id: str) -> None:
-        """Send VOLUME_DOWN command to given player.
-
-        - player_id: player_id of the player to handle the command.
-        """
-        if not (player := self.get(player_id)):
-            return
-        current_volume = player.volume_state or 0
-        if current_volume < 5 or current_volume > 95:
-            step_size = 1
-        elif current_volume < 20 or current_volume > 80:
-            step_size = 2
-        else:
-            step_size = 5
-        new_volume = max(0, current_volume - step_size)
-        await self.cmd_volume_set(player_id, new_volume)
-
-    @api_command("players/cmd/group_volume")
-    @handle_player_command
-    async def cmd_group_volume(
-        self,
-        player_id: str,
-        volume_level: int,
-    ) -> None:
-        """
-        Handle adjusting the overall/group volume to a playergroup (or synced players).
-
-        Will set a new (overall) volume level to a group player or syncgroup.
-
-        :param group_player: dedicated group player or syncleader to handle the command.
-        :param volume_level: volume level (0..100) to set to the group.
-        """
-        player = self.get(player_id, True)
-        assert player is not None  # for type checker
-        if player.type == PlayerType.GROUP or player.group_members:
-            # dedicated group player or sync leader
-            await self.set_group_volume(player, volume_level)
-            return
-        if player.synced_to and (sync_leader := self.get(player.synced_to)):
-            # redirect to sync leader
-            await self.set_group_volume(sync_leader, volume_level)
-            return
-        # treat as normal player volume change
-        await self.cmd_volume_set(player_id, volume_level)
-
-    @api_command("players/cmd/group_volume_up")
-    @handle_player_command
-    async def cmd_group_volume_up(self, player_id: str) -> None:
-        """Send VOLUME_UP command to given playergroup.
-
-        - player_id: player_id of the player to handle the command.
-        """
-        group_player = self.get(player_id, True)
-        assert group_player
-        cur_volume = group_player.group_volume
-        if cur_volume < 5 or cur_volume > 95:
-            step_size = 1
-        elif cur_volume < 20 or cur_volume > 80:
-            step_size = 2
-        else:
-            step_size = 5
-        new_volume = min(100, cur_volume + step_size)
-        await self.cmd_group_volume(player_id, new_volume)
-
-    @api_command("players/cmd/group_volume_down")
-    @handle_player_command
-    async def cmd_group_volume_down(self, player_id: str) -> None:
-        """Send VOLUME_DOWN command to given playergroup.
-
-        - player_id: player_id of the player to handle the command.
-        """
-        group_player = self.get(player_id, True)
-        assert group_player
-        cur_volume = group_player.group_volume
-        if cur_volume < 5 or cur_volume > 95:
-            step_size = 1
-        elif cur_volume < 20 or cur_volume > 80:
-            step_size = 2
-        else:
-            step_size = 5
-        new_volume = max(0, cur_volume - step_size)
-        await self.cmd_group_volume(player_id, new_volume)
-
-    @api_command("players/cmd/volume_mute")
-    @handle_player_command
-    async def cmd_volume_mute(self, player_id: str, muted: bool) -> None:
-        """Send VOLUME_MUTE command to given player.
-
-        - player_id: player_id of the player to handle the command.
-        - muted: bool if player should be muted.
-        """
-        player = self.get(player_id, True)
-        assert player
-        if player.mute_control == PLAYER_CONTROL_NONE:
-            raise UnsupportedFeaturedException(
-                f"Player {player.display_name} does not support muting"
-            )
-        if player.mute_control == PLAYER_CONTROL_NATIVE:
-            # player supports mute command natively: forward to player
-            async with self._player_throttlers[player_id]:
-                await player.volume_mute(muted)
-        elif player.mute_control == PLAYER_CONTROL_FAKE:
-            # user wants to use fake mute control - so we use volume instead
-            self.logger.debug(
-                "Using volume for muting for player %s",
-                player.display_name,
-            )
-            if muted:
-                player.extra_data[ATTR_PREVIOUS_VOLUME] = player.volume_state
-                player.extra_data[ATTR_FAKE_MUTE] = True
-                await self.cmd_volume_set(player_id, 0)
-            else:
-                player._attr_volume_muted = False
-                prev_volume = player.extra_data.get(ATTR_PREVIOUS_VOLUME, 1)
-                player.extra_data[ATTR_FAKE_MUTE] = False
-                await self.cmd_volume_set(player_id, prev_volume)
-        else:
-            # handle external player control
-            player_control = self._controls.get(player.mute_control)
-            control_name = player_control.name if player_control else player.mute_control
-            self.logger.debug("Redirecting mute command to PlayerControl %s", control_name)
-            if not player_control or not player_control.supports_mute:
-                raise UnsupportedFeaturedException(
-                    f"Player control {control_name} is not available"
-                )
-            async with self._player_throttlers[player_id]:
-                assert player_control.mute_set is not None
-                await player_control.mute_set(muted)
-
-    @api_command("players/cmd/play_announcement")
-    async def play_announcement(
-        self,
-        player_id: str,
-        url: str,
-        pre_announce: bool | str | None = None,
-        volume_level: int | None = None,
-        pre_announce_url: str | None = None,
-    ) -> None:
-        """
-        Handle playback of an announcement (url) on given player.
-
-        - player_id: player_id of the player to handle the command.
-        - url: URL of the announcement to play.
-        - pre_announce: optional bool if pre-announce should be used.
-        - volume_level: optional volume level to set for the announcement.
-        - pre_announce_url: optional custom URL to use for the pre-announce chime.
-        """
-        player = self.get(player_id, True)
-        assert player is not None  # for type checking
-        if not url.startswith("http"):
-            raise PlayerCommandFailed("Only URLs are supported for announcements")
-        if (
-            pre_announce
-            and pre_announce_url
-            and not validate_announcement_chime_url(pre_announce_url)
-        ):
-            raise PlayerCommandFailed("Invalid pre-announce chime URL specified.")
-        # prevent multiple announcements at the same time to the same player with a lock
-        if player_id not in self._announce_locks:
-            self._announce_locks[player_id] = lock = asyncio.Lock()
-        else:
-            lock = self._announce_locks[player_id]
-        async with lock:
-            try:
-                # mark announcement_in_progress on player
-                player.extra_data[ATTR_ANNOUNCEMENT_IN_PROGRESS] = True
-                # determine if the player has native announcements support
-                native_announce_support = (
-                    PlayerFeature.PLAY_ANNOUNCEMENT in player.supported_features
-                )
-                # determine pre-announce from (group)player config
-                if pre_announce is None and "tts" in url:
-                    conf_pre_announce = self.mass.config.get_raw_player_config_value(
-                        player_id,
-                        CONF_ENTRY_TTS_PRE_ANNOUNCE.key,
-                        CONF_ENTRY_TTS_PRE_ANNOUNCE.default_value,
-                    )
-                    pre_announce = cast("bool", conf_pre_announce)
-                if pre_announce_url is None:
-                    if conf_pre_announce_url := self.mass.config.get_raw_player_config_value(
-                        player_id,
-                        CONF_PRE_ANNOUNCE_CHIME_URL,
-                    ):
-                        # player default custom chime url
-                        pre_announce_url = cast("str", conf_pre_announce_url)
-                    else:
-                        # use global default chime url
-                        pre_announce_url = ANNOUNCE_ALERT_FILE
-                # if player type is group with all members supporting announcements,
-                # we forward the request to each individual player
-                if player.type == PlayerType.GROUP and (
-                    all(
-                        PlayerFeature.PLAY_ANNOUNCEMENT in x.supported_features
-                        for x in self.iter_group_members(player)
-                    )
-                ):
-                    # forward the request to each individual player
-                    async with TaskManager(self.mass) as tg:
-                        for group_member in player.group_members:
-                            tg.create_task(
-                                self.play_announcement(
-                                    group_member,
-                                    url=url,
-                                    pre_announce=pre_announce,
-                                    volume_level=volume_level,
-                                    pre_announce_url=pre_announce_url,
-                                )
-                            )
-                    return
-                self.logger.info(
-                    "Playback announcement to player %s (with pre-announce: %s): %s",
-                    player.display_name,
-                    pre_announce,
-                    url,
-                )
-                # create a PlayerMedia object for the announcement so
-                # we can send a regular play-media call downstream
-                announce_data = AnnounceData(
-                    announcement_url=url,
-                    pre_announce=pre_announce,
-                    pre_announce_url=pre_announce_url,
-                )
-                announcement = PlayerMedia(
-                    uri=self.mass.streams.get_announcement_url(player_id, url, announce_data),
-                    media_type=MediaType.ANNOUNCEMENT,
-                    title="Announcement",
-                    custom_data=announce_data,
-                )
-                # handle native announce support
-                if native_announce_support:
-                    announcement_volume = self.get_announcement_volume(player_id, volume_level)
-                    await player.play_announcement(announcement, announcement_volume)
-                    return
-                # use fallback/default implementation
-                await self._play_announcement(player, announcement, volume_level)
-            finally:
-                player.extra_data[ATTR_ANNOUNCEMENT_IN_PROGRESS] = False
-
-    @handle_player_command
-    async def play_media(self, player_id: str, media: PlayerMedia) -> None:
-        """Handle PLAY MEDIA on given player.
-
-        - player_id: player_id of the player to handle the command.
-        - media: The Media that needs to be played on the player.
-        """
-        player = self._get_player_with_redirect(player_id)
-        # power on the player if needed
-        if player.powered is False and player.power_control != PLAYER_CONTROL_NONE:
-            await self.cmd_power(player.player_id, True)
-        await player.play_media(media)
-
-    @api_command("players/cmd/select_source")
-    async def select_source(self, player_id: str, source: str) -> None:
-        """
-        Handle SELECT SOURCE command on given player.
-
-        - player_id: player_id of the player to handle the command.
-        - source: The ID of the source that needs to be activated/selected.
-        """
-        player = self.get(player_id, True)
-        assert player is not None  # for type checking
-        if player.synced_to or player.active_group:
-            raise PlayerCommandFailed(f"Player {player.display_name} is currently grouped")
-        # check if player is already playing and source is different
-        # in that case we need to stop the player first
-        prev_source = player.active_source
-        if prev_source and source != prev_source:
-            if player.playback_state != PlaybackState.IDLE:
-                await self.cmd_stop(player_id)
-                await asyncio.sleep(0.5)  # small delay to allow stop to process
-            player.active_source = None
-            player.current_media = None
-        # check if source is a pluginsource
-        # in that case the source id is the instance_id of the plugin provider
-        if plugin_prov := self.mass.get_provider(source):
-            await self._handle_select_plugin_source(player, plugin_prov)
-            return
-        # check if source is a mass queue
-        # this can be used to restore the queue after a source switch
-        if mass_queue := self.mass.player_queues.get(source):
-            await self.mass.player_queues.play(mass_queue.queue_id)
-            return
-        # basic check if player supports source selection
-        if PlayerFeature.SELECT_SOURCE not in player.supported_features:
-            raise UnsupportedFeaturedException(
-                f"Player {player.display_name} does not support source selection"
-            )
-        # basic check if source is valid for player
-        if not any(x for x in player.source_list if x.id == source):
-            raise PlayerCommandFailed(
-                f"{source} is an invalid source for player {player.display_name}"
-            )
-        # forward to player
-        await player.select_source(source)
-
-    async def enqueue_next_media(self, player_id: str, media: PlayerMedia) -> None:
-        """
-        Handle enqueuing of a next media item on the player.
-
-        :param player_id: player_id of the player to handle the command.
-        :param media: The Media that needs to be enqueued on the player.
-        :raises UnsupportedFeaturedException: if the player does not support enqueueing.
-        :raises PlayerUnavailableError: if the player is not available.
-        """
-        player = self.get(player_id, raise_unavailable=True)
-        assert player is not None  # for type checking
-        if PlayerFeature.ENQUEUE not in player.supported_features:
-            raise UnsupportedFeaturedException(
-                f"Player {player.display_name} does not support enqueueing"
-            )
-        async with self._player_throttlers[player_id]:
-            await player.enqueue_next_media(media)
-
-    @api_command("players/cmd/set_members")
-    async def cmd_set_members(
-        self,
-        target_player: str,
-        player_ids_to_add: list[str] | None = None,
-        player_ids_to_remove: list[str] | None = None,
-    ) -> None:
-        """
-        Join/unjoin given player(s) to/from target player.
-
-        Will add the given player(s) to the target player (sync leader or group player).
-
-        :param target_player: player_id of the syncgroup leader or group player.
-        :param player_ids_to_add: List of player_id's to add to the target player.
-        :param player_ids_to_remove: List of player_id's to remove from the target player.
-
-        :raises UnsupportedFeaturedException: if the target player does not support grouping.
-        :raises PlayerUnavailableError: if the target player is not available.
-        """
-        parent_player: Player | None = self.get(target_player, True)
-        assert parent_player is not None  # for type checking
-        if PlayerFeature.SET_MEMBERS not in parent_player.supported_features:
-            msg = f"Player {parent_player.name} does not support group commands"
-            raise UnsupportedFeaturedException(msg)
-
-        if parent_player.synced_to:
-            # guard edge case: player already synced to another player
-            raise PlayerCommandFailed(
-                f"Player {parent_player.name} is already synced to another player on its own, "
-                "you need to ungroup it first before you can join other players to it.",
-            )
-
-        # filter all player ids on compatibility and availability
-        final_player_ids_to_add: list[str] = []
-        for child_player_id in player_ids_to_add or []:
-            if child_player_id == target_player:
-                continue
-            if child_player_id in final_player_ids_to_add:
-                continue
-            if not (child_player := self.get(child_player_id)) or not child_player.available:
-                self.logger.warning("Player %s is not available", child_player_id)
-                continue
-
-            # check if player can be synced/grouped with the target player
-            if not (
-                child_player_id in parent_player.can_group_with
-                or child_player.provider.lookup_key in parent_player.can_group_with
-                or "*" in parent_player.can_group_with
-            ):
-                raise UnsupportedFeaturedException(
-                    f"Player {child_player.name} can not be grouped with {parent_player.name}"
-                )
-
-            if (
-                child_player.synced_to
-                and child_player.synced_to == target_player
-                and child_player_id in parent_player.group_members
-            ):
-                continue  # already synced to this target
-
-            # Check if player is already part of another group and try to automatically ungroup it
-            # first. If that fails, power off the group
-            if child_player.active_group and child_player.active_group != target_player:
-                if (
-                    other_group := self.get(child_player.active_group)
-                ) and PlayerFeature.SET_MEMBERS in other_group.supported_features:
-                    self.logger.warning(
-                        "Player %s is already part of another group (%s), "
-                        "removing from that group first",
-                        child_player.name,
-                        child_player.active_group,
-                    )
-                    if child_player.player_id in other_group.static_group_members:
-                        self.logger.warning(
-                            "Player %s is a static member of group %s: removing is not possible, "
-                            "powering the group off instead",
-                            child_player.name,
-                            child_player.active_group,
-                        )
-                        await self.cmd_power(child_player.active_group, False)
-                    else:
-                        await other_group.set_members(player_ids_to_remove=[child_player.player_id])
-                else:
-                    self.logger.warning(
-                        "Player %s is already part of another group (%s), powering it off first",
-                        child_player.name,
-                        child_player.active_group,
-                    )
-                    await self.cmd_power(child_player.active_group, False)
-            elif child_player.synced_to and child_player.synced_to != target_player:
-                self.logger.warning(
-                    "Player %s is already synced to another player, ungrouping first",
-                    child_player.name,
-                )
-                await self.cmd_ungroup(child_player.player_id)
-
-            # power on the player if needed
-            if not child_player.powered and child_player.power_control != PLAYER_CONTROL_NONE:
-                await self.cmd_power(child_player.player_id, True, skip_update=True)
-            # if we reach here, all checks passed
-            final_player_ids_to_add.append(child_player_id)
-
-        final_player_ids_to_remove: list[str] = []
-        if player_ids_to_remove:
-            static_members = set(parent_player.static_group_members)
-            for child_player_id in player_ids_to_remove:
-                if child_player_id == target_player:
-                    raise UnsupportedFeaturedException(
-                        f"Cannot remove {parent_player.name} from itself as a member!"
-                    )
-                if child_player_id not in parent_player.group_members:
-                    continue
-                if child_player_id in static_members:
-                    raise UnsupportedFeaturedException(
-                        f"Cannot remove {child_player_id} from {parent_player.name} "
-                        "as it is a static member of this group"
-                    )
-                final_player_ids_to_remove.append(child_player_id)
-
-        # forward command to the player after all (base) sanity checks
-        async with self._player_throttlers[target_player]:
-            await parent_player.set_members(
-                player_ids_to_add=final_player_ids_to_add or None,
-                player_ids_to_remove=final_player_ids_to_remove or None,
-            )
-
-    @api_command("players/cmd/group")
-    @handle_player_command
-    async def cmd_group(self, player_id: str, target_player: str) -> None:
-        """Handle GROUP command for given player.
-
-        Join/add the given player(id) to the given (leader) player/sync group.
-        If the target player itself is already synced to another player, this may fail.
-        If the player can not be synced with the given target player, this may fail.
-
-        :param player_id: player_id of the player to handle the command.
-        :param target_player: player_id of the syncgroup leader or group player.
-
-        :raises UnsupportedFeaturedException: if the target player does not support grouping.
-        :raises PlayerCommandFailed: if the target player is already synced to another player.
-        :raises PlayerUnavailableError: if the target player is not available.
-        :raises PlayerCommandFailed: if the player is already grouped to another player.
-        """
-        await self.cmd_set_members(target_player, player_ids_to_add=[player_id])
-
-    @api_command("players/cmd/group_many")
-    async def cmd_group_many(self, target_player: str, child_player_ids: list[str]) -> None:
-        """
-        Join given player(s) to target player.
-
-        Will add the given player(s) to the target player (sync leader or group player).
-        NOTE: This is a (deprecated) alias for cmd_set_members.
-        """
-        await self.cmd_set_members(target_player, player_ids_to_add=child_player_ids)
-
-    @api_command("players/cmd/ungroup")
-    @handle_player_command
-    async def cmd_ungroup(self, player_id: str) -> None:
-        """Handle UNGROUP command for given player.
-
-        Remove the given player from any (sync)groups it currently is synced to.
-        If the player is not currently grouped to any other player,
-        this will silently be ignored.
-
-        NOTE: This is a (deprecated) alias for cmd_set_members.
-        """
-        if not (player := self.get(player_id)):
-            self.logger.warning("Player %s is not available", player_id)
-            return
-
-        if (
-            player.active_group
-            and (group_player := self.get(player.active_group))
-            and (PlayerFeature.SET_MEMBERS in group_player.supported_features)
-        ):
-            # the player is part of a (permanent) groupplayer and the user tries to ungroup
-            if player_id in group_player.static_group_members:
-                raise UnsupportedFeaturedException(
-                    f"Player {player.name}  is a static member of group {group_player.name} "
-                    "and cannot be removed from that group!"
-                )
-            await group_player.set_members(player_ids_to_remove=[player_id])
-            return
-
-        if player.synced_to and (synced_player := self.get(player.synced_to)):
-            # player is a sync member
-            await synced_player.set_members(player_ids_to_remove=[player_id])
-            return
-
-        if not (player.synced_to or player.group_members):
-            return  # nothing to do
-
-        if PlayerFeature.SET_MEMBERS not in player.supported_features:
-            self.logger.warning("Player %s does not support (un)group commands", player.name)
-            return
-
-        # forward command to the player once all checks passed
-        await player.ungroup()
-
-    @api_command("players/cmd/ungroup_many")
-    async def cmd_ungroup_many(self, player_ids: list[str]) -> None:
-        """Handle UNGROUP command for all the given players."""
-        for player_id in list(player_ids):
-            await self.cmd_ungroup(player_id)
-
-    @api_command("players/create_group_player")
-    async def create_group_player(
-        self, provider: str, name: str, members: list[str], dynamic: bool = True
-    ):
-        """
-        Create a new (permanent) Group Player.
-
-        :param provider: The provider to create the group player for
-        :param name: Name of the new group player
-        :param members: List of player ids to add to the group
-        :param dynamic: Whether the group is dynamic (members can change)
-        """
-        if not (provider_instance := self.mass.get_provider(provider)):
-            raise ProviderUnavailableError(f"Provider {provider} not found")
-        provider_instance.check_feature(ProviderFeature.CREATE_GROUP_PLAYER)
-        provider_instance = cast("PlayerProvider", provider_instance)
-        # create the group player
-        return await provider_instance.create_group_player(name, members, dynamic)
-
-    @api_command("players/remove_group_player")
-    async def remove_group_player(self, player_id: str) -> None:
-        """
-        Remove a group player.
-
-        :param player_id: ID of the group player to remove.
-        """
-        if not (player := self.get(player_id)):
-            # we simply permanently delete the player by wiping its config
-            self.mass.config.remove(f"players/{player_id}")
-            return
-        if player.type != PlayerType.GROUP:
-            raise UnsupportedFeaturedException(
-                f"Player {player.display_name} is not a group player"
-            )
-        player.provider.check_feature(ProviderFeature.REMOVE_GROUP_PLAYER)
-        await player.provider.remove_group_player(player_id)
-
-    @api_command("players/add_currently_playing_to_favorites")
-    async def add_currently_playing_to_favorites(self, player_id: str) -> None:
-        """
-        Add the currently playing item/track on given player to the favorites.
-
-        This tries to resolve the currently playing media to an actual media item
-        and add that to the favorites in the library.
-
-        Will raise an error if the player is not currently playing anything
-        or if the currently playing media can not be resolved to a media item.
-        """
-        player = self._get_player_with_redirect(player_id)
-        # handle mass player queue active
-        if mass_queue := self.get_active_queue(player):
-            if not (current_item := mass_queue.current_item) or not current_item.media_item:
-                raise PlayerCommandFailed("No current item to add to favorites")
-            # if we're playing a radio station, try to resolve the currently playing track
-            if current_item.media_item.media_type == MediaType.RADIO:
-                if not (
-                    (streamdetails := mass_queue.current_item.streamdetails)
-                    and (stream_title := streamdetails.stream_title)
-                    and " - " in stream_title
-                ):
-                    # no stream title available, so we can't resolve the track
-                    # this can happen if the radio station does not provide metadata
-                    # or there's a commercial break
-                    # Possible future improvement could be to actually detect the song with a
-                    # shazam-like approach.
-                    raise PlayerCommandFailed("No current item to add to favorites")
-                # send the streamtitle into a global search query
-                search_artist, search_title_title = stream_title.split(" - ", 1)
-                # strip off any additional comments in the title (such as from Radio Paradise)
-                search_title_title = search_title_title.split(" | ")[0].strip()
-                if track := await self.mass.music.get_track_by_name(
-                    search_title_title, search_artist
-                ):
-                    # we found a track, so add it to the favorites
-                    await self.mass.music.add_item_to_favorites(track)
-                    return
-                # we could not resolve the track, so raise an error
-                raise PlayerCommandFailed("No current item to add to favorites")
-
-            # else: any other media item, just add it to the favorites directly
-            await self.mass.music.add_item_to_favorites(current_item.media_item)
-            return
-
-        # guard for player with no active source
-        if not player.active_source:
-            raise PlayerCommandFailed("Player has no active source")
-        # handle other source active using the current_media with uri
-        if current_media := player.current_media:
-            # prefer the uri of the current media item
-            if current_media.uri:
-                with suppress(MusicAssistantError):
-                    await self.mass.music.add_item_to_favorites(current_media.uri)
-                    return
-            # fallback to search based on artist and title (and album if available)
-            if current_media.artist and current_media.title:
-                if track := await self.mass.music.get_track_by_name(
-                    current_media.title,
-                    current_media.artist,
-                    current_media.album,
-                ):
-                    # we found a track, so add it to the favorites
-                    await self.mass.music.add_item_to_favorites(track)
-                    return
-        # if we reach here, we could not resolve the currently playing item
-        raise PlayerCommandFailed("No current item to add to favorites")
-
-    async def register(self, player: Player) -> None:
-        """Register a player on the Player Controller."""
-        if self.mass.closing:
-            return
-        player_id = player.player_id
-
-        if player_id in self._players:
-            msg = f"Player {player_id} is already registered!"
-            raise AlreadyRegisteredError(msg)
-
-        # ignore disabled players
-        if not player.enabled:
-            return
-
-        # register throttler for this player
-        self._player_throttlers[player_id] = Throttler(1, 0.05)
-
-        # restore 'fake' power state from cache if available
-        cached_value = await self.mass.cache.get(
-            key=player.player_id,
-            provider=self.domain,
-            category=CACHE_CATEGORY_PLAYER_POWER,
-            default=False,
-        )
-        if cached_value is not None:
-            player.extra_data[ATTR_FAKE_POWER] = cached_value
-
-        # finally actually register it
-        self._players[player_id] = player
-
-        # ensure we fetch and set the latest/full config for the player
-        player_config = await self.mass.config.get_player_config(player_id)
-        player.set_config(player_config)
-        # call hook after the player is registered and config is set
-        await player.on_config_updated()
-        # always call update to fix special attributes like display name, group volume etc.
-        player.update_state()
-
-        self.logger.info(
-            "Player registered: %s/%s",
-            player_id,
-            player.display_name,
-        )
-        # signal event that a player was added
-        self.mass.signal_event(EventType.PLAYER_ADDED, object_id=player.player_id, data=player)
-
-        # register playerqueue for this player
-        await self.mass.player_queues.on_player_register(player)
-
-    async def register_or_update(self, player: Player) -> None:
-        """Register a new player on the controller or update existing one."""
-        if self.mass.closing:
-            return
-
-        if player.player_id in self._players:
-            self._players[player.player_id] = player
-            player.update_state()
-            return
-
-        await self.register(player)
-
-    def trigger_player_update(self, player_id: str, force_update: bool = False) -> None:
-        """Trigger an update for the given player."""
-        if self.mass.closing:
-            return
-        player = self.get(player_id, True)
-        assert player is not None  # for type checker
-        self.mass.loop.call_soon(player.update_state, force_update)
-
-    async def unregister(self, player_id: str, permanent: bool = False) -> None:
-        """
-        Unregister a player from the player controller.
-
-        Called (by a PlayerProvider) when a player is removed
-        or no longer available (for a longer period of time).
-
-        This will remove the player from the player controller and
-        optionally remove the player's config from the mass config.
-
-        - player_id: player_id of the player to unregister.
-        - permanent: if True, remove the player permanently by deleting
-        the player's config from the mass config. If False, the player config will not be removed,
-        allowing for re-registration (with the same config) later.
-
-        If the player is not registered, this will silently be ignored.
-        """
-        player = self._players.get(player_id)
-        if player is None:
-            return
-        await self._cleanup_player_memberships(player_id)
-        del self._players[player_id]
-        self.logger.info("Player removed: %s", player.name)
-        self.mass.player_queues.on_player_remove(player_id, permanent=permanent)
-        await player.on_unload()
-        if permanent:
-            self.delete_player_config(player_id)
-        self.mass.signal_event(EventType.PLAYER_REMOVED, player_id)
-
-    @api_command("players/remove")
-    async def remove(self, player_id: str) -> None:
-        """
-        Remove a player from a provider.
-
-        Can only be called when a PlayerProvider supports ProviderFeature.REMOVE_PLAYER.
-        """
-        player = self.get(player_id)
-        if player is None:
-            # we simply permanently delete the player config since it is not registered
-            self.delete_player_config(player_id)
-            return
-        if player.type == PlayerType.GROUP:
-            # Handle group player removal
-            await player.provider.remove_group_player(player_id)
-            return
-        player.provider.check_feature(ProviderFeature.REMOVE_PLAYER)
-        await player.provider.remove_player(player_id)
-        # check for group memberships that need to be updated
-        if player.active_group and (group_player := self.mass.players.get(player.active_group)):
-            # try to remove from the group
-            with suppress(UnsupportedFeaturedException, PlayerCommandFailed):
-                await group_player.set_members(
-                    player_ids_to_remove=[player_id],
-                )
-        # We removed the player and can now clean up its config
-        self.delete_player_config(player_id)
-
-    def delete_player_config(self, player_id: str) -> None:
-        """
-        Permanently delete a player's configuration.
-
-        Should only be called for players that are not registered by the player controller.
-        """
-        # we simply permanently delete the player by wiping its config
-        conf_key = f"{CONF_PLAYERS}/{player_id}"
-        dsp_conf_key = f"{CONF_PLAYER_DSP}/{player_id}"
-        for key in (conf_key, dsp_conf_key):
-            self.mass.config.remove(key)
-
-    def signal_player_state_update(
-        self,
-        player: Player,
-        changed_values: dict[str, tuple[Any, Any]],
-        force_update: bool = False,
-        skip_forward: bool = False,
-    ) -> None:
-        """
-        Signal a player state update.
-
-        Called by a Player when its state has changed.
-        This will update the player state in the controller and signal the event bus.
-        """
-        player_id = player.player_id
-        if self.mass.closing:
-            return
-
-        # ignore updates for disabled players
-        if not player.enabled and "enabled" not in changed_values:
-            return
-
-        if len(changed_values) == 0 and not force_update:
-            # nothing changed
-            return
-
-        # always signal update to the playerqueue
-        self.mass.player_queues.on_player_update(player, changed_values)
-
-        if changed_values.keys() == {"elapsed_time"} and not force_update:
-            # ignore elapsed_time only changes
-            prev_value = changed_values["elapsed_time"][0] or 0
-            new_value = changed_values["elapsed_time"][1] or 0
-            if abs(prev_value - new_value) < 30:
-                # ignore small changes in elapsed time
-                return
-
-        # handle DSP reload of the leader when grouping/ungrouping
-        if ATTR_GROUP_MEMBERS in changed_values:
-            prev_group_members, new_group_members = changed_values[ATTR_GROUP_MEMBERS]
-            self._handle_group_dsp_change(player, prev_group_members or [], new_group_members)
-
-        if ATTR_GROUP_MEMBERS in changed_values:
-            # Removed group members also need to be updated since they are no longer part
-            # of this group and are available for playback again
-            prev_group_members = changed_values[ATTR_GROUP_MEMBERS][0] or []
-            new_group_members = changed_values[ATTR_GROUP_MEMBERS][1] or []
-            removed_members = set(prev_group_members) - set(new_group_members)
-            for player_id in removed_members:
-                if removed_player := self.get(player_id):
-                    removed_player.update_state()
-
-        became_inactive = False
-        if "available" in changed_values:
-            became_inactive = changed_values["available"][1] is False
-        if not became_inactive and "enabled" in changed_values:
-            became_inactive = changed_values["enabled"][1] is False
-        if became_inactive and (player.active_group or player.synced_to):
-            self.mass.create_task(self._cleanup_player_memberships(player.player_id))
-
-        # signal player update on the eventbus
-        self.mass.signal_event(EventType.PLAYER_UPDATED, object_id=player_id, data=player)
-
-        if skip_forward and not force_update:
-            return
-
-        # update/signal group player(s) child's when group updates
-        for child_player in self.iter_group_members(player, exclude_self=True):
-            child_player.update_state()
-        # update/signal group player(s) when child updates
-        for group_player in self._get_player_groups(player, powered_only=False):
-            group_player.update_state()
-        # update/signal manually synced to player when child updates
-        if (synced_to := player.synced_to) and (synced_to_player := self.get(synced_to)):
-            synced_to_player.update_state()
-        # update/signal active groups when a group member updates
-        if (active_group := player.active_group) and (
-            active_group_player := self.get(active_group)
-        ):
-            active_group_player.update_state()
-
-    async def register_player_control(self, player_control: PlayerControl) -> None:
-        """Register a new PlayerControl on the controller."""
-        if self.mass.closing:
-            return
-        control_id = player_control.id
-
-        if control_id in self._controls:
-            msg = f"PlayerControl {control_id} is already registered"
-            raise AlreadyRegisteredError(msg)
-
-        # make sure that the playercontrol's provider is set to the instance_id
-        prov = self.mass.get_provider(player_control.provider)
-        if not prov or prov.instance_id != player_control.provider:
-            raise RuntimeError(f"Invalid provider ID given: {player_control.provider}")
-
-        self._controls[control_id] = player_control
-
-        self.logger.info(
-            "PlayerControl registered: %s/%s",
-            control_id,
-            player_control.name,
-        )
-
-        # always call update to update any attached players etc.
-        self.update_player_control(player_control.id)
-
-    async def register_or_update_player_control(self, player_control: PlayerControl) -> None:
-        """Register a new playercontrol on the controller or update existing one."""
-        if self.mass.closing:
-            return
-        if player_control.id in self._controls:
-            self._controls[player_control.id] = player_control
-            self.update_player_control(player_control.id)
-            return
-        await self.register_player_control(player_control)
-
-    def update_player_control(self, control_id: str) -> None:
-        """Update playercontrol state."""
-        if self.mass.closing:
-            return
-        # update all players that are using this control
-        for player in self._players.values():
-            if control_id in (player.power_control, player.volume_control, player.mute_control):
-                self.mass.loop.call_soon(player.update_state)
-
-    def remove_player_control(self, control_id: str) -> None:
-        """Remove a player_control from the player manager."""
-        control = self._controls.pop(control_id, None)
-        if control is None:
-            return
-        self._controls.pop(control_id, None)
-        self.logger.info("PlayerControl removed: %s", control.name)
-
-    def get_player_provider(self, player_id: str) -> PlayerProvider:
-        """Return PlayerProvider for given player."""
-        player = self._players[player_id]
-        assert player  # for type checker
-        return player.provider
-
-    def get_active_queue(self, player: Player) -> PlayerQueue | None:
-        """Return the current active queue for a player (if any)."""
-        # account for player that is synced (sync child)
-        if player.synced_to and player.synced_to != player.player_id:
-            if sync_leader := self.get(player.synced_to):
-                return self.get_active_queue(sync_leader)
-        # handle active group player
-        if player.active_group and player.active_group != player.player_id:
-            if group_player := self.get(player.active_group):
-                return self.get_active_queue(group_player)
-        # active_source may be filled queue id (or None)
-        active_source = player.active_source or player.player_id
-        if active_queue := self.mass.player_queues.get(active_source):
-            return active_queue
-        return None
-
-    async def set_group_volume(self, group_player: Player, volume_level: int) -> None:
-        """Handle adjusting the overall/group volume to a playergroup (or synced players)."""
-        cur_volume = group_player.state.group_volume
-        volume_dif = volume_level - cur_volume
-        coros = []
-        # handle group volume by only applying the volume to powered members
-        for child_player in self.iter_group_members(
-            group_player, only_powered=True, exclude_self=False
-        ):
-            if child_player.volume_control == PLAYER_CONTROL_NONE:
-                continue
-            cur_child_volume = child_player.volume_level or 0
-            new_child_volume = int(cur_child_volume + volume_dif)
-            new_child_volume = max(0, new_child_volume)
-            new_child_volume = min(100, new_child_volume)
-            coros.append(self.cmd_volume_set(child_player.player_id, new_child_volume))
-        await asyncio.gather(*coros)
-
-    def get_announcement_volume(self, player_id: str, volume_override: int | None) -> int | None:
-        """Get the (player specific) volume for a announcement."""
-        volume_strategy = self.mass.config.get_raw_player_config_value(
-            player_id,
-            CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY.key,
-            CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY.default_value,
-        )
-        volume_strategy_volume = self.mass.config.get_raw_player_config_value(
-            player_id,
-            CONF_ENTRY_ANNOUNCE_VOLUME.key,
-            CONF_ENTRY_ANNOUNCE_VOLUME.default_value,
-        )
-        if volume_strategy == "none":
-            return None
-        volume_level = volume_override
-        if volume_level is None and volume_strategy == "absolute":
-            volume_level = volume_strategy_volume
-        elif volume_level is None and volume_strategy == "relative":
-            player = self.get(player_id)
-            volume_level = player.volume_level + volume_strategy_volume
-        elif volume_level is None and volume_strategy == "percentual":
-            player = self.get(player_id)
-            percentual = (player.volume_level / 100) * volume_strategy_volume
-            volume_level = player.volume_level + percentual
-        if volume_level is not None:
-            announce_volume_min = self.mass.config.get_raw_player_config_value(
-                player_id,
-                CONF_ENTRY_ANNOUNCE_VOLUME_MIN.key,
-                CONF_ENTRY_ANNOUNCE_VOLUME_MIN.default_value,
-            )
-            volume_level = max(announce_volume_min, volume_level)
-            announce_volume_max = self.mass.config.get_raw_player_config_value(
-                player_id,
-                CONF_ENTRY_ANNOUNCE_VOLUME_MAX.key,
-                CONF_ENTRY_ANNOUNCE_VOLUME_MAX.default_value,
-            )
-            volume_level = min(announce_volume_max, volume_level)
-        # ensure the result is an integer
-        return None if volume_level is None else int(volume_level)
-
-    def iter_group_members(
-        self,
-        group_player: Player,
-        only_powered: bool = False,
-        only_playing: bool = False,
-        active_only: bool = False,
-        exclude_self: bool = True,
-    ) -> Iterator[Player]:
-        """Get (child) players attached to a group player or syncgroup."""
-        for child_id in list(group_player.group_members):
-            if child_player := self.get(child_id, False):
-                if not child_player.available or not child_player.enabled:
-                    continue
-                if only_powered and child_player.powered is False:
-                    continue
-                if active_only and child_player.active_group != group_player.player_id:
-                    continue
-                if exclude_self and child_player.player_id == group_player.player_id:
-                    continue
-                if only_playing and child_player.playback_state not in (
-                    PlaybackState.PLAYING,
-                    PlaybackState.PAUSED,
-                ):
-                    continue
-                yield child_player
-
-    async def wait_for_state(
-        self,
-        player: Player,
-        wanted_state: PlaybackState,
-        timeout: float = 60.0,
-        minimal_time: float = 0,
-    ) -> None:
-        """Wait for the given player to reach the given state."""
-        start_timestamp = time.time()
-        self.logger.debug(
-            "Waiting for player %s to reach state %s", player.display_name, wanted_state
-        )
-        try:
-            async with asyncio.timeout(timeout):
-                while player.playback_state != wanted_state:
-                    await asyncio.sleep(0.1)
-
-        except TimeoutError:
-            self.logger.debug(
-                "Player %s did not reach state %s within the timeout of %s seconds",
-                player.display_name,
-                wanted_state,
-                timeout,
-            )
-        elapsed_time = round(time.time() - start_timestamp, 2)
-        if elapsed_time < minimal_time:
-            self.logger.debug(
-                "Player %s reached state %s too soon (%s vs %s seconds) - add fallback sleep...",
-                player.display_name,
-                wanted_state,
-                elapsed_time,
-                minimal_time,
-            )
-            await asyncio.sleep(minimal_time - elapsed_time)
-        else:
-            self.logger.debug(
-                "Player %s reached state %s within %s seconds",
-                player.display_name,
-                wanted_state,
-                elapsed_time,
-            )
-
-    async def on_player_config_change(self, config: PlayerConfig, changed_keys: set[str]) -> None:
-        """Call (by config manager) when the configuration of a player changes."""
-        player_disabled = "enabled" in changed_keys and not config.enabled
-        # signal player provider that the player got enabled/disabled
-        if player_provider := self.mass.get_provider(config.provider):
-            assert isinstance(player_provider, PlayerProvider)  # for type checking
-            if "enabled" in changed_keys and not config.enabled:
-                player_provider.on_player_disabled(config.player_id)
-            elif "enabled" in changed_keys and config.enabled:
-                player_provider.on_player_enabled(config.player_id)
-        # ensure player state gets updated with any updated config
-        if not (player := self.get(config.player_id)):
-            return  # guard against player not being registered (yet)
-        player.set_config(config)
-        await player.on_config_updated()
-        player.update_state()
-        resume_queue: PlayerQueue | None = (
-            self.mass.player_queues.get(player.active_source) if player.active_source else None
-        )
-        if player_disabled:
-            # edge case: ensure that the player is powered off if the player gets disabled
-            if player.power_control != PLAYER_CONTROL_NONE:
-                await self.cmd_power(config.player_id, False)
-            elif player.playback_state != PlaybackState.IDLE:
-                await self.cmd_stop(config.player_id)
-            player.available = False
-        # if the PlayerQueue was playing, restart playback
-        # TODO: add property to ConfigEntry if it requires a restart of playback on change
-        elif not player_disabled and resume_queue and resume_queue.state == PlaybackState.PLAYING:
-            # always stop first to ensure the player uses the new config
-            await self.mass.player_queues.stop(resume_queue.queue_id)
-            self.mass.call_later(1, self.mass.player_queues.resume, resume_queue.queue_id, False)
-
-    async def on_player_dsp_change(self, player_id: str) -> None:
-        """Call (by config manager) when the DSP settings of a player change."""
-        # signal player provider that the config changed
-        if not (player := self.get(player_id)):
-            return
-        if player.playback_state == PlaybackState.PLAYING:
-            self.logger.info("Restarting playback of Player %s after DSP change", player_id)
-            # this will restart the queue stream/playback
-            if player.mass_queue_active:
-                self.mass.call_later(0, self.mass.player_queues.resume, player.active_source, False)
-                return
-            # if the player is not using a queue, we need to stop and start playback
-            await self.cmd_stop(player_id)
-            await self.cmd_play(player_id)
-
-    async def _cleanup_player_memberships(self, player_id: str) -> None:
-        """Ensure a player is detached from any groups or syncgroups."""
-        if not (player := self.get(player_id)):
-            return
-
-        if (
-            player.active_group
-            and (group := self.get(player.active_group))
-            and group.supports_feature(PlayerFeature.SET_MEMBERS)
-        ):
-            # Ungroup the player if its part of an active group, this will ignore
-            # static_group_members since that is only checked when using cmd_set_members
-            with suppress(UnsupportedFeaturedException, PlayerCommandFailed):
-                await group.set_members(player_ids_to_remove=[player_id])
-        elif player.synced_to and player.supports_feature(PlayerFeature.SET_MEMBERS):
-            # Remove the player if it was synced, otherwise it will still show as
-            # synced to the other player after it gets registered again
-            with suppress(UnsupportedFeaturedException, PlayerCommandFailed):
-                await player.ungroup()
-
-    def _get_player_with_redirect(self, player_id: str) -> Player:
-        """Get player with check if playback related command should be redirected."""
-        player = self.get(player_id, True)
-        assert player is not None  # for type checking
-        if player.synced_to and (sync_leader := self.get(player.synced_to)):
-            self.logger.info(
-                "Player %s is synced to %s and can not accept "
-                "playback related commands itself, "
-                "redirected the command to the sync leader.",
-                player.name,
-                sync_leader.name,
-            )
-            return sync_leader
-        if player.active_group and (active_group := self.get(player.active_group)):
-            self.logger.info(
-                "Player %s is part of a playergroup and can not accept "
-                "playback related commands itself, "
-                "redirected the command to the group leader.",
-                player.name,
-            )
-            return active_group
-        return player
-
-    def _get_player_groups(
-        self, player: Player, available_only: bool = True, powered_only: bool = False
-    ) -> Iterator[Player]:
-        """Return all groupplayers the given player belongs to."""
-        for _player in self.all(return_unavailable=not available_only):
-            if _player.player_id == player.player_id:
-                continue
-            if _player.type != PlayerType.GROUP:
-                continue
-            if powered_only and _player.powered is False:
-                continue
-            if player.player_id in _player.group_members:
-                yield _player
-
-    async def _play_announcement(  # noqa: PLR0915
-        self,
-        player: Player,
-        announcement: PlayerMedia,
-        volume_level: int | None = None,
-    ) -> None:
-        """Handle (default/fallback) implementation of the play announcement feature.
-
-        This default implementation will;
-        - stop playback of the current media (if needed)
-        - power on the player (if needed)
-        - raise the volume a bit
-        - play the announcement (from given url)
-        - wait for the player to finish playing
-        - restore the previous power and volume
-        - restore playback (if needed and if possible)
-
-        This default implementation will only be used if the player
-        (provider) has no native support for the PLAY_ANNOUNCEMENT feature.
-        """
-        prev_power = player.powered
-        prev_state = player.playback_state
-        prev_synced_to = player.synced_to
-        prev_group = self.get(player.active_group) if player.active_group else None
-        prev_source = player.active_source
-        prev_queue = self.get_active_queue(player)
-        prev_media = player.current_media
-        prev_media_name = prev_media.title or prev_media.uri if prev_media else None
-        if prev_synced_to:
-            # ungroup player if its currently synced
-            self.logger.debug(
-                "Announcement to player %s - ungrouping player from %s...",
-                player.display_name,
-                prev_synced_to,
-            )
-            await self.cmd_ungroup(player.player_id)
-        elif prev_group:
-            # if the player is part of a group player, we need to ungroup it
-            if PlayerFeature.SET_MEMBERS in prev_group.supported_features:
-                self.logger.debug(
-                    "Announcement to player %s - ungrouping from group player %s...",
-                    player.display_name,
-                    prev_group.display_name,
-                )
-                await prev_group.set_members(player_ids_to_remove=[player.player_id])
-            else:
-                # if the player is part of a group player that does not support ungrouping,
-                # we need to power off the groupplayer instead
-                self.logger.debug(
-                    "Announcement to player %s - turning off group player %s...",
-                    player.display_name,
-                    prev_group.display_name,
-                )
-                await self.cmd_power(player.player_id, False)
-        elif prev_state in (PlaybackState.PLAYING, PlaybackState.PAUSED):
-            # normal/standalone player: stop player if its currently playing
-            self.logger.debug(
-                "Announcement to player %s - stop existing content (%s)...",
-                player.display_name,
-                prev_media_name,
-            )
-            await self.cmd_stop(player.player_id)
-            # wait for the player to stop
-            await self.wait_for_state(player, PlaybackState.IDLE, 10, 0.4)
-        # adjust volume if needed
-        # in case of a (sync) group, we need to do this for all child players
-        prev_volumes: dict[str, int] = {}
-        async with TaskManager(self.mass) as tg:
-            for volume_player_id in player.group_members or (player.player_id,):
-                if not (volume_player := self.get(volume_player_id)):
-                    continue
-                # catch any players that have a different source active
-                if (
-                    volume_player.active_source
-                    not in (
-                        player.active_source,
-                        volume_player.player_id,
-                        None,
-                    )
-                    and volume_player.playback_state == PlaybackState.PLAYING
-                ):
-                    self.logger.warning(
-                        "Detected announcement to playergroup %s while group member %s is playing "
-                        "other content, this may lead to unexpected behavior.",
-                        player.display_name,
-                        volume_player.display_name,
-                    )
-                    tg.create_task(self.cmd_stop(volume_player.player_id))
-                if volume_player.volume_control == PLAYER_CONTROL_NONE:
-                    continue
-                if (prev_volume := volume_player.volume_level) is None:
-                    continue
-                announcement_volume = self.get_announcement_volume(volume_player_id, volume_level)
-                if announcement_volume is None:
-                    continue
-                temp_volume = announcement_volume or player.volume_level
-                if temp_volume != prev_volume:
-                    prev_volumes[volume_player_id] = prev_volume
-                    self.logger.debug(
-                        "Announcement to player %s - setting temporary volume (%s)...",
-                        volume_player.display_name,
-                        announcement_volume,
-                    )
-                    tg.create_task(
-                        self.cmd_volume_set(volume_player.player_id, announcement_volume)
-                    )
-        # play the announcement
-        self.logger.debug(
-            "Announcement to player %s - playing the announcement on the player...",
-            player.display_name,
-        )
-        await self.play_media(player_id=player.player_id, media=announcement)
-        # wait for the player(s) to play
-        await self.wait_for_state(player, PlaybackState.PLAYING, 10, minimal_time=0.1)
-        # wait for the player to stop playing
-        if not announcement.duration:
-            media_info = await async_parse_tags(
-                announcement.custom_data["url"], require_duration=True
-            )
-            announcement.duration = media_info.duration
-        await self.wait_for_state(
-            player,
-            PlaybackState.IDLE,
-            timeout=announcement.duration + 6,
-            minimal_time=announcement.duration,
-        )
-        self.logger.debug(
-            "Announcement to player %s - restore previous state...", player.display_name
-        )
-        # restore volume
-        async with TaskManager(self.mass) as tg:
-            for volume_player_id, prev_volume in prev_volumes.items():
-                tg.create_task(self.cmd_volume_set(volume_player_id, prev_volume))
-        await asyncio.sleep(0.2)
-        player.current_media = prev_media
-        player.active_source = prev_source
-        # either power off the player or resume playing
-        if not prev_power and player.power_control != PLAYER_CONTROL_NONE:
-            await self.cmd_power(player.player_id, False)
-            return
-        elif prev_synced_to:
-            await self.cmd_group(player.player_id, prev_synced_to)
-        elif prev_group:
-            if PlayerFeature.SET_MEMBERS in prev_group.supported_features:
-                self.logger.debug(
-                    "Announcement to player %s - grouping back to group player %s...",
-                    player.display_name,
-                    prev_group.display_name,
-                )
-                await prev_group.set_members(player_ids_to_add=[player.player_id])
-            elif prev_state == PlaybackState.PLAYING:
-                # if the player is part of a group player that does not support set_members,
-                # we need to restart the groupplayer
-                self.logger.debug(
-                    "Announcement to player %s - restarting playback on group player %s...",
-                    player.display_name,
-                    prev_group.display_name,
-                )
-                await self.cmd_play(prev_group.player_id)
-        elif prev_queue and prev_state == PlaybackState.PLAYING:
-            await self.mass.player_queues.resume(prev_queue.queue_id, True)
-            await self.wait_for_state(player, PlaybackState.PLAYING, 5)
-        elif prev_state == PlaybackState.PLAYING:
-            # player was playing something else - try to resume that here
-            for source in player.source_list_state:
-                if source.id == prev_source and not source.passive:
-                    await player.select_source(source.id)
-                    break
-            else:
-                # no source found, try to resume the previous media
-                await self.cmd_play(player.player_id)
-
-    async def _poll_players(self) -> None:
-        """Background task that polls players for updates."""
-        while True:
-            for player in list(self._players.values()):
-                # if the player is playing, update elapsed time every tick
-                # to ensure the queue has accurate details
-                player_playing = player.playback_state == PlaybackState.PLAYING
-                if player_playing:
-                    self.mass.loop.call_soon(
-                        self.mass.player_queues.on_player_update,
-                        player,
-                        {"corrected_elapsed_time": player.corrected_elapsed_time},
-                    )
-                # Poll player;
-                if not player.needs_poll:
-                    continue
-                try:
-                    last_poll: float = player.extra_data[ATTR_LAST_POLL]
-                except KeyError:
-                    last_poll = 0.0
-                if (self.mass.loop.time() - last_poll) < player.poll_interval:
-                    continue
-                player.extra_data[ATTR_LAST_POLL] = self.mass.loop.time()
-                try:
-                    await player.poll()
-                except Exception as err:
-                    self.logger.warning(
-                        "Error while requesting latest state from player %s: %s",
-                        player.display_name,
-                        str(err),
-                        exc_info=err if self.logger.isEnabledFor(10) else None,
-                    )
-                finally:
-                    # always update player state
-                    self.mass.loop.call_soon(player.update_state)
-            await asyncio.sleep(1)
-
-    async def _handle_select_plugin_source(
-        self, player: Player, plugin_prov: PluginProvider
-    ) -> None:
-        """Handle playback/select of given plugin source on player."""
-        plugin_source = plugin_prov.get_source()
-        stream_url = await self.mass.streams.get_plugin_source_url(
-            plugin_source.id, player.player_id
-        )
-        await self.play_media(
-            player_id=player.player_id,
-            media=PlayerMedia(
-                uri=stream_url,
-                media_type=MediaType.PLUGIN_SOURCE,
-                title=plugin_source.name,
-                custom_data={
-                    "provider": plugin_prov.instance_id,
-                    "source_id": plugin_source.id,
-                    "player_id": player.player_id,
-                    "audio_format": plugin_source.audio_format,
-                },
-            ),
-        )
-        # trigger player update to ensure the source is set
-        self.trigger_player_update(player.player_id)
-
-    def _handle_group_dsp_change(
-        self, player: Player, prev_group_members: list[str], new_group_members: list[str]
-    ) -> None:
-        """Handle DSP reload when group membership changes."""
-        prev_child_count = len(prev_group_members)
-        new_child_count = len(new_group_members)
-        is_player_group = player.type == PlayerType.GROUP
-
-        # handle special case for PlayerGroups: since there are no leaders,
-        # DSP still always work with a single player in the group.
-        multi_device_dsp_threshold = 1 if is_player_group else 0
-
-        prev_is_multiple_devices = prev_child_count > multi_device_dsp_threshold
-        new_is_multiple_devices = new_child_count > multi_device_dsp_threshold
-
-        if prev_is_multiple_devices == new_is_multiple_devices:
-            return  # no change in multi-device status
-
-        supports_multi_device_dsp = PlayerFeature.MULTI_DEVICE_DSP in player.supported_features
-
-        dsp_enabled: bool
-        if player.type == PlayerType.GROUP:
-            # Since player groups do not have leaders, we will use the only child
-            # that was in the group before and after the change
-            if prev_is_multiple_devices:
-                if childs := new_group_members:
-                    # We shrank the group from multiple players to a single player
-                    # So the now only child will control the DSP
-                    dsp_enabled = self.mass.config.get_player_dsp_config(childs[0]).enabled
-                else:
-                    dsp_enabled = False
-            elif childs := prev_group_members:
-                # We grew the group from a single player to multiple players,
-                # let's see if the previous single player had DSP enabled
-                dsp_enabled = self.mass.config.get_player_dsp_config(childs[0]).enabled
-            else:
-                dsp_enabled = False
-        else:
-            dsp_enabled = self.mass.config.get_player_dsp_config(player.player_id).enabled
-
-        if dsp_enabled and not supports_multi_device_dsp:
-            # We now know that the group configuration has changed so:
-            # - multi-device DSP is not supported
-            # - we switched from a group with multiple players to a single player
-            #   (or vice versa)
-            # - the leader has DSP enabled
-            self.mass.create_task(self.mass.players.on_player_dsp_change(player.player_id))
-
-    def __iter__(self) -> Iterator[Player]:
-        """Iterate over all players."""
-        return iter(self._players.values())
diff --git a/music_assistant/controllers/players/__init__.py b/music_assistant/controllers/players/__init__.py
new file mode 100644 (file)
index 0000000..455198a
--- /dev/null
@@ -0,0 +1,21 @@
+"""
+MusicAssistant PlayerController.
+
+Handles all logic to control supported players,
+which are provided by Player Providers.
+
+Note that the PlayerController has a concept of a 'player' and a 'playerstate'.
+The Player is the actual object that is provided by the provider,
+which incorporates the actual state of the player (e.g. volume, state, etc)
+and functions for controlling the player (e.g. play, pause, etc).
+
+The playerstate is the (final) state of the player, including any user customizations
+and transformations that are applied to the player.
+The playerstate is the object that is exposed to the outside world (via the API).
+"""
+
+from __future__ import annotations
+
+from .player_controller import PlayerController
+
+__all__ = ["PlayerController"]
diff --git a/music_assistant/controllers/players/player_controller.py b/music_assistant/controllers/players/player_controller.py
new file mode 100644 (file)
index 0000000..0c260c2
--- /dev/null
@@ -0,0 +1,2081 @@
+"""
+MusicAssistant PlayerController.
+
+Handles all logic to control supported players,
+which are provided by Player Providers.
+
+Note that the PlayerController has a concept of a 'player' and a 'playerstate'.
+The Player is the actual object that is provided by the provider,
+which incorporates the actual state of the player (e.g. volume, state, etc)
+and functions for controlling the player (e.g. play, pause, etc).
+
+The playerstate is the (final) state of the player, including any user customizations
+and transformations that are applied to the player.
+The playerstate is the object that is exposed to the outside world (via the API).
+"""
+
+from __future__ import annotations
+
+import asyncio
+import functools
+import time
+from contextlib import suppress
+from typing import TYPE_CHECKING, Any, Concatenate, TypedDict, cast
+
+from music_assistant_models.constants import (
+    PLAYER_CONTROL_FAKE,
+    PLAYER_CONTROL_NATIVE,
+    PLAYER_CONTROL_NONE,
+)
+from music_assistant_models.enums import (
+    EventType,
+    MediaType,
+    PlaybackState,
+    PlayerFeature,
+    PlayerType,
+    ProviderFeature,
+    ProviderType,
+)
+from music_assistant_models.errors import (
+    AlreadyRegisteredError,
+    MusicAssistantError,
+    PlayerCommandFailed,
+    PlayerUnavailableError,
+    ProviderUnavailableError,
+    UnsupportedFeaturedException,
+)
+from music_assistant_models.player_control import PlayerControl  # noqa: TC002
+
+from music_assistant.constants import (
+    ANNOUNCE_ALERT_FILE,
+    ATTR_ANNOUNCEMENT_IN_PROGRESS,
+    ATTR_FAKE_MUTE,
+    ATTR_FAKE_POWER,
+    ATTR_FAKE_VOLUME,
+    ATTR_GROUP_MEMBERS,
+    ATTR_LAST_POLL,
+    ATTR_PREVIOUS_VOLUME,
+    CONF_AUTO_PLAY,
+    CONF_ENTRY_ANNOUNCE_VOLUME,
+    CONF_ENTRY_ANNOUNCE_VOLUME_MAX,
+    CONF_ENTRY_ANNOUNCE_VOLUME_MIN,
+    CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY,
+    CONF_ENTRY_TTS_PRE_ANNOUNCE,
+    CONF_PLAYER_DSP,
+    CONF_PLAYERS,
+    CONF_PRE_ANNOUNCE_CHIME_URL,
+)
+from music_assistant.helpers.api import api_command
+from music_assistant.helpers.tags import async_parse_tags
+from music_assistant.helpers.throttle_retry import Throttler
+from music_assistant.helpers.util import TaskManager, validate_announcement_chime_url
+from music_assistant.models.core_controller import CoreController
+from music_assistant.models.player import Player, PlayerMedia, PlayerState
+from music_assistant.models.player_provider import PlayerProvider
+from music_assistant.models.plugin import PluginProvider, PluginSource
+
+from .sync_groups import SyncGroupController, SyncGroupPlayer
+
+if TYPE_CHECKING:
+    from collections.abc import Awaitable, Callable, Coroutine, Iterator
+
+    from music_assistant_models.config_entries import CoreConfig, PlayerConfig
+    from music_assistant_models.player_queue import PlayerQueue
+
+CACHE_CATEGORY_PLAYER_POWER = 1
+
+
+class AnnounceData(TypedDict):
+    """Announcement data."""
+
+    announcement_url: str
+    pre_announce: bool
+    pre_announce_url: str
+
+
+def handle_player_command[PlayerControllerT: "PlayerController", **P, R](
+    func: Callable[Concatenate[PlayerControllerT, P], Awaitable[R]],
+) -> Callable[Concatenate[PlayerControllerT, P], Coroutine[Any, Any, R | None]]:
+    """Check and log commands to players."""
+
+    @functools.wraps(func)
+    async def wrapper(self: PlayerControllerT, *args: P.args, **kwargs: P.kwargs) -> R | None:
+        """Log and handle_player_command commands to players."""
+        player_id = kwargs["player_id"] if "player_id" in kwargs else args[0]
+        if (player := self._players.get(player_id)) is None or not player.available:
+            # player not existent
+            self.logger.warning(
+                "Ignoring command %s for unavailable player %s",
+                func.__name__,
+                player_id,
+            )
+            return
+
+        self.logger.debug(
+            "Handling command %s for player %s",
+            func.__name__,
+            player.display_name,
+        )
+        try:
+            await func(self, *args, **kwargs)
+        except Exception as err:
+            raise PlayerCommandFailed(str(err)) from err
+
+    return wrapper
+
+
+class PlayerController(CoreController):
+    """Controller holding all logic to control registered players."""
+
+    domain: str = "players"
+
+    def __init__(self, *args, **kwargs) -> None:
+        """Initialize core controller."""
+        super().__init__(*args, **kwargs)
+        self._players: dict[str, Player] = {}
+        self._controls: dict[str, PlayerControl] = {}
+        self.manifest.name = "Player Controller"
+        self.manifest.description = (
+            "Music Assistant's core controller which manages all players from all providers."
+        )
+        self.manifest.icon = "speaker-multiple"
+        self._poll_task: asyncio.Task | None = None
+        self._player_throttlers: dict[str, Throttler] = {}
+        self._announce_locks: dict[str, asyncio.Lock] = {}
+        self._sync_groups: SyncGroupController = SyncGroupController(self)
+
+    async def setup(self, config: CoreConfig) -> None:
+        """Async initialize of module."""
+        self._poll_task = self.mass.create_task(self._poll_players())
+
+    async def close(self) -> None:
+        """Cleanup on exit."""
+        if self._poll_task and not self._poll_task.done():
+            self._poll_task.cancel()
+
+    async def on_provider_loaded(self, provider: PlayerProvider) -> None:
+        """Handle logic when a provider is loaded."""
+        if ProviderFeature.SYNC_PLAYERS in provider.supported_features:
+            await self._sync_groups.on_provider_loaded(provider)
+
+    async def on_provider_unload(self, provider: PlayerProvider) -> None:
+        """Handle logic when a provider is (about to get) unloaded."""
+        if ProviderFeature.SYNC_PLAYERS in provider.supported_features:
+            await self._sync_groups.on_provider_unload(provider)
+
+    @property
+    def providers(self) -> list[PlayerProvider]:
+        """Return all loaded/running MusicProviders."""
+        return self.mass.get_providers(ProviderType.PLAYER)  # type: ignore=return-value
+
+    def all(
+        self,
+        return_unavailable: bool = True,
+        return_disabled: bool = False,
+        provider_filter: str | None = None,
+        return_sync_groups: bool = True,
+    ) -> list[Player]:
+        """
+        Return all registered players.
+
+        :param return_unavailable [bool]: Include unavailable players.
+        :param return_disabled [bool]: Include disabled players.
+        :param provider_filter [str]: Optional filter by provider lookup key.
+
+        :return: List of Player objects.
+        """
+        return [
+            player
+            for player in self._players.values()
+            if (player.available or return_unavailable)
+            and (player.enabled or return_disabled)
+            and (provider_filter is None or player.provider.lookup_key == provider_filter)
+            and (return_sync_groups or not isinstance(player, SyncGroupPlayer))
+        ]
+
+    @api_command("players/all")
+    def all_states(
+        self,
+        return_unavailable: bool = True,
+        return_disabled: bool = False,
+        provider_filter: str | None = None,
+    ) -> list[PlayerState]:
+        """
+        Return PlayerState for all registered players.
+
+        :param return_unavailable [bool]: Include unavailable players.
+        :param return_disabled [bool]: Include disabled players.
+        :param provider_filter [str]: Optional filter by provider lookup key.
+
+        :return: List of PlayerState objects.
+        """
+        return [
+            player.state
+            for player in self.all(
+                return_unavailable=return_unavailable,
+                return_disabled=return_disabled,
+                provider_filter=provider_filter,
+            )
+        ]
+
+    def get(
+        self,
+        player_id: str,
+        raise_unavailable: bool = False,
+    ) -> Player | None:
+        """
+        Return Player by player_id.
+
+        :param player_id [str]: ID of the player.
+        :param raise_unavailable [bool]: Raise if player is unavailable.
+
+        :raises PlayerUnavailableError: If player is unavailable and raise_unavailable is True.
+        :return: Player object or None.
+        """
+        if player := self._players.get(player_id):
+            if (not player.available or not player.enabled) and raise_unavailable:
+                msg = f"Player {player_id} is not available"
+                raise PlayerUnavailableError(msg)
+            return player
+        if raise_unavailable:
+            msg = f"Player {player_id} is not available"
+            raise PlayerUnavailableError(msg)
+        return None
+
+    @api_command("players/get")
+    def get_state(
+        self,
+        player_id: str,
+        raise_unavailable: bool = False,
+    ) -> PlayerState | None:
+        """
+        Return PlayerState by player_id.
+
+        :param player_id [str]: ID of the player.
+        :param raise_unavailable [bool]: Raise if player is unavailable.
+
+        :raises PlayerUnavailableError: If player is unavailable and raise_unavailable is True.
+        :return: Player object or None.
+        """
+        if player := self.get(player_id, raise_unavailable):
+            return player.state
+        return None
+
+    def get_player_by_name(self, name: str) -> Player | None:
+        """
+        Return Player by name.
+
+        :param name: Name of the player.
+        :return: Player object or None.
+        """
+        return next((x for x in self._players.values() if x.name == name), None)
+
+    @api_command("players/get_by_name")
+    def get_player_state_by_name(self, name: str) -> PlayerState | None:
+        """
+        Return PlayerState by name.
+
+        :param name: Name of the player.
+        :return: PlayerState object or None.
+        """
+        if player := self.get_player_by_name(name):
+            return player.state
+        return None
+
+    @api_command("players/player_controls")
+    def player_controls(
+        self,
+    ) -> list[PlayerControl]:
+        """Return all registered playercontrols."""
+        return list(self._controls.values())
+
+    @api_command("players/player_control")
+    def get_player_control(
+        self,
+        control_id: str,
+    ) -> PlayerControl | None:
+        """
+        Return PlayerControl by control_id.
+
+        :param control_id: ID of the player control.
+        :return: PlayerControl object or None.
+        """
+        if control := self._controls.get(control_id):
+            return control
+        return None
+
+    @api_command("players/plugin_sources")
+    def get_plugin_sources(self) -> list[PluginSource]:
+        """Return all available plugin sources."""
+        return [
+            plugin_prov.get_source()
+            for plugin_prov in self.mass.get_providers(ProviderType.PLUGIN)
+            if isinstance(plugin_prov, PluginProvider)
+            and ProviderFeature.AUDIO_SOURCE in plugin_prov.supported_features
+        ]
+
+    @api_command("players/plugin_source")
+    def get_plugin_source(
+        self,
+        source_id: str,
+    ) -> PluginSource | None:
+        """
+        Return PluginSource by source_id.
+
+        :param source_id: ID of the plugin source.
+        :return: PluginSource object or None.
+        """
+        for plugin_prov in self.mass.get_providers(ProviderType.PLUGIN):
+            assert isinstance(plugin_prov, PluginProvider)  # for type checking
+            if ProviderFeature.AUDIO_SOURCE not in plugin_prov.supported_features:
+                continue
+            if (source := plugin_prov.get_source()) and source.id == source_id:
+                return source
+        return None
+
+    # Player commands
+
+    @api_command("players/cmd/stop")
+    @handle_player_command
+    async def cmd_stop(self, player_id: str) -> None:
+        """Send STOP command to given player.
+
+        - player_id: player_id of the player to handle the command.
+        """
+        player = self._get_player_with_redirect(player_id)
+        # Redirect to queue controller if it is active
+        if active_queue := self.get_active_queue(player):
+            await self.mass.player_queues.stop(active_queue.queue_id)
+            return
+        # handle command on player directly
+        async with self._player_throttlers[player.player_id]:
+            await player.stop()
+
+    @api_command("players/cmd/play")
+    @handle_player_command
+    async def cmd_play(self, player_id: str) -> None:
+        """Send PLAY (unpause) command to given player.
+
+        - player_id: player_id of the player to handle the command.
+        """
+        player = self._get_player_with_redirect(player_id)
+        if player.playback_state == PlaybackState.PLAYING:
+            self.logger.info(
+                "Ignore PLAY request to player %s: player is already playing", player.display_name
+            )
+            return
+        # Redirect to queue controller if it is active
+        if active_queue := self.get_active_queue(player):
+            await self.mass.player_queues.play(active_queue.queue_id)
+            return
+        # handle command on player directly
+        async with self._player_throttlers[player.player_id]:
+            await player.play()
+
+    @api_command("players/cmd/pause")
+    @handle_player_command
+    async def cmd_pause(self, player_id: str) -> None:
+        """Send PAUSE command to given player.
+
+        - player_id: player_id of the player to handle the command.
+        """
+        player = self._get_player_with_redirect(player_id)
+        # Redirect to queue controller if it is active
+        if active_queue := self.get_active_queue(player):
+            await self.mass.player_queues.pause(active_queue.queue_id)
+            return
+        if PlayerFeature.PAUSE not in player.supported_features:
+            # if player does not support pause, we need to send stop
+            self.logger.debug(
+                "Player %s does not support pause, using STOP instead",
+                player.display_name,
+            )
+            await self.cmd_stop(player.player_id)
+            return
+        # handle command on player directly
+        await player.pause()
+
+    @api_command("players/cmd/play_pause")
+    async def cmd_play_pause(self, player_id: str) -> None:
+        """Toggle play/pause on given player.
+
+        - player_id: player_id of the player to handle the command.
+        """
+        player = self._get_player_with_redirect(player_id)
+        if player.playback_state == PlaybackState.PLAYING:
+            await self.cmd_pause(player.player_id)
+        else:
+            await self.cmd_play(player.player_id)
+
+    @api_command("players/cmd/seek")
+    async def cmd_seek(self, player_id: str, position: int) -> None:
+        """Handle SEEK command for given player.
+
+        - player_id: player_id of the player to handle the command.
+        - position: position in seconds to seek to in the current playing item.
+        """
+        player = self._get_player_with_redirect(player_id)
+        # Redirect to queue controller if it is active
+        if active_queue := self.get_active_queue(player):
+            await self.mass.player_queues.seek(active_queue.queue_id, position)
+            return
+        if PlayerFeature.SEEK not in player.supported_features:
+            msg = f"Player {player.display_name} does not support seeking"
+            raise UnsupportedFeaturedException(msg)
+        # handle command on player directly
+        await player.seek(position)
+
+    @api_command("players/cmd/next")
+    async def cmd_next_track(self, player_id: str) -> None:
+        """Handle NEXT TRACK command for given player."""
+        player = self._get_player_with_redirect(player_id)
+        active_source_id = player.active_source or player.player_id
+
+        # Redirect to queue controller if it is active
+        if active_queue := self.get_active_queue(player):
+            await self.mass.player_queues.next(active_queue.queue_id)
+            return
+
+        if PlayerFeature.NEXT_PREVIOUS in player.supported_features:
+            # player has some other source active and native next/previous support
+            active_source = next((x for x in player.source_list if x.id == active_source_id), None)
+            if active_source and active_source.can_next_previous:
+                await player.next_track()
+                return
+            msg = "This action is (currently) unavailable for this source."
+            raise PlayerCommandFailed(msg)
+
+        msg = f"Player {player.display_name} does not support skipping to the next track."
+        raise UnsupportedFeaturedException(msg)
+
+    @api_command("players/cmd/previous")
+    async def cmd_previous_track(self, player_id: str) -> None:
+        """Handle PREVIOUS TRACK command for given player."""
+        player = self._get_player_with_redirect(player_id)
+        active_source_id = player.active_source or player.player_id
+        # Redirect to queue controller if it is active
+        if active_queue := self.get_active_queue(player):
+            await self.mass.player_queues.previous(active_queue.queue_id)
+            return
+
+        if PlayerFeature.NEXT_PREVIOUS in player.supported_features:
+            # player has some other source active and native next/previous support
+            active_source = next((x for x in player.source_list if x.id == active_source_id), None)
+            if active_source and active_source.can_next_previous:
+                await player.previous_track()
+                return
+            msg = "This action is (currently) unavailable for this source."
+            raise PlayerCommandFailed(msg)
+
+        msg = f"Player {player.display_name} does not support skipping to the previous track."
+        raise UnsupportedFeaturedException(msg)
+
+    @api_command("players/cmd/power")
+    @handle_player_command
+    async def cmd_power(self, player_id: str, powered: bool, skip_update: bool = False) -> None:
+        """Send POWER command to given player.
+
+        - player_id: player_id of the player to handle the command.
+        - powered: bool if player should be powered on or off.
+        """
+        player = self.get(player_id, True)
+        assert player is not None  # for type checking
+        player_state = player.state
+
+        if player_state.powered == powered:
+            self.logger.debug(
+                "Ignoring power %s command for player %s: already in state %s",
+                "ON" if powered else "OFF",
+                player_state.name,
+                "ON" if player_state.powered else "OFF",
+            )
+            return  # nothing to do
+
+        # ungroup player at power off
+        player_was_synced = player.synced_to is not None
+        if player.type == PlayerType.PLAYER and not powered:
+            # ungroup player if it is synced (or is a sync leader itself)
+            # NOTE: ungroup will be ignored if the player is not grouped or synced
+            await self.cmd_ungroup(player_id)
+
+        # always stop player at power off
+        if (
+            not powered
+            and not player_was_synced
+            and player.playback_state in (PlaybackState.PLAYING, PlaybackState.PAUSED)
+        ):
+            await self.cmd_stop(player_id)
+            # short sleep: allow the stop command to process and prevent race conditions
+            await asyncio.sleep(0.2)
+
+        # power off all synced childs when player is a sync leader
+        elif not powered and player.type == PlayerType.PLAYER and player.group_members:
+            async with TaskManager(self.mass) as tg:
+                for member in self.iter_group_members(player, True):
+                    if member.power_control == PLAYER_CONTROL_NONE:
+                        continue
+                    tg.create_task(self.cmd_power(member.player_id, False))
+
+        # handle actual power command
+        if player.power_control == PLAYER_CONTROL_NONE:
+            raise UnsupportedFeaturedException(
+                f"Player {player.display_name} does not support power control"
+            )
+        if player.power_control == PLAYER_CONTROL_NATIVE:
+            # player supports power command natively: forward to player provider
+            async with self._player_throttlers[player_id]:
+                await player.power(powered)
+        elif player.power_control == PLAYER_CONTROL_FAKE:
+            # user wants to use fake power control - so we (optimistically) update the state
+            # and store the state in the cache
+            player.extra_data[ATTR_FAKE_POWER] = powered
+            await self.mass.cache.set(
+                key=player_id,
+                data=powered,
+                provider=self.domain,
+                category=CACHE_CATEGORY_PLAYER_POWER,
+            )
+        else:
+            # handle external player control
+            player_control = self._controls.get(player.power_control)
+            control_name = player_control.name if player_control else player.power_control
+            self.logger.debug("Redirecting power command to PlayerControl %s", control_name)
+            if not player_control or not player_control.supports_power:
+                raise UnsupportedFeaturedException(
+                    f"Player control {control_name} is not available"
+                )
+            if powered:
+                assert player_control.power_on is not None  # for type checking
+                await player_control.power_on()
+            else:
+                assert player_control.power_off is not None  # for type checking
+                await player_control.power_off()
+
+        # always optimistically set the power state to update the UI
+        # as fast as possible and prevent race conditions
+        player_state.powered = powered
+        # reset active source on power off
+        if not powered:
+            player_state.active_source = None
+
+        if not skip_update:
+            player.update_state()
+
+        # handle 'auto play on power on' feature
+        if (
+            not player.active_group
+            and powered
+            and player.config.get_value(CONF_AUTO_PLAY)
+            and player.active_source in (None, player_id)
+            and not player.extra_data.get(ATTR_ANNOUNCEMENT_IN_PROGRESS)
+        ):
+            await self.mass.player_queues.resume(player_id)
+
+    @api_command("players/cmd/volume_set")
+    @handle_player_command
+    async def cmd_volume_set(self, player_id: str, volume_level: int) -> None:
+        """Send VOLUME_SET command to given player.
+
+        - player_id: player_id of the player to handle the command.
+        - volume_level: volume level (0..100) to set on the player.
+        """
+        player = self.get(player_id, True)
+        assert player is not None  # for type checker
+        if player.type == PlayerType.GROUP:
+            # redirect to special group volume control
+            await self.cmd_group_volume(player_id, volume_level)
+            return
+
+        if player.volume_control == PLAYER_CONTROL_NONE:
+            raise UnsupportedFeaturedException(
+                f"Player {player.display_name} does not support volume control"
+            )
+
+        if player.mute_control != PLAYER_CONTROL_NONE and player.volume_muted:
+            # if player is muted, we unmute it first
+            self.logger.debug(
+                "Unmuting player %s before setting volume",
+                player.display_name,
+            )
+            await self.cmd_volume_mute(player_id, False)
+
+        if player.volume_control == PLAYER_CONTROL_NATIVE:
+            # player supports volume command natively: forward to player
+            async with self._player_throttlers[player_id]:
+                await player.volume_set(volume_level)
+            return
+        if player.volume_control == PLAYER_CONTROL_FAKE:
+            # user wants to use fake volume control - so we (optimistically) update the state
+            # and store the state in the cache
+            player.extra_data[ATTR_FAKE_VOLUME] = volume_level
+            # trigger update
+            player.update_state()
+            return
+        # else: handle external player control
+        player_control = self._controls.get(player.volume_control)
+        control_name = player_control.name if player_control else player.volume_control
+        self.logger.debug("Redirecting volume command to PlayerControl %s", control_name)
+        if not player_control or not player_control.supports_volume:
+            raise UnsupportedFeaturedException(f"Player control {control_name} is not available")
+        async with self._player_throttlers[player_id]:
+            assert player_control.volume_set is not None
+            await player_control.volume_set(volume_level)
+
+    @api_command("players/cmd/volume_up")
+    @handle_player_command
+    async def cmd_volume_up(self, player_id: str) -> None:
+        """Send VOLUME_UP command to given player.
+
+        - player_id: player_id of the player to handle the command.
+        """
+        if not (player := self.get(player_id)):
+            return
+        current_volume = player.volume_state or 0
+        if current_volume < 5 or current_volume > 95:
+            step_size = 1
+        elif current_volume < 20 or current_volume > 80:
+            step_size = 2
+        else:
+            step_size = 5
+        new_volume = min(100, current_volume + step_size)
+        await self.cmd_volume_set(player_id, new_volume)
+
+    @api_command("players/cmd/volume_down")
+    @handle_player_command
+    async def cmd_volume_down(self, player_id: str) -> None:
+        """Send VOLUME_DOWN command to given player.
+
+        - player_id: player_id of the player to handle the command.
+        """
+        if not (player := self.get(player_id)):
+            return
+        current_volume = player.volume_state or 0
+        if current_volume < 5 or current_volume > 95:
+            step_size = 1
+        elif current_volume < 20 or current_volume > 80:
+            step_size = 2
+        else:
+            step_size = 5
+        new_volume = max(0, current_volume - step_size)
+        await self.cmd_volume_set(player_id, new_volume)
+
+    @api_command("players/cmd/group_volume")
+    @handle_player_command
+    async def cmd_group_volume(
+        self,
+        player_id: str,
+        volume_level: int,
+    ) -> None:
+        """
+        Handle adjusting the overall/group volume to a playergroup (or synced players).
+
+        Will set a new (overall) volume level to a group player or syncgroup.
+
+        :param group_player: dedicated group player or syncleader to handle the command.
+        :param volume_level: volume level (0..100) to set to the group.
+        """
+        player = self.get(player_id, True)
+        assert player is not None  # for type checker
+        if player.type == PlayerType.GROUP or player.group_members:
+            # dedicated group player or sync leader
+            await self.set_group_volume(player, volume_level)
+            return
+        if player.synced_to and (sync_leader := self.get(player.synced_to)):
+            # redirect to sync leader
+            await self.set_group_volume(sync_leader, volume_level)
+            return
+        # treat as normal player volume change
+        await self.cmd_volume_set(player_id, volume_level)
+
+    @api_command("players/cmd/group_volume_up")
+    @handle_player_command
+    async def cmd_group_volume_up(self, player_id: str) -> None:
+        """Send VOLUME_UP command to given playergroup.
+
+        - player_id: player_id of the player to handle the command.
+        """
+        group_player = self.get(player_id, True)
+        assert group_player
+        cur_volume = group_player.group_volume
+        if cur_volume < 5 or cur_volume > 95:
+            step_size = 1
+        elif cur_volume < 20 or cur_volume > 80:
+            step_size = 2
+        else:
+            step_size = 5
+        new_volume = min(100, cur_volume + step_size)
+        await self.cmd_group_volume(player_id, new_volume)
+
+    @api_command("players/cmd/group_volume_down")
+    @handle_player_command
+    async def cmd_group_volume_down(self, player_id: str) -> None:
+        """Send VOLUME_DOWN command to given playergroup.
+
+        - player_id: player_id of the player to handle the command.
+        """
+        group_player = self.get(player_id, True)
+        assert group_player
+        cur_volume = group_player.group_volume
+        if cur_volume < 5 or cur_volume > 95:
+            step_size = 1
+        elif cur_volume < 20 or cur_volume > 80:
+            step_size = 2
+        else:
+            step_size = 5
+        new_volume = max(0, cur_volume - step_size)
+        await self.cmd_group_volume(player_id, new_volume)
+
+    @api_command("players/cmd/volume_mute")
+    @handle_player_command
+    async def cmd_volume_mute(self, player_id: str, muted: bool) -> None:
+        """Send VOLUME_MUTE command to given player.
+
+        - player_id: player_id of the player to handle the command.
+        - muted: bool if player should be muted.
+        """
+        player = self.get(player_id, True)
+        assert player
+        if player.mute_control == PLAYER_CONTROL_NONE:
+            raise UnsupportedFeaturedException(
+                f"Player {player.display_name} does not support muting"
+            )
+        if player.mute_control == PLAYER_CONTROL_NATIVE:
+            # player supports mute command natively: forward to player
+            async with self._player_throttlers[player_id]:
+                await player.volume_mute(muted)
+        elif player.mute_control == PLAYER_CONTROL_FAKE:
+            # user wants to use fake mute control - so we use volume instead
+            self.logger.debug(
+                "Using volume for muting for player %s",
+                player.display_name,
+            )
+            if muted:
+                player.extra_data[ATTR_PREVIOUS_VOLUME] = player.volume_state
+                player.extra_data[ATTR_FAKE_MUTE] = True
+                await self.cmd_volume_set(player_id, 0)
+            else:
+                player._attr_volume_muted = False
+                prev_volume = player.extra_data.get(ATTR_PREVIOUS_VOLUME, 1)
+                player.extra_data[ATTR_FAKE_MUTE] = False
+                await self.cmd_volume_set(player_id, prev_volume)
+        else:
+            # handle external player control
+            player_control = self._controls.get(player.mute_control)
+            control_name = player_control.name if player_control else player.mute_control
+            self.logger.debug("Redirecting mute command to PlayerControl %s", control_name)
+            if not player_control or not player_control.supports_mute:
+                raise UnsupportedFeaturedException(
+                    f"Player control {control_name} is not available"
+                )
+            async with self._player_throttlers[player_id]:
+                assert player_control.mute_set is not None
+                await player_control.mute_set(muted)
+
+    @api_command("players/cmd/play_announcement")
+    async def play_announcement(
+        self,
+        player_id: str,
+        url: str,
+        pre_announce: bool | str | None = None,
+        volume_level: int | None = None,
+        pre_announce_url: str | None = None,
+    ) -> None:
+        """
+        Handle playback of an announcement (url) on given player.
+
+        - player_id: player_id of the player to handle the command.
+        - url: URL of the announcement to play.
+        - pre_announce: optional bool if pre-announce should be used.
+        - volume_level: optional volume level to set for the announcement.
+        - pre_announce_url: optional custom URL to use for the pre-announce chime.
+        """
+        player = self.get(player_id, True)
+        assert player is not None  # for type checking
+        if not url.startswith("http"):
+            raise PlayerCommandFailed("Only URLs are supported for announcements")
+        if (
+            pre_announce
+            and pre_announce_url
+            and not validate_announcement_chime_url(pre_announce_url)
+        ):
+            raise PlayerCommandFailed("Invalid pre-announce chime URL specified.")
+        # prevent multiple announcements at the same time to the same player with a lock
+        if player_id not in self._announce_locks:
+            self._announce_locks[player_id] = lock = asyncio.Lock()
+        else:
+            lock = self._announce_locks[player_id]
+        async with lock:
+            try:
+                # mark announcement_in_progress on player
+                player.extra_data[ATTR_ANNOUNCEMENT_IN_PROGRESS] = True
+                # determine if the player has native announcements support
+                native_announce_support = (
+                    PlayerFeature.PLAY_ANNOUNCEMENT in player.supported_features
+                )
+                # determine pre-announce from (group)player config
+                if pre_announce is None and "tts" in url:
+                    conf_pre_announce = self.mass.config.get_raw_player_config_value(
+                        player_id,
+                        CONF_ENTRY_TTS_PRE_ANNOUNCE.key,
+                        CONF_ENTRY_TTS_PRE_ANNOUNCE.default_value,
+                    )
+                    pre_announce = cast("bool", conf_pre_announce)
+                if pre_announce_url is None:
+                    if conf_pre_announce_url := self.mass.config.get_raw_player_config_value(
+                        player_id,
+                        CONF_PRE_ANNOUNCE_CHIME_URL,
+                    ):
+                        # player default custom chime url
+                        pre_announce_url = cast("str", conf_pre_announce_url)
+                    else:
+                        # use global default chime url
+                        pre_announce_url = ANNOUNCE_ALERT_FILE
+                # if player type is group with all members supporting announcements,
+                # we forward the request to each individual player
+                if player.type == PlayerType.GROUP and (
+                    all(
+                        PlayerFeature.PLAY_ANNOUNCEMENT in x.supported_features
+                        for x in self.iter_group_members(player)
+                    )
+                ):
+                    # forward the request to each individual player
+                    async with TaskManager(self.mass) as tg:
+                        for group_member in player.group_members:
+                            tg.create_task(
+                                self.play_announcement(
+                                    group_member,
+                                    url=url,
+                                    pre_announce=pre_announce,
+                                    volume_level=volume_level,
+                                    pre_announce_url=pre_announce_url,
+                                )
+                            )
+                    return
+                self.logger.info(
+                    "Playback announcement to player %s (with pre-announce: %s): %s",
+                    player.display_name,
+                    pre_announce,
+                    url,
+                )
+                # create a PlayerMedia object for the announcement so
+                # we can send a regular play-media call downstream
+                announce_data = AnnounceData(
+                    announcement_url=url,
+                    pre_announce=pre_announce,
+                    pre_announce_url=pre_announce_url,
+                )
+                announcement = PlayerMedia(
+                    uri=self.mass.streams.get_announcement_url(player_id, url, announce_data),
+                    media_type=MediaType.ANNOUNCEMENT,
+                    title="Announcement",
+                    custom_data=announce_data,
+                )
+                # handle native announce support
+                if native_announce_support:
+                    announcement_volume = self.get_announcement_volume(player_id, volume_level)
+                    await player.play_announcement(announcement, announcement_volume)
+                    return
+                # use fallback/default implementation
+                await self._play_announcement(player, announcement, volume_level)
+            finally:
+                player.extra_data[ATTR_ANNOUNCEMENT_IN_PROGRESS] = False
+
+    @handle_player_command
+    async def play_media(self, player_id: str, media: PlayerMedia) -> None:
+        """Handle PLAY MEDIA on given player.
+
+        - player_id: player_id of the player to handle the command.
+        - media: The Media that needs to be played on the player.
+        """
+        player = self._get_player_with_redirect(player_id)
+        # power on the player if needed
+        if player.powered is False and player.power_control != PLAYER_CONTROL_NONE:
+            await self.cmd_power(player.player_id, True)
+        await player.play_media(media)
+
+    @api_command("players/cmd/select_source")
+    async def select_source(self, player_id: str, source: str) -> None:
+        """
+        Handle SELECT SOURCE command on given player.
+
+        - player_id: player_id of the player to handle the command.
+        - source: The ID of the source that needs to be activated/selected.
+        """
+        player = self.get(player_id, True)
+        assert player is not None  # for type checking
+        if player.synced_to or player.active_group:
+            raise PlayerCommandFailed(f"Player {player.display_name} is currently grouped")
+        # check if player is already playing and source is different
+        # in that case we need to stop the player first
+        prev_source = player.active_source
+        if prev_source and source != prev_source:
+            if player.playback_state != PlaybackState.IDLE:
+                await self.cmd_stop(player_id)
+                await asyncio.sleep(0.5)  # small delay to allow stop to process
+            player.state.active_source = None
+            player.state.current_media = None
+        # check if source is a pluginsource
+        # in that case the source id is the instance_id of the plugin provider
+        if plugin_prov := self.mass.get_provider(source):
+            await self._handle_select_plugin_source(player, plugin_prov)
+            return
+        # check if source is a mass queue
+        # this can be used to restore the queue after a source switch
+        if mass_queue := self.mass.player_queues.get(source):
+            await self.mass.player_queues.play(mass_queue.queue_id)
+            return
+        # basic check if player supports source selection
+        if PlayerFeature.SELECT_SOURCE not in player.supported_features:
+            raise UnsupportedFeaturedException(
+                f"Player {player.display_name} does not support source selection"
+            )
+        # basic check if source is valid for player
+        if not any(x for x in player.source_list if x.id == source):
+            raise PlayerCommandFailed(
+                f"{source} is an invalid source for player {player.display_name}"
+            )
+        # forward to player
+        await player.select_source(source)
+
+    async def enqueue_next_media(self, player_id: str, media: PlayerMedia) -> None:
+        """
+        Handle enqueuing of a next media item on the player.
+
+        :param player_id: player_id of the player to handle the command.
+        :param media: The Media that needs to be enqueued on the player.
+        :raises UnsupportedFeaturedException: if the player does not support enqueueing.
+        :raises PlayerUnavailableError: if the player is not available.
+        """
+        player = self.get(player_id, raise_unavailable=True)
+        assert player is not None  # for type checking
+        if PlayerFeature.ENQUEUE not in player.supported_features:
+            raise UnsupportedFeaturedException(
+                f"Player {player.display_name} does not support enqueueing"
+            )
+        async with self._player_throttlers[player_id]:
+            await player.enqueue_next_media(media)
+
+    @api_command("players/cmd/set_members")
+    async def cmd_set_members(
+        self,
+        target_player: str,
+        player_ids_to_add: list[str] | None = None,
+        player_ids_to_remove: list[str] | None = None,
+    ) -> None:
+        """
+        Join/unjoin given player(s) to/from target player.
+
+        Will add the given player(s) to the target player (sync leader or group player).
+
+        :param target_player: player_id of the syncgroup leader or group player.
+        :param player_ids_to_add: List of player_id's to add to the target player.
+        :param player_ids_to_remove: List of player_id's to remove from the target player.
+
+        :raises UnsupportedFeaturedException: if the target player does not support grouping.
+        :raises PlayerUnavailableError: if the target player is not available.
+        """
+        parent_player: Player | None = self.get(target_player, True)
+        assert parent_player is not None  # for type checking
+        if PlayerFeature.SET_MEMBERS not in parent_player.supported_features:
+            msg = f"Player {parent_player.name} does not support group commands"
+            raise UnsupportedFeaturedException(msg)
+
+        if parent_player.synced_to:
+            # guard edge case: player already synced to another player
+            raise PlayerCommandFailed(
+                f"Player {parent_player.name} is already synced to another player on its own, "
+                "you need to ungroup it first before you can join other players to it.",
+            )
+
+        # filter all player ids on compatibility and availability
+        final_player_ids_to_add: list[str] = []
+        for child_player_id in player_ids_to_add or []:
+            if child_player_id == target_player:
+                continue
+            if child_player_id in final_player_ids_to_add:
+                continue
+            if not (child_player := self.get(child_player_id)) or not child_player.available:
+                self.logger.warning("Player %s is not available", child_player_id)
+                continue
+
+            # check if player can be synced/grouped with the target player
+            if not (
+                child_player_id in parent_player.can_group_with
+                or child_player.provider.lookup_key in parent_player.can_group_with
+                or "*" in parent_player.can_group_with
+            ):
+                raise UnsupportedFeaturedException(
+                    f"Player {child_player.name} can not be grouped with {parent_player.name}"
+                )
+
+            if (
+                child_player.synced_to
+                and child_player.synced_to == target_player
+                and child_player_id in parent_player.group_members
+            ):
+                continue  # already synced to this target
+
+            # Check if player is already part of another group and try to automatically ungroup it
+            # first. If that fails, power off the group
+            if child_player.active_group and child_player.active_group != target_player:
+                if (
+                    other_group := self.get(child_player.active_group)
+                ) and PlayerFeature.SET_MEMBERS in other_group.supported_features:
+                    self.logger.warning(
+                        "Player %s is already part of another group (%s), "
+                        "removing from that group first",
+                        child_player.name,
+                        child_player.active_group,
+                    )
+                    if child_player.player_id in other_group.static_group_members:
+                        self.logger.warning(
+                            "Player %s is a static member of group %s: removing is not possible, "
+                            "powering the group off instead",
+                            child_player.name,
+                            child_player.active_group,
+                        )
+                        await self.cmd_power(child_player.active_group, False)
+                    else:
+                        await other_group.set_members(player_ids_to_remove=[child_player.player_id])
+                else:
+                    self.logger.warning(
+                        "Player %s is already part of another group (%s), powering it off first",
+                        child_player.name,
+                        child_player.active_group,
+                    )
+                    await self.cmd_power(child_player.active_group, False)
+            elif child_player.synced_to and child_player.synced_to != target_player:
+                self.logger.warning(
+                    "Player %s is already synced to another player, ungrouping first",
+                    child_player.name,
+                )
+                await self.cmd_ungroup(child_player.player_id)
+
+            # power on the player if needed
+            if not child_player.powered and child_player.power_control != PLAYER_CONTROL_NONE:
+                await self.cmd_power(child_player.player_id, True, skip_update=True)
+            # if we reach here, all checks passed
+            final_player_ids_to_add.append(child_player_id)
+
+        final_player_ids_to_remove: list[str] = []
+        if player_ids_to_remove:
+            static_members = set(parent_player.static_group_members)
+            for child_player_id in player_ids_to_remove:
+                if child_player_id == target_player:
+                    raise UnsupportedFeaturedException(
+                        f"Cannot remove {parent_player.name} from itself as a member!"
+                    )
+                if child_player_id not in parent_player.group_members:
+                    continue
+                if child_player_id in static_members:
+                    raise UnsupportedFeaturedException(
+                        f"Cannot remove {child_player_id} from {parent_player.name} "
+                        "as it is a static member of this group"
+                    )
+                final_player_ids_to_remove.append(child_player_id)
+
+        # forward command to the player after all (base) sanity checks
+        async with self._player_throttlers[target_player]:
+            await parent_player.set_members(
+                player_ids_to_add=final_player_ids_to_add or None,
+                player_ids_to_remove=final_player_ids_to_remove or None,
+            )
+
+    @api_command("players/cmd/group")
+    @handle_player_command
+    async def cmd_group(self, player_id: str, target_player: str) -> None:
+        """Handle GROUP command for given player.
+
+        Join/add the given player(id) to the given (leader) player/sync group.
+        If the target player itself is already synced to another player, this may fail.
+        If the player can not be synced with the given target player, this may fail.
+
+        :param player_id: player_id of the player to handle the command.
+        :param target_player: player_id of the syncgroup leader or group player.
+
+        :raises UnsupportedFeaturedException: if the target player does not support grouping.
+        :raises PlayerCommandFailed: if the target player is already synced to another player.
+        :raises PlayerUnavailableError: if the target player is not available.
+        :raises PlayerCommandFailed: if the player is already grouped to another player.
+        """
+        await self.cmd_set_members(target_player, player_ids_to_add=[player_id])
+
+    @api_command("players/cmd/group_many")
+    async def cmd_group_many(self, target_player: str, child_player_ids: list[str]) -> None:
+        """
+        Join given player(s) to target player.
+
+        Will add the given player(s) to the target player (sync leader or group player).
+        NOTE: This is a (deprecated) alias for cmd_set_members.
+        """
+        await self.cmd_set_members(target_player, player_ids_to_add=child_player_ids)
+
+    @api_command("players/cmd/ungroup")
+    @handle_player_command
+    async def cmd_ungroup(self, player_id: str) -> None:
+        """Handle UNGROUP command for given player.
+
+        Remove the given player from any (sync)groups it currently is synced to.
+        If the player is not currently grouped to any other player,
+        this will silently be ignored.
+
+        NOTE: This is a (deprecated) alias for cmd_set_members.
+        """
+        if not (player := self.get(player_id)):
+            self.logger.warning("Player %s is not available", player_id)
+            return
+
+        if (
+            player.active_group
+            and (group_player := self.get(player.active_group))
+            and (PlayerFeature.SET_MEMBERS in group_player.supported_features)
+        ):
+            # the player is part of a (permanent) groupplayer and the user tries to ungroup
+            if player_id in group_player.static_group_members:
+                raise UnsupportedFeaturedException(
+                    f"Player {player.name}  is a static member of group {group_player.name} "
+                    "and cannot be removed from that group!"
+                )
+            await group_player.set_members(player_ids_to_remove=[player_id])
+            return
+
+        if player.synced_to and (synced_player := self.get(player.synced_to)):
+            # player is a sync member
+            await synced_player.set_members(player_ids_to_remove=[player_id])
+            return
+
+        if not (player.synced_to or player.group_members):
+            return  # nothing to do
+
+        if PlayerFeature.SET_MEMBERS not in player.supported_features:
+            self.logger.warning("Player %s does not support (un)group commands", player.name)
+            return
+
+        # forward command to the player once all checks passed
+        await player.ungroup()
+
+    @api_command("players/cmd/ungroup_many")
+    async def cmd_ungroup_many(self, player_ids: list[str]) -> None:
+        """Handle UNGROUP command for all the given players."""
+        for player_id in list(player_ids):
+            await self.cmd_ungroup(player_id)
+
+    @api_command("players/create_group_player")
+    async def create_group_player(
+        self, provider: str, name: str, members: list[str], dynamic: bool = True
+    ):
+        """
+        Create a new (permanent) Group Player.
+
+        :param provider: The provider(id) to create the group player for
+        :param name: Name of the new group player
+        :param members: List of player ids to add to the group
+        :param dynamic: Whether the group is dynamic (members can change)
+        """
+        if not (provider_instance := self.mass.get_provider(provider)):
+            raise ProviderUnavailableError(f"Provider {provider} not found")
+        provider_instance = cast("PlayerProvider", provider_instance)
+        if ProviderFeature.CREATE_GROUP_PLAYER in provider_instance.supported_features:
+            return await provider_instance.create_group_player(name, members, dynamic)
+        if ProviderFeature.SYNC_PLAYERS in provider_instance.supported_features:
+            # provider supports syncing but not dedicated group players
+            # create a sync group instead
+            return await self._sync_groups.create_group_player(
+                provider_instance, name, members, dynamic=dynamic
+            )
+        raise UnsupportedFeaturedException(
+            f"Provider {provider} does not support creating group players"
+        )
+
+    @api_command("players/remove_group_player")
+    async def remove_group_player(self, player_id: str) -> None:
+        """
+        Remove a group player.
+
+        :param player_id: ID of the group player to remove.
+        """
+        if not (player := self.get(player_id)):
+            # we simply permanently delete the player by wiping its config
+            self.mass.config.remove(f"players/{player_id}")
+            return
+        if player.type != PlayerType.GROUP:
+            raise UnsupportedFeaturedException(
+                f"Player {player.display_name} is not a group player"
+            )
+        player.provider.check_feature(ProviderFeature.REMOVE_GROUP_PLAYER)
+        await player.provider.remove_group_player(player_id)
+
+    @api_command("players/add_currently_playing_to_favorites")
+    async def add_currently_playing_to_favorites(self, player_id: str) -> None:
+        """
+        Add the currently playing item/track on given player to the favorites.
+
+        This tries to resolve the currently playing media to an actual media item
+        and add that to the favorites in the library.
+
+        Will raise an error if the player is not currently playing anything
+        or if the currently playing media can not be resolved to a media item.
+        """
+        player = self._get_player_with_redirect(player_id)
+        # handle mass player queue active
+        if mass_queue := self.get_active_queue(player):
+            if not (current_item := mass_queue.current_item) or not current_item.media_item:
+                raise PlayerCommandFailed("No current item to add to favorites")
+            # if we're playing a radio station, try to resolve the currently playing track
+            if current_item.media_item.media_type == MediaType.RADIO:
+                if not (
+                    (streamdetails := mass_queue.current_item.streamdetails)
+                    and (stream_title := streamdetails.stream_title)
+                    and " - " in stream_title
+                ):
+                    # no stream title available, so we can't resolve the track
+                    # this can happen if the radio station does not provide metadata
+                    # or there's a commercial break
+                    # Possible future improvement could be to actually detect the song with a
+                    # shazam-like approach.
+                    raise PlayerCommandFailed("No current item to add to favorites")
+                # send the streamtitle into a global search query
+                search_artist, search_title_title = stream_title.split(" - ", 1)
+                # strip off any additional comments in the title (such as from Radio Paradise)
+                search_title_title = search_title_title.split(" | ")[0].strip()
+                if track := await self.mass.music.get_track_by_name(
+                    search_title_title, search_artist
+                ):
+                    # we found a track, so add it to the favorites
+                    await self.mass.music.add_item_to_favorites(track)
+                    return
+                # we could not resolve the track, so raise an error
+                raise PlayerCommandFailed("No current item to add to favorites")
+
+            # else: any other media item, just add it to the favorites directly
+            await self.mass.music.add_item_to_favorites(current_item.media_item)
+            return
+
+        # guard for player with no active source
+        if not player.active_source:
+            raise PlayerCommandFailed("Player has no active source")
+        # handle other source active using the current_media with uri
+        if current_media := player.current_media:
+            # prefer the uri of the current media item
+            if current_media.uri:
+                with suppress(MusicAssistantError):
+                    await self.mass.music.add_item_to_favorites(current_media.uri)
+                    return
+            # fallback to search based on artist and title (and album if available)
+            if current_media.artist and current_media.title:
+                if track := await self.mass.music.get_track_by_name(
+                    current_media.title,
+                    current_media.artist,
+                    current_media.album,
+                ):
+                    # we found a track, so add it to the favorites
+                    await self.mass.music.add_item_to_favorites(track)
+                    return
+        # if we reach here, we could not resolve the currently playing item
+        raise PlayerCommandFailed("No current item to add to favorites")
+
+    async def register(self, player: Player) -> None:
+        """Register a player on the Player Controller."""
+        if self.mass.closing:
+            return
+        player_id = player.player_id
+
+        if player_id in self._players:
+            msg = f"Player {player_id} is already registered!"
+            raise AlreadyRegisteredError(msg)
+
+        # ignore disabled players
+        if not player.enabled:
+            return
+
+        # register throttler for this player
+        self._player_throttlers[player_id] = Throttler(1, 0.05)
+
+        # restore 'fake' power state from cache if available
+        cached_value = await self.mass.cache.get(
+            key=player.player_id,
+            provider=self.domain,
+            category=CACHE_CATEGORY_PLAYER_POWER,
+            default=False,
+        )
+        if cached_value is not None:
+            player.extra_data[ATTR_FAKE_POWER] = cached_value
+
+        # finally actually register it
+        self._players[player_id] = player
+
+        # ensure we fetch and set the latest/full config for the player
+        player_config = await self.mass.config.get_player_config(player_id)
+        player.set_config(player_config)
+        # call hook after the player is registered and config is set
+        await player.on_config_updated()
+        # always call update to fix special attributes like display name, group volume etc.
+        player.update_state()
+
+        self.logger.info(
+            "Player registered: %s/%s",
+            player_id,
+            player.display_name,
+        )
+        # signal event that a player was added
+        self.mass.signal_event(EventType.PLAYER_ADDED, object_id=player.player_id, data=player)
+
+        # register playerqueue for this player
+        await self.mass.player_queues.on_player_register(player)
+
+    async def register_or_update(self, player: Player) -> None:
+        """Register a new player on the controller or update existing one."""
+        if self.mass.closing:
+            return
+
+        if player.player_id in self._players:
+            self._players[player.player_id] = player
+            player.update_state()
+            return
+
+        await self.register(player)
+
+    def trigger_player_update(self, player_id: str, force_update: bool = False) -> None:
+        """Trigger an update for the given player."""
+        if self.mass.closing:
+            return
+        player = self.get(player_id, True)
+        assert player is not None  # for type checker
+        self.mass.loop.call_soon(player.update_state, force_update)
+
+    async def unregister(self, player_id: str, permanent: bool = False) -> None:
+        """
+        Unregister a player from the player controller.
+
+        Called (by a PlayerProvider) when a player is removed
+        or no longer available (for a longer period of time).
+
+        This will remove the player from the player controller and
+        optionally remove the player's config from the mass config.
+
+        - player_id: player_id of the player to unregister.
+        - permanent: if True, remove the player permanently by deleting
+        the player's config from the mass config. If False, the player config will not be removed,
+        allowing for re-registration (with the same config) later.
+
+        If the player is not registered, this will silently be ignored.
+        """
+        player = self._players.get(player_id)
+        if player is None:
+            return
+        await self._cleanup_player_memberships(player_id)
+        del self._players[player_id]
+        self.logger.info("Player removed: %s", player.name)
+        self.mass.player_queues.on_player_remove(player_id, permanent=permanent)
+        await player.on_unload()
+        if permanent:
+            self.delete_player_config(player_id)
+        self.mass.signal_event(EventType.PLAYER_REMOVED, player_id)
+
+    @api_command("players/remove")
+    async def remove(self, player_id: str) -> None:
+        """
+        Remove a player from a provider.
+
+        Can only be called when a PlayerProvider supports ProviderFeature.REMOVE_PLAYER.
+        """
+        player = self.get(player_id)
+        if player is None:
+            # we simply permanently delete the player config since it is not registered
+            self.delete_player_config(player_id)
+            return
+        if player.type == PlayerType.GROUP:
+            # Handle group player removal
+            await player.provider.remove_group_player(player_id)
+            return
+        player.provider.check_feature(ProviderFeature.REMOVE_PLAYER)
+        await player.provider.remove_player(player_id)
+        # check for group memberships that need to be updated
+        if player.active_group and (group_player := self.mass.players.get(player.active_group)):
+            # try to remove from the group
+            with suppress(UnsupportedFeaturedException, PlayerCommandFailed):
+                await group_player.set_members(
+                    player_ids_to_remove=[player_id],
+                )
+        # We removed the player and can now clean up its config
+        self.delete_player_config(player_id)
+
+    def delete_player_config(self, player_id: str) -> None:
+        """
+        Permanently delete a player's configuration.
+
+        Should only be called for players that are not registered by the player controller.
+        """
+        # we simply permanently delete the player by wiping its config
+        conf_key = f"{CONF_PLAYERS}/{player_id}"
+        dsp_conf_key = f"{CONF_PLAYER_DSP}/{player_id}"
+        for key in (conf_key, dsp_conf_key):
+            self.mass.config.remove(key)
+
+    def signal_player_state_update(
+        self,
+        player: Player,
+        changed_values: dict[str, tuple[Any, Any]],
+        force_update: bool = False,
+        skip_forward: bool = False,
+    ) -> None:
+        """
+        Signal a player state update.
+
+        Called by a Player when its state has changed.
+        This will update the player state in the controller and signal the event bus.
+        """
+        player_id = player.player_id
+        if self.mass.closing:
+            return
+
+        # ignore updates for disabled players
+        if not player.enabled and "enabled" not in changed_values:
+            return
+
+        if len(changed_values) == 0 and not force_update:
+            # nothing changed
+            return
+
+        # always signal update to the playerqueue
+        self.mass.player_queues.on_player_update(player, changed_values)
+
+        if changed_values.keys() == {"elapsed_time"} and not force_update:
+            # ignore elapsed_time only changes
+            prev_value = changed_values["elapsed_time"][0] or 0
+            new_value = changed_values["elapsed_time"][1] or 0
+            if abs(prev_value - new_value) < 30:
+                # ignore small changes in elapsed time
+                return
+
+        # handle DSP reload of the leader when grouping/ungrouping
+        if ATTR_GROUP_MEMBERS in changed_values:
+            prev_group_members, new_group_members = changed_values[ATTR_GROUP_MEMBERS]
+            self._handle_group_dsp_change(player, prev_group_members or [], new_group_members)
+
+        if ATTR_GROUP_MEMBERS in changed_values:
+            # Removed group members also need to be updated since they are no longer part
+            # of this group and are available for playback again
+            prev_group_members = changed_values[ATTR_GROUP_MEMBERS][0] or []
+            new_group_members = changed_values[ATTR_GROUP_MEMBERS][1] or []
+            removed_members = set(prev_group_members) - set(new_group_members)
+            for player_id in removed_members:
+                if removed_player := self.get(player_id):
+                    removed_player.update_state()
+
+        became_inactive = False
+        if "available" in changed_values:
+            became_inactive = changed_values["available"][1] is False
+        if not became_inactive and "enabled" in changed_values:
+            became_inactive = changed_values["enabled"][1] is False
+        if became_inactive and (player.active_group or player.synced_to):
+            self.mass.create_task(self._cleanup_player_memberships(player.player_id))
+
+        # signal player update on the eventbus
+        self.mass.signal_event(EventType.PLAYER_UPDATED, object_id=player_id, data=player)
+
+        if skip_forward and not force_update:
+            return
+
+        # update/signal group player(s) child's when group updates
+        for child_player in self.iter_group_members(player, exclude_self=True):
+            child_player.update_state()
+        # update/signal group player(s) when child updates
+        for group_player in self._get_player_groups(player, powered_only=False):
+            group_player.update_state()
+        # update/signal manually synced to player when child updates
+        if (synced_to := player.synced_to) and (synced_to_player := self.get(synced_to)):
+            synced_to_player.update_state()
+        # update/signal active groups when a group member updates
+        if (active_group := player.active_group) and (
+            active_group_player := self.get(active_group)
+        ):
+            active_group_player.update_state()
+
+    async def register_player_control(self, player_control: PlayerControl) -> None:
+        """Register a new PlayerControl on the controller."""
+        if self.mass.closing:
+            return
+        control_id = player_control.id
+
+        if control_id in self._controls:
+            msg = f"PlayerControl {control_id} is already registered"
+            raise AlreadyRegisteredError(msg)
+
+        # make sure that the playercontrol's provider is set to the instance_id
+        prov = self.mass.get_provider(player_control.provider)
+        if not prov or prov.instance_id != player_control.provider:
+            raise RuntimeError(f"Invalid provider ID given: {player_control.provider}")
+
+        self._controls[control_id] = player_control
+
+        self.logger.info(
+            "PlayerControl registered: %s/%s",
+            control_id,
+            player_control.name,
+        )
+
+        # always call update to update any attached players etc.
+        self.update_player_control(player_control.id)
+
+    async def register_or_update_player_control(self, player_control: PlayerControl) -> None:
+        """Register a new playercontrol on the controller or update existing one."""
+        if self.mass.closing:
+            return
+        if player_control.id in self._controls:
+            self._controls[player_control.id] = player_control
+            self.update_player_control(player_control.id)
+            return
+        await self.register_player_control(player_control)
+
+    def update_player_control(self, control_id: str) -> None:
+        """Update playercontrol state."""
+        if self.mass.closing:
+            return
+        # update all players that are using this control
+        for player in self._players.values():
+            if control_id in (player.power_control, player.volume_control, player.mute_control):
+                self.mass.loop.call_soon(player.update_state)
+
+    def remove_player_control(self, control_id: str) -> None:
+        """Remove a player_control from the player manager."""
+        control = self._controls.pop(control_id, None)
+        if control is None:
+            return
+        self._controls.pop(control_id, None)
+        self.logger.info("PlayerControl removed: %s", control.name)
+
+    def get_player_provider(self, player_id: str) -> PlayerProvider:
+        """Return PlayerProvider for given player."""
+        player = self._players[player_id]
+        assert player  # for type checker
+        return player.provider
+
+    def get_active_queue(self, player: Player) -> PlayerQueue | None:
+        """Return the current active queue for a player (if any)."""
+        # account for player that is synced (sync child)
+        if player.synced_to and player.synced_to != player.player_id:
+            if sync_leader := self.get(player.synced_to):
+                return self.get_active_queue(sync_leader)
+        # handle active group player
+        if player.active_group and player.active_group != player.player_id:
+            if group_player := self.get(player.active_group):
+                return self.get_active_queue(group_player)
+        # active_source may be filled queue id (or None)
+        active_source = player.active_source or player.player_id
+        if active_queue := self.mass.player_queues.get(active_source):
+            return active_queue
+        return None
+
+    async def set_group_volume(self, group_player: Player, volume_level: int) -> None:
+        """Handle adjusting the overall/group volume to a playergroup (or synced players)."""
+        cur_volume = group_player.state.group_volume
+        volume_dif = volume_level - cur_volume
+        coros = []
+        # handle group volume by only applying the volume to powered members
+        for child_player in self.iter_group_members(
+            group_player, only_powered=True, exclude_self=False
+        ):
+            if child_player.volume_control == PLAYER_CONTROL_NONE:
+                continue
+            cur_child_volume = child_player.volume_level or 0
+            new_child_volume = int(cur_child_volume + volume_dif)
+            new_child_volume = max(0, new_child_volume)
+            new_child_volume = min(100, new_child_volume)
+            coros.append(self.cmd_volume_set(child_player.player_id, new_child_volume))
+        await asyncio.gather(*coros)
+
+    def get_announcement_volume(self, player_id: str, volume_override: int | None) -> int | None:
+        """Get the (player specific) volume for a announcement."""
+        volume_strategy = self.mass.config.get_raw_player_config_value(
+            player_id,
+            CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY.key,
+            CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY.default_value,
+        )
+        volume_strategy_volume = self.mass.config.get_raw_player_config_value(
+            player_id,
+            CONF_ENTRY_ANNOUNCE_VOLUME.key,
+            CONF_ENTRY_ANNOUNCE_VOLUME.default_value,
+        )
+        if volume_strategy == "none":
+            return None
+        volume_level = volume_override
+        if volume_level is None and volume_strategy == "absolute":
+            volume_level = volume_strategy_volume
+        elif volume_level is None and volume_strategy == "relative":
+            player = self.get(player_id)
+            volume_level = player.volume_level + volume_strategy_volume
+        elif volume_level is None and volume_strategy == "percentual":
+            player = self.get(player_id)
+            percentual = (player.volume_level / 100) * volume_strategy_volume
+            volume_level = player.volume_level + percentual
+        if volume_level is not None:
+            announce_volume_min = self.mass.config.get_raw_player_config_value(
+                player_id,
+                CONF_ENTRY_ANNOUNCE_VOLUME_MIN.key,
+                CONF_ENTRY_ANNOUNCE_VOLUME_MIN.default_value,
+            )
+            volume_level = max(announce_volume_min, volume_level)
+            announce_volume_max = self.mass.config.get_raw_player_config_value(
+                player_id,
+                CONF_ENTRY_ANNOUNCE_VOLUME_MAX.key,
+                CONF_ENTRY_ANNOUNCE_VOLUME_MAX.default_value,
+            )
+            volume_level = min(announce_volume_max, volume_level)
+        # ensure the result is an integer
+        return None if volume_level is None else int(volume_level)
+
+    def iter_group_members(
+        self,
+        group_player: Player,
+        only_powered: bool = False,
+        only_playing: bool = False,
+        active_only: bool = False,
+        exclude_self: bool = True,
+    ) -> Iterator[Player]:
+        """Get (child) players attached to a group player or syncgroup."""
+        for child_id in list(group_player.group_members):
+            if child_player := self.get(child_id, False):
+                if not child_player.available or not child_player.enabled:
+                    continue
+                if only_powered and child_player.powered is False:
+                    continue
+                if active_only and child_player.active_group != group_player.player_id:
+                    continue
+                if exclude_self and child_player.player_id == group_player.player_id:
+                    continue
+                if only_playing and child_player.playback_state not in (
+                    PlaybackState.PLAYING,
+                    PlaybackState.PAUSED,
+                ):
+                    continue
+                yield child_player
+
+    async def wait_for_state(
+        self,
+        player: Player,
+        wanted_state: PlaybackState,
+        timeout: float = 60.0,
+        minimal_time: float = 0,
+    ) -> None:
+        """Wait for the given player to reach the given state."""
+        start_timestamp = time.time()
+        self.logger.debug(
+            "Waiting for player %s to reach state %s", player.display_name, wanted_state
+        )
+        try:
+            async with asyncio.timeout(timeout):
+                while player.playback_state != wanted_state:
+                    await asyncio.sleep(0.1)
+
+        except TimeoutError:
+            self.logger.debug(
+                "Player %s did not reach state %s within the timeout of %s seconds",
+                player.display_name,
+                wanted_state,
+                timeout,
+            )
+        elapsed_time = round(time.time() - start_timestamp, 2)
+        if elapsed_time < minimal_time:
+            self.logger.debug(
+                "Player %s reached state %s too soon (%s vs %s seconds) - add fallback sleep...",
+                player.display_name,
+                wanted_state,
+                elapsed_time,
+                minimal_time,
+            )
+            await asyncio.sleep(minimal_time - elapsed_time)
+        else:
+            self.logger.debug(
+                "Player %s reached state %s within %s seconds",
+                player.display_name,
+                wanted_state,
+                elapsed_time,
+            )
+
+    async def on_player_config_change(self, config: PlayerConfig, changed_keys: set[str]) -> None:
+        """Call (by config manager) when the configuration of a player changes."""
+        player_disabled = "enabled" in changed_keys and not config.enabled
+        # signal player provider that the player got enabled/disabled
+        if player_provider := self.mass.get_provider(config.provider):
+            assert isinstance(player_provider, PlayerProvider)  # for type checking
+            if "enabled" in changed_keys and not config.enabled:
+                player_provider.on_player_disabled(config.player_id)
+            elif "enabled" in changed_keys and config.enabled:
+                player_provider.on_player_enabled(config.player_id)
+        # ensure player state gets updated with any updated config
+        if not (player := self.get(config.player_id)):
+            return  # guard against player not being registered (yet)
+        player.set_config(config)
+        await player.on_config_updated()
+        player.update_state()
+        resume_queue: PlayerQueue | None = (
+            self.mass.player_queues.get(player.active_source) if player.active_source else None
+        )
+        if player_disabled:
+            # edge case: ensure that the player is powered off if the player gets disabled
+            if player.power_control != PLAYER_CONTROL_NONE:
+                await self.cmd_power(config.player_id, False)
+            elif player.playback_state != PlaybackState.IDLE:
+                await self.cmd_stop(config.player_id)
+        # if the PlayerQueue was playing, restart playback
+        # TODO: add property to ConfigEntry if it requires a restart of playback on change
+        elif not player_disabled and resume_queue and resume_queue.state == PlaybackState.PLAYING:
+            # always stop first to ensure the player uses the new config
+            await self.mass.player_queues.stop(resume_queue.queue_id)
+            self.mass.call_later(1, self.mass.player_queues.resume, resume_queue.queue_id, False)
+
+    async def on_player_dsp_change(self, player_id: str) -> None:
+        """Call (by config manager) when the DSP settings of a player change."""
+        # signal player provider that the config changed
+        if not (player := self.get(player_id)):
+            return
+        if player.playback_state == PlaybackState.PLAYING:
+            self.logger.info("Restarting playback of Player %s after DSP change", player_id)
+            # this will restart the queue stream/playback
+            if player.mass_queue_active:
+                self.mass.call_later(0, self.mass.player_queues.resume, player.active_source, False)
+                return
+            # if the player is not using a queue, we need to stop and start playback
+            await self.cmd_stop(player_id)
+            await self.cmd_play(player_id)
+
+    async def _cleanup_player_memberships(self, player_id: str) -> None:
+        """Ensure a player is detached from any groups or syncgroups."""
+        if not (player := self.get(player_id)):
+            return
+
+        if (
+            player.active_group
+            and (group := self.get(player.active_group))
+            and group.supports_feature(PlayerFeature.SET_MEMBERS)
+        ):
+            # Ungroup the player if its part of an active group, this will ignore
+            # static_group_members since that is only checked when using cmd_set_members
+            with suppress(UnsupportedFeaturedException, PlayerCommandFailed):
+                await group.set_members(player_ids_to_remove=[player_id])
+        elif player.synced_to and player.supports_feature(PlayerFeature.SET_MEMBERS):
+            # Remove the player if it was synced, otherwise it will still show as
+            # synced to the other player after it gets registered again
+            with suppress(UnsupportedFeaturedException, PlayerCommandFailed):
+                await player.ungroup()
+
+    def _get_player_with_redirect(self, player_id: str) -> Player:
+        """Get player with check if playback related command should be redirected."""
+        player = self.get(player_id, True)
+        assert player is not None  # for type checking
+        if player.synced_to and (sync_leader := self.get(player.synced_to)):
+            self.logger.info(
+                "Player %s is synced to %s and can not accept "
+                "playback related commands itself, "
+                "redirected the command to the sync leader.",
+                player.name,
+                sync_leader.name,
+            )
+            return sync_leader
+        if player.active_group and (active_group := self.get(player.active_group)):
+            self.logger.info(
+                "Player %s is part of a playergroup and can not accept "
+                "playback related commands itself, "
+                "redirected the command to the group leader.",
+                player.name,
+            )
+            return active_group
+        return player
+
+    def _get_player_groups(
+        self, player: Player, available_only: bool = True, powered_only: bool = False
+    ) -> Iterator[Player]:
+        """Return all groupplayers the given player belongs to."""
+        for _player in self.all(return_unavailable=not available_only):
+            if _player.player_id == player.player_id:
+                continue
+            if _player.type != PlayerType.GROUP:
+                continue
+            if powered_only and _player.powered is False:
+                continue
+            if player.player_id in _player.group_members:
+                yield _player
+
+    async def _play_announcement(  # noqa: PLR0915
+        self,
+        player: Player,
+        announcement: PlayerMedia,
+        volume_level: int | None = None,
+    ) -> None:
+        """Handle (default/fallback) implementation of the play announcement feature.
+
+        This default implementation will;
+        - stop playback of the current media (if needed)
+        - power on the player (if needed)
+        - raise the volume a bit
+        - play the announcement (from given url)
+        - wait for the player to finish playing
+        - restore the previous power and volume
+        - restore playback (if needed and if possible)
+
+        This default implementation will only be used if the player
+        (provider) has no native support for the PLAY_ANNOUNCEMENT feature.
+        """
+        prev_power = player.powered
+        prev_state = player.playback_state
+        prev_synced_to = player.synced_to
+        prev_group = self.get(player.active_group) if player.active_group else None
+        prev_source = player.active_source
+        prev_queue = self.get_active_queue(player)
+        prev_media = player.current_media
+        prev_media_name = prev_media.title or prev_media.uri if prev_media else None
+        if prev_synced_to:
+            # ungroup player if its currently synced
+            self.logger.debug(
+                "Announcement to player %s - ungrouping player from %s...",
+                player.display_name,
+                prev_synced_to,
+            )
+            await self.cmd_ungroup(player.player_id)
+        elif prev_group:
+            # if the player is part of a group player, we need to ungroup it
+            if PlayerFeature.SET_MEMBERS in prev_group.supported_features:
+                self.logger.debug(
+                    "Announcement to player %s - ungrouping from group player %s...",
+                    player.display_name,
+                    prev_group.display_name,
+                )
+                await prev_group.set_members(player_ids_to_remove=[player.player_id])
+            else:
+                # if the player is part of a group player that does not support ungrouping,
+                # we need to power off the groupplayer instead
+                self.logger.debug(
+                    "Announcement to player %s - turning off group player %s...",
+                    player.display_name,
+                    prev_group.display_name,
+                )
+                await self.cmd_power(player.player_id, False)
+        elif prev_state in (PlaybackState.PLAYING, PlaybackState.PAUSED):
+            # normal/standalone player: stop player if its currently playing
+            self.logger.debug(
+                "Announcement to player %s - stop existing content (%s)...",
+                player.display_name,
+                prev_media_name,
+            )
+            await self.cmd_stop(player.player_id)
+            # wait for the player to stop
+            await self.wait_for_state(player, PlaybackState.IDLE, 10, 0.4)
+        # adjust volume if needed
+        # in case of a (sync) group, we need to do this for all child players
+        prev_volumes: dict[str, int] = {}
+        async with TaskManager(self.mass) as tg:
+            for volume_player_id in player.group_members or (player.player_id,):
+                if not (volume_player := self.get(volume_player_id)):
+                    continue
+                # catch any players that have a different source active
+                if (
+                    volume_player.active_source
+                    not in (
+                        player.active_source,
+                        volume_player.player_id,
+                        None,
+                    )
+                    and volume_player.playback_state == PlaybackState.PLAYING
+                ):
+                    self.logger.warning(
+                        "Detected announcement to playergroup %s while group member %s is playing "
+                        "other content, this may lead to unexpected behavior.",
+                        player.display_name,
+                        volume_player.display_name,
+                    )
+                    tg.create_task(self.cmd_stop(volume_player.player_id))
+                if volume_player.volume_control == PLAYER_CONTROL_NONE:
+                    continue
+                if (prev_volume := volume_player.volume_level) is None:
+                    continue
+                announcement_volume = self.get_announcement_volume(volume_player_id, volume_level)
+                if announcement_volume is None:
+                    continue
+                temp_volume = announcement_volume or player.volume_level
+                if temp_volume != prev_volume:
+                    prev_volumes[volume_player_id] = prev_volume
+                    self.logger.debug(
+                        "Announcement to player %s - setting temporary volume (%s)...",
+                        volume_player.display_name,
+                        announcement_volume,
+                    )
+                    tg.create_task(
+                        self.cmd_volume_set(volume_player.player_id, announcement_volume)
+                    )
+        # play the announcement
+        self.logger.debug(
+            "Announcement to player %s - playing the announcement on the player...",
+            player.display_name,
+        )
+        await self.play_media(player_id=player.player_id, media=announcement)
+        # wait for the player(s) to play
+        await self.wait_for_state(player, PlaybackState.PLAYING, 10, minimal_time=0.1)
+        # wait for the player to stop playing
+        if not announcement.duration:
+            media_info = await async_parse_tags(
+                announcement.custom_data["url"], require_duration=True
+            )
+            announcement.duration = media_info.duration
+        await self.wait_for_state(
+            player,
+            PlaybackState.IDLE,
+            timeout=announcement.duration + 6,
+            minimal_time=announcement.duration,
+        )
+        self.logger.debug(
+            "Announcement to player %s - restore previous state...", player.display_name
+        )
+        # restore volume
+        async with TaskManager(self.mass) as tg:
+            for volume_player_id, prev_volume in prev_volumes.items():
+                tg.create_task(self.cmd_volume_set(volume_player_id, prev_volume))
+        await asyncio.sleep(0.2)
+        player.current_media = prev_media
+        player.active_source = prev_source
+        # either power off the player or resume playing
+        if not prev_power and player.power_control != PLAYER_CONTROL_NONE:
+            await self.cmd_power(player.player_id, False)
+            return
+        elif prev_synced_to:
+            await self.cmd_group(player.player_id, prev_synced_to)
+        elif prev_group:
+            if PlayerFeature.SET_MEMBERS in prev_group.supported_features:
+                self.logger.debug(
+                    "Announcement to player %s - grouping back to group player %s...",
+                    player.display_name,
+                    prev_group.display_name,
+                )
+                await prev_group.set_members(player_ids_to_add=[player.player_id])
+            elif prev_state == PlaybackState.PLAYING:
+                # if the player is part of a group player that does not support set_members,
+                # we need to restart the groupplayer
+                self.logger.debug(
+                    "Announcement to player %s - restarting playback on group player %s...",
+                    player.display_name,
+                    prev_group.display_name,
+                )
+                await self.cmd_play(prev_group.player_id)
+        elif prev_queue and prev_state == PlaybackState.PLAYING:
+            await self.mass.player_queues.resume(prev_queue.queue_id, True)
+            await self.wait_for_state(player, PlaybackState.PLAYING, 5)
+        elif prev_state == PlaybackState.PLAYING:
+            # player was playing something else - try to resume that here
+            for source in player.source_list_state:
+                if source.id == prev_source and not source.passive:
+                    await player.select_source(source.id)
+                    break
+            else:
+                # no source found, try to resume the previous media
+                await self.cmd_play(player.player_id)
+
+    async def _poll_players(self) -> None:
+        """Background task that polls players for updates."""
+        while True:
+            for player in list(self._players.values()):
+                # if the player is playing, update elapsed time every tick
+                # to ensure the queue has accurate details
+                player_playing = player.playback_state == PlaybackState.PLAYING
+                if player_playing:
+                    self.mass.loop.call_soon(
+                        self.mass.player_queues.on_player_update,
+                        player,
+                        {"corrected_elapsed_time": player.corrected_elapsed_time},
+                    )
+                # Poll player;
+                if not player.needs_poll:
+                    continue
+                try:
+                    last_poll: float = player.extra_data[ATTR_LAST_POLL]
+                except KeyError:
+                    last_poll = 0.0
+                if (self.mass.loop.time() - last_poll) < player.poll_interval:
+                    continue
+                player.extra_data[ATTR_LAST_POLL] = self.mass.loop.time()
+                try:
+                    await player.poll()
+                except Exception as err:
+                    self.logger.warning(
+                        "Error while requesting latest state from player %s: %s",
+                        player.display_name,
+                        str(err),
+                        exc_info=err if self.logger.isEnabledFor(10) else None,
+                    )
+            await asyncio.sleep(1)
+
+    async def _handle_select_plugin_source(
+        self, player: Player, plugin_prov: PluginProvider
+    ) -> None:
+        """Handle playback/select of given plugin source on player."""
+        plugin_source = plugin_prov.get_source()
+        stream_url = await self.mass.streams.get_plugin_source_url(
+            plugin_source.id, player.player_id
+        )
+        await self.play_media(
+            player_id=player.player_id,
+            media=PlayerMedia(
+                uri=stream_url,
+                media_type=MediaType.PLUGIN_SOURCE,
+                title=plugin_source.name,
+                custom_data={
+                    "provider": plugin_prov.instance_id,
+                    "source_id": plugin_source.id,
+                    "player_id": player.player_id,
+                    "audio_format": plugin_source.audio_format,
+                },
+            ),
+        )
+        # trigger player update to ensure the source is set
+        self.trigger_player_update(player.player_id)
+
+    def _handle_group_dsp_change(
+        self, player: Player, prev_group_members: list[str], new_group_members: list[str]
+    ) -> None:
+        """Handle DSP reload when group membership changes."""
+        prev_child_count = len(prev_group_members)
+        new_child_count = len(new_group_members)
+        is_player_group = player.type == PlayerType.GROUP
+
+        # handle special case for PlayerGroups: since there are no leaders,
+        # DSP still always work with a single player in the group.
+        multi_device_dsp_threshold = 1 if is_player_group else 0
+
+        prev_is_multiple_devices = prev_child_count > multi_device_dsp_threshold
+        new_is_multiple_devices = new_child_count > multi_device_dsp_threshold
+
+        if prev_is_multiple_devices == new_is_multiple_devices:
+            return  # no change in multi-device status
+
+        supports_multi_device_dsp = PlayerFeature.MULTI_DEVICE_DSP in player.supported_features
+
+        dsp_enabled: bool
+        if player.type == PlayerType.GROUP:
+            # Since player groups do not have leaders, we will use the only child
+            # that was in the group before and after the change
+            if prev_is_multiple_devices:
+                if childs := new_group_members:
+                    # We shrank the group from multiple players to a single player
+                    # So the now only child will control the DSP
+                    dsp_enabled = self.mass.config.get_player_dsp_config(childs[0]).enabled
+                else:
+                    dsp_enabled = False
+            elif childs := prev_group_members:
+                # We grew the group from a single player to multiple players,
+                # let's see if the previous single player had DSP enabled
+                dsp_enabled = self.mass.config.get_player_dsp_config(childs[0]).enabled
+            else:
+                dsp_enabled = False
+        else:
+            dsp_enabled = self.mass.config.get_player_dsp_config(player.player_id).enabled
+
+        if dsp_enabled and not supports_multi_device_dsp:
+            # We now know that the group configuration has changed so:
+            # - multi-device DSP is not supported
+            # - we switched from a group with multiple players to a single player
+            #   (or vice versa)
+            # - the leader has DSP enabled
+            self.mass.create_task(self.mass.players.on_player_dsp_change(player.player_id))
+
+    def __iter__(self) -> Iterator[Player]:
+        """Iterate over all players."""
+        return iter(self._players.values())
diff --git a/music_assistant/controllers/players/sync_groups.py b/music_assistant/controllers/players/sync_groups.py
new file mode 100644 (file)
index 0000000..0d95ca9
--- /dev/null
@@ -0,0 +1,590 @@
+"""
+Controller for (provider specific) SyncGroup players.
+
+A SyncGroup player is a virtual player that automatically groups multiple players
+together in a sync group, where one player is the sync leader
+and the other players are synced to that leader.
+"""
+
+from __future__ import annotations
+
+import asyncio
+from copy import deepcopy
+from typing import TYPE_CHECKING, cast
+
+import shortuuid
+from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption
+from music_assistant_models.constants import PLAYER_CONTROL_NONE
+from music_assistant_models.enums import (
+    ConfigEntryType,
+    PlaybackState,
+    PlayerFeature,
+    PlayerType,
+    ProviderFeature,
+)
+from music_assistant_models.errors import UnsupportedFeaturedException
+from music_assistant_models.player import DeviceInfo, PlayerMedia, PlayerSource
+from propcache import under_cached_property as cached_property
+
+from music_assistant.constants import (
+    CONF_CROSSFADE_DURATION,
+    CONF_DYNAMIC_GROUP_MEMBERS,
+    CONF_ENABLE_ICY_METADATA,
+    CONF_FLOW_MODE,
+    CONF_GROUP_MEMBERS,
+    CONF_HTTP_PROFILE,
+    CONF_OUTPUT_CODEC,
+    CONF_SAMPLE_RATES,
+    CONF_SMART_FADES_MODE,
+    SYNCGROUP_PREFIX,
+)
+from music_assistant.models.player import GroupPlayer, Player
+
+if TYPE_CHECKING:
+    from music_assistant.models.player_provider import PlayerProvider
+
+    from .player_controller import PlayerController
+
+
+SUPPORT_DYNAMIC_LEADER = {
+    # providers that support dynamic leader selection in a syncgroup
+    # meaning that if you would remove the current leader from the group,
+    # the provider will automatically select a new leader from the remaining members
+    # and the music keeps playing uninterrupted.
+    "airplay",
+    "squeezelite",
+    "resonate",
+    # TODO: Get this working with Sonos as well (need to handle range requests)
+}
+
+OPTIONAL_FEATURES = {
+    PlayerFeature.ENQUEUE,
+    PlayerFeature.GAPLESS_PLAYBACK,
+    PlayerFeature.GAPLESS_DIFFERENT_SAMPLERATE,
+    PlayerFeature.NEXT_PREVIOUS,
+    PlayerFeature.PAUSE,
+    PlayerFeature.PLAY_ANNOUNCEMENT,
+    PlayerFeature.SEEK,
+    PlayerFeature.SELECT_SOURCE,
+    PlayerFeature.VOLUME_MUTE,
+}
+
+
+class SyncGroupPlayer(GroupPlayer):
+    """Helper class for a (provider specific) SyncGroup player."""
+
+    _attr_type: PlayerType = PlayerType.GROUP
+    sync_leader: Player | None = None
+    """The active sync leader player for this syncgroup."""
+
+    @cached_property
+    def is_dynamic(self) -> bool:
+        """Return if the player is a dynamic group player."""
+        return bool(self.config.get_value(CONF_DYNAMIC_GROUP_MEMBERS, False))
+
+    def __init__(
+        self,
+        provider: PlayerProvider,
+        player_id: str,
+    ) -> None:
+        """Initialize GroupPlayer instance."""
+        super().__init__(provider, player_id)
+        self._attr_name = self.config.name or f"SyncGroup {player_id}"
+        self._attr_available = True
+        self._attr_powered = False  # group players are always powered off by default
+        self._attr_active_source = None
+        self._attr_device_info = DeviceInfo(model="Sync Group", manufacturer=provider.name)
+        self._attr_supported_features = {
+            PlayerFeature.POWER,
+            PlayerFeature.VOLUME_SET,
+        }
+
+    async def on_config_updated(self) -> None:
+        """Handle logic when the player is loaded or updated."""
+        # Config is only available after the player was registered
+        static_members = cast("list[str]", self.config.get_value(CONF_GROUP_MEMBERS, []))
+        self._attr_static_group_members = static_members.copy()
+        if not self.powered:
+            self._attr_group_members = static_members.copy()
+        if self.is_dynamic:
+            self._attr_supported_features.add(PlayerFeature.SET_MEMBERS)
+        else:
+            self._attr_supported_features.discard(PlayerFeature.SET_MEMBERS)
+
+    @property
+    def supported_features(self) -> set[PlayerFeature]:
+        """Return the supported features of the player."""
+        if self.sync_leader:
+            base_features = self._attr_supported_features.copy()
+            # add features supported by the sync leader
+            for feature in OPTIONAL_FEATURES:
+                if feature in self.sync_leader.supported_features:
+                    base_features.add(feature)
+            return base_features
+        return self._attr_supported_features
+
+    @property
+    def playback_state(self) -> PlaybackState:
+        """Return the current playback state of the player."""
+        if self.power_state:
+            return self.sync_leader.playback_state if self.sync_leader else PlaybackState.IDLE
+        else:
+            return PlaybackState.IDLE
+
+    @cached_property
+    def flow_mode(self) -> bool:
+        """
+        Return if the player needs flow mode.
+
+        Will by default be set to True if the player does not support PlayerFeature.ENQUEUE
+        or has a flow mode config entry set to True.
+        """
+        if leader := self.sync_leader:
+            return leader.flow_mode
+        return False
+
+    @property
+    def elapsed_time(self) -> float | None:
+        """Return the elapsed time in (fractional) seconds of the current track (if any)."""
+        return self.sync_leader.elapsed_time if self.sync_leader else None
+
+    @property
+    def elapsed_time_last_updated(self) -> float | None:
+        """Return when the elapsed time was last updated."""
+        return self.sync_leader.elapsed_time_last_updated if self.sync_leader else None
+
+    @property
+    def current_media(self) -> PlayerMedia | None:
+        """Return the current media item (if any) loaded in the player."""
+        return self.sync_leader.current_media if self.sync_leader else self._attr_current_media
+
+    @property
+    def active_source(self) -> str | None:
+        """Return the active source id (if any) of the player."""
+        return self._attr_active_source
+
+    @property
+    def source_list(self) -> list[PlayerSource]:
+        """Return list of available (native) sources for this player."""
+        if self.sync_leader:
+            return self.sync_leader.source_list
+        return []
+
+    @property
+    def can_group_with(self) -> set[str]:
+        """
+        Return the id's of players this player can group with.
+
+        This should return set of player_id's this player can group/sync with
+        or just the provider's instance_id if all players can group with each other.
+        """
+        if self.is_dynamic and (leader := self.sync_leader):
+            return leader.can_group_with
+        elif self.is_dynamic:
+            return {self.provider.lookup_key}
+        else:
+            return set()
+
+    async def get_config_entries(self) -> list[ConfigEntry]:
+        """Return all (provider/player specific) Config Entries for the given player (if any)."""
+        entries: list[ConfigEntry] = [
+            # default entries for player groups
+            *await super().get_config_entries(),
+            # add syncgroup specific entries
+            ConfigEntry(
+                key=CONF_GROUP_MEMBERS,
+                type=ConfigEntryType.STRING,
+                multi_value=True,
+                label="Group members",
+                default_value=[],
+                description="Select all players you want to be part of this group",
+                required=False,  # needed for dynamic members (which allows empty members list)
+                options=[
+                    ConfigValueOption(x.display_name, x.player_id)
+                    for x in self.provider.players
+                    if x.type != PlayerType.GROUP
+                ],
+            ),
+            ConfigEntry(
+                key="dynamic_members",
+                type=ConfigEntryType.BOOLEAN,
+                label="Enable dynamic members",
+                description="Allow (un)joining members dynamically, so the group more or less "
+                "behaves the same like manually syncing players together, "
+                "with the main difference being that the group player will hold the queue.",
+                default_value=False,
+                required=False,
+            ),
+        ]
+        # combine base group entries with (base) player entries for this player type
+        child_player = next((x for x in self.provider.players if x.type == PlayerType.PLAYER), None)
+        if child_player:
+            allowed_conf_entries = (
+                CONF_HTTP_PROFILE,
+                CONF_ENABLE_ICY_METADATA,
+                CONF_CROSSFADE_DURATION,
+                CONF_OUTPUT_CODEC,
+                CONF_FLOW_MODE,
+                CONF_SAMPLE_RATES,
+                CONF_SMART_FADES_MODE,
+            )
+            child_config_entries = await child_player.get_config_entries()
+            entries.extend(
+                [entry for entry in child_config_entries if entry.key in allowed_conf_entries]
+            )
+        return entries
+
+    async def stop(self) -> None:
+        """Send STOP command to given player."""
+        if sync_leader := self.sync_leader:
+            await sync_leader.stop()
+
+    async def play(self) -> None:
+        """Send PLAY command to given player."""
+        if sync_leader := self.sync_leader:
+            await sync_leader.play()
+
+    async def pause(self) -> None:
+        """Send PAUSE command to given player."""
+        if sync_leader := self.sync_leader:
+            await sync_leader.pause()
+
+    async def power(self, powered: bool) -> None:
+        """Handle POWER command to group player."""
+        prev_power = self._attr_powered
+        if powered == prev_power:
+            # no change
+            return
+
+        # always stop at power off
+        if not powered and self.playback_state in (PlaybackState.PLAYING, PlaybackState.PAUSED):
+            await self.stop()
+
+        # optimistically set the group state
+
+        self._attr_powered = powered
+        self.update_state()
+
+        if not prev_power and powered:
+            # ensure static members are present when powering on
+            for static_group_member in self._attr_static_group_members:
+                member_player = self.mass.players.get(static_group_member)
+                if not member_player or not member_player.available or not member_player.enabled:
+                    if static_group_member in self._attr_group_members:
+                        self._attr_group_members.remove(static_group_member)
+                    continue
+                if static_group_member not in self._attr_group_members:
+                    self._attr_group_members.append(static_group_member)
+            # Select sync leader and handle turn on
+            new_leader = self._select_sync_leader()
+            # handle TURN_ON of the group player by turning on all members
+            for member in self.mass.players.iter_group_members(
+                self, only_powered=False, active_only=False
+            ):
+                await self._handle_member_collisions(member)
+                if not member.powered and member.power_control != PLAYER_CONTROL_NONE:
+                    await member.power(True)
+            # Set up the sync group with the new leader
+            await self._handle_leader_transition(new_leader)
+        elif prev_power and not powered:
+            # handle TURN_OFF of the group player by dissolving group and turning off all members
+            await self._dissolve_syncgroup()
+            # turn off all group members
+            for member in self.mass.players.iter_group_members(
+                self, only_powered=True, active_only=True
+            ):
+                if member.powered and member.power_control != PLAYER_CONTROL_NONE:
+                    await member.power(False)
+
+        if not powered:
+            # Reset to unfiltered static members list when powered off
+            # (the frontend will hide unavailable members)
+            self._attr_group_members = self._attr_static_group_members.copy()
+            self._attr_active_source = None
+            # and clear the sync leader
+            self.sync_leader = None
+        self.update_state()
+
+    async def volume_set(self, volume_level: int) -> None:
+        """Send VOLUME_SET command to given player."""
+        # group volume is already handled in the player manager
+
+    async def play_media(self, media: PlayerMedia) -> None:
+        """Handle PLAY MEDIA on given player."""
+        # power on (which will also resync if needed)
+        await self.power(True)
+        # simply forward the command to the sync leader
+        if sync_leader := self.sync_leader:
+            await sync_leader.play_media(media)
+            self._attr_current_media = deepcopy(media)
+            self._attr_active_source = media.source_id
+            self.update_state()
+        else:
+            raise RuntimeError("an empty group cannot play media, consider adding members first")
+
+    async def enqueue_next_media(self, media: PlayerMedia) -> None:
+        """Handle enqueuing of a next media item on the player."""
+        if sync_leader := self.sync_leader:
+            await sync_leader.enqueue_next_media(media)
+
+    async def set_members(
+        self,
+        player_ids_to_add: list[str] | None = None,
+        player_ids_to_remove: list[str] | None = None,
+    ) -> None:
+        """Handle SET_MEMBERS command on the player."""
+        if not self.is_dynamic:
+            raise UnsupportedFeaturedException(
+                f"Group {self.display_name} does not allow dynamically adding/removing members!"
+            )
+        # handle additions
+        final_players_to_add: list[str] = []
+        for player_id in player_ids_to_add or []:
+            if player_id in self._attr_group_members:
+                continue
+            if player_id == self.player_id:
+                raise UnsupportedFeaturedException(
+                    f"Cannot add {self.display_name} to itself as a member!"
+                )
+            self._attr_group_members.append(player_id)
+            final_players_to_add.append(player_id)
+        # handle removals
+        final_players_to_remove: list[str] = []
+        for player_id in player_ids_to_remove or []:
+            if player_id not in self._attr_group_members:
+                continue
+            if player_id == self.player_id:
+                raise UnsupportedFeaturedException(
+                    f"Cannot remove {self.display_name} from itself as a member!"
+                )
+            self._attr_group_members.remove(player_id)
+            final_players_to_remove.append(player_id)
+        self.update_state()
+        if not self.powered:
+            # Don't need to do anything else if the group is powered off
+            # The syncing will be done once powered on
+            return
+        next_leader = self._select_sync_leader()
+        prev_leader = self.sync_leader
+
+        if prev_leader and next_leader is None:
+            # Edge case: we no longer have any members in the group (and thus no leader)
+            await self._handle_leader_transition(None)
+        elif prev_leader != next_leader:
+            # Edge case: we had changed the leader (or just got one)
+            await self._handle_leader_transition(next_leader)
+        elif self.sync_leader and (player_ids_to_add or player_ids_to_remove):
+            # if the group still has the same leader, we need to (re)sync the members
+            # Handle collisions for newly added players
+            for player_id in final_players_to_add:
+                if player := self.mass.players.get(player_id):
+                    await self._handle_member_collisions(player)
+
+            await self.sync_leader.set_members(
+                player_ids_to_add=final_players_to_add,
+                player_ids_to_remove=final_players_to_remove,
+            )
+
+    async def _form_syncgroup(self) -> None:
+        """Form syncgroup by syncing all (possible) members."""
+        if self.sync_leader is None:
+            # This is an empty group, leader will be selected once a member is added
+            self._attr_group_members = []
+            self.update_state()
+            return
+        # ensure the sync leader is first in the list
+        self._attr_group_members = [
+            self.sync_leader.player_id,
+            *[x for x in self._attr_group_members if x != self.sync_leader.player_id],
+        ]
+        self.update_state()
+        members_to_sync: list[str] = []
+        for member in self.mass.players.iter_group_members(self, active_only=False):
+            # Handle collisions before attempting to sync
+            await self._handle_member_collisions(member)
+
+            if member.synced_to and member.synced_to != self.sync_leader.player_id:
+                # ungroup first
+                await member.ungroup()
+            if member.player_id == self.sync_leader.player_id:
+                # skip sync leader
+                continue
+            if (
+                member.synced_to == self.sync_leader.player_id
+                and member.player_id in self.sync_leader.group_members
+            ):
+                # already synced
+                continue
+            members_to_sync.append(member.player_id)
+        if members_to_sync:
+            await self.sync_leader.set_members(members_to_sync)
+
+    async def _dissolve_syncgroup(self) -> None:
+        """Dissolve the current syncgroup by ungrouping all members and restoring leader queue."""
+        if sync_leader := self.sync_leader:
+            # dissolve the temporary syncgroup from the sync leader
+            sync_children = [x for x in sync_leader.group_members if x != sync_leader.player_id]
+            if sync_children:
+                await sync_leader.set_members(player_ids_to_remove=sync_children)
+            # Reset the leaders queue since it is no longer part of this group
+            sync_leader.update_state()
+
+    async def _handle_leader_transition(self, new_leader: Player | None) -> None:
+        """Handle transition from current leader to new leader."""
+        prev_leader = self.sync_leader
+        was_playing = False
+
+        if (
+            prev_leader
+            and new_leader
+            and prev_leader != new_leader
+            and self.provider.domain in SUPPORT_DYNAMIC_LEADER
+        ):
+            # provider supports dynamic leader selection, so just remove/add members
+            await prev_leader.ungroup()
+            self.sync_leader = new_leader
+            # allow some time to propagate the changes before resyncing
+            await asyncio.sleep(2)
+            await self._form_syncgroup()
+            return
+
+        if prev_leader:
+            # Save current media and playback state for potential restart
+            was_playing = self.playback_state == PlaybackState.PLAYING
+            # Stop current playback and dissolve existing group
+            await self.stop()
+            await self._dissolve_syncgroup()
+            # allow some time to propagate the changes before resyncing
+            await asyncio.sleep(2)
+
+        # Set new leader
+        self.sync_leader = new_leader
+
+        if new_leader:
+            # form a syncgroup with the new leader
+            await self._form_syncgroup()
+
+            # Restart playback if requested and we have media to play
+            if was_playing and self.current_media is not None:
+                await new_leader.play_media(self.current_media)
+
+    def _select_sync_leader(self) -> Player | None:
+        """Select the active sync leader player for a syncgroup."""
+        if self.sync_leader and self.sync_leader.player_id in self.group_members:
+            # Don't change the sync leader if we already have one
+            return self.sync_leader
+        for prefer_sync_leader in (True, False):
+            for child_player in self.mass.players.iter_group_members(self):
+                if prefer_sync_leader and child_player.synced_to:
+                    # prefer the first player that already has sync children
+                    continue
+                if child_player.active_group not in (
+                    None,
+                    self.player_id,
+                    child_player.player_id,
+                ):
+                    # this should not happen (because its already handled in the power on logic),
+                    # but guard it just in case bad things happen
+                    continue
+                return child_player
+        return None
+
+    async def _handle_member_collisions(self, member: Player) -> None:
+        """Handle collisions when adding a member to the sync group."""
+        active_groups = member.active_groups
+        for group in active_groups:
+            if group == self.player_id:
+                continue
+            # collision: child player is part another group that is already active !
+            # solve this by trying to leave the group first
+            if other_group := self.mass.players.get(group):
+                if (
+                    other_group.supports_feature(PlayerFeature.SET_MEMBERS)
+                    and member.player_id not in other_group.static_group_members
+                ):
+                    await other_group.set_members(player_ids_to_remove=[member.player_id])
+                else:
+                    # if the other group does not support SET_MEMBERS or it is a static
+                    # member, we need to power it off to leave the group
+                    await other_group.power(False)
+        if (
+            member.synced_to is not None
+            and member.synced_to != self.sync_leader
+            and (synced_to_player := self.mass.players.get(member.synced_to))
+            and member.player_id in synced_to_player.group_members
+        ):
+            # collision: child player is synced to another player and still in that group
+            # ungroup it first
+            await synced_to_player.set_members(player_ids_to_remove=[member.player_id])
+
+
+class SyncGroupController:
+    """Controller managing SyncGroup players."""
+
+    def __init__(self, player_controller: PlayerController) -> None:
+        """Initialize SyncGroupController."""
+        self.player_controller = player_controller
+        self.mass = player_controller.mass
+
+    async def create_group_player(
+        self, provider: PlayerProvider, name: str, members: list[str], dynamic: bool = True
+    ) -> Player:
+        """
+        Create new SyncGroup Player.
+
+        :param provider: The provider to create the group player for
+        :param name: Name of the group player
+        :param members: List of player ids to add to the group
+        :param dynamic: Whether the group is dynamic (members can change)
+        """
+        # default implementation for providers that support syncing players
+        if ProviderFeature.SYNC_PLAYERS not in provider.supported_features:
+            # the frontend should already prevent this, but just in case
+            raise UnsupportedFeaturedException(
+                f"Provider {provider.name} does not support player syncing!"
+            )
+        # Create a new syncgroup player with the given members
+        members = [x for x in members if x in [y.player_id for y in provider.players]]
+        player_id = f"{SYNCGROUP_PREFIX}{shortuuid.random(8).lower()}"
+        self.mass.config.create_default_player_config(
+            player_id=player_id,
+            provider=provider.lookup_key,
+            name=name,
+            enabled=True,
+            values={
+                CONF_GROUP_MEMBERS: members,
+                CONF_DYNAMIC_GROUP_MEMBERS: dynamic,
+            },
+        )
+        return await self._register_syncgroup_player(player_id, provider)
+
+    async def remove_group_player(self, player_id: str) -> None:
+        """
+        Remove a group player.
+
+        :param player_id: ID of the group player to remove.
+        """
+        # we simply permanently unregister the syncgroup player and wipe its config
+        await self.mass.players.unregister(player_id, True)
+
+    async def _register_syncgroup_player(self, player_id: str, provider: PlayerProvider) -> Player:
+        """Register a syncgroup player."""
+        syncgroup = SyncGroupPlayer(provider, player_id)
+        await self.mass.players.register_or_update(syncgroup)
+        return syncgroup
+
+    async def on_provider_loaded(self, provider: PlayerProvider) -> None:
+        """Handle logic when a provider is loaded."""
+        # register existing syncgroup players for this provider
+        for player_conf in await self.mass.config.get_player_configs(provider.lookup_key):
+            if player_conf.player_id.startswith(SYNCGROUP_PREFIX):
+                await self._register_syncgroup_player(player_conf.player_id, provider)
+
+    async def on_provider_unload(self, provider: PlayerProvider) -> None:
+        """Handle logic when a provider is (about to get) unloaded."""
+        # unregister existing syncgroup players for this provider
+        for player in self.mass.players.all(
+            provider_filter=provider.lookup_key, return_sync_groups=True
+        ):
+            if player.player_id.startswith(SYNCGROUP_PREFIX):
+                await self.mass.players.unregister(player.player_id, False)
index f55fb34f9e70ca76caf5f5c7eef4c9a190a92ab6..55ec3da06d104ef1d8ae52ba3c28e595838f68a8 100644 (file)
@@ -14,7 +14,7 @@ import os
 import urllib.parse
 from collections.abc import AsyncGenerator
 from dataclasses import dataclass
-from typing import TYPE_CHECKING, TypedDict
+from typing import TYPE_CHECKING
 
 from aiofiles.os import wrap
 from aiohttp import web
@@ -54,6 +54,7 @@ from music_assistant.constants import (
     SILENCE_FILE,
     VERBOSE_LOG_LEVEL,
 )
+from music_assistant.controllers.players.player_controller import AnnounceData
 from music_assistant.helpers.audio import (
     CACHE_FILES_IN_USE,
     get_chunksize,
@@ -117,14 +118,6 @@ class CrossfadeData:
     session_id: str
 
 
-class AnnounceData(TypedDict):
-    """Announcement data."""
-
-    announcement_url: str
-    pre_announce: bool
-    pre_announce_url: str
-
-
 class StreamsController(CoreController):
     """Webserver Controller to stream audio to players."""
 
@@ -1052,7 +1045,7 @@ class StreamsController(CoreController):
             if plugin_source.stream_type == StreamType.CUSTOM
             else plugin_source.path
         )
-        player.active_source = plugin_source_id
+        player.state.active_source = plugin_source_id
         plugin_source.in_use_by = player_id
         try:
             async for chunk in get_ffmpeg_stream(
@@ -1069,7 +1062,7 @@ class StreamsController(CoreController):
                 "Finished streaming PluginSource %s to %s", plugin_source_id, player_id
             )
             await asyncio.sleep(0.5)
-            player.active_source = player.player_id
+            player.state.active_source = player.player_id
             plugin_source.in_use_by = None
 
     async def get_queue_item_stream(
index bd03bb3958eee94c62ba7643db270eed3778d07a..5b41c5bbb6d5d31a054946fab3e4765fde92d03b 100644 (file)
@@ -44,10 +44,10 @@ from music_assistant.constants import (
     MASS_LOGGER_NAME,
     VERBOSE_LOG_LEVEL,
 )
+from music_assistant.controllers.players.sync_groups import SyncGroupPlayer
 from music_assistant.helpers.json import JSON_DECODE_EXCEPTIONS, json_loads
 from music_assistant.helpers.throttle_retry import BYPASS_THROTTLER
 from music_assistant.helpers.util import clean_stream_title, remove_file
-from music_assistant.models.player import SyncGroupPlayer
 
 from .datetime import utc
 from .dsp import filter_to_ffmpeg_params
index 5678ed03649bba11b0daaa797ae859f89ed6ff49..74dcfb57a67d732e5fa4f80eb0f79218d797e2e9 100644 (file)
@@ -42,7 +42,7 @@ from music_assistant.controllers.config import ConfigController
 from music_assistant.controllers.metadata import MetaDataController
 from music_assistant.controllers.music import MusicController
 from music_assistant.controllers.player_queues import PlayerQueuesController
-from music_assistant.controllers.players import PlayerController
+from music_assistant.controllers.players.player_controller import PlayerController
 from music_assistant.controllers.streams import StreamsController
 from music_assistant.controllers.webserver import WebserverController
 from music_assistant.helpers.aiohttp_client import create_clientsession
@@ -586,11 +586,10 @@ class MusicAssistant:
             if provider.manifest.mdns_discovery:
                 for mdns_type in provider.manifest.mdns_discovery:
                     self._aiobrowser.types.discard(mdns_type)
-            # make sure to stop any running sync tasks first
-            for sync_task in self.music.in_progress_syncs:
-                if sync_task.provider_instance == instance_id:
-                    if sync_task.task:
-                        sync_task.task.cancel()
+            if isinstance(provider, PlayerProvider):
+                await self.players.on_provider_unload(provider)
+            if isinstance(provider, MusicProvider):
+                await self.music.on_provider_unload(provider)
             # check if there are no other providers dependent of this provider
             for dep_prov in self.providers:
                 if dep_prov.manifest.depends_on == provider.domain:
@@ -717,7 +716,9 @@ class MusicAssistant:
         self.signal_event(EventType.PROVIDERS_UPDATED, data=self.get_providers())
         await self._update_available_providers_cache()
         if isinstance(provider, MusicProvider):
-            await self.music.schedule_provider_sync(provider.instance_id)
+            await self.music.on_provider_loaded(provider)
+        if isinstance(provider, PlayerProvider):
+            await self.players.on_provider_loaded(provider)
 
     async def __load_provider_manifests(self) -> None:
         """Preload all available provider manifest files."""
index af671f4e9d227a5ca2a0510207677df008bfa59d..1c5b404a28aca3bedb43515711d643cb69c9dd8a 100644 (file)
@@ -44,9 +44,6 @@ from music_assistant.constants import (
     ATTR_FAKE_MUTE,
     ATTR_FAKE_POWER,
     ATTR_FAKE_VOLUME,
-    CONF_CROSSFADE_DURATION,
-    CONF_DYNAMIC_GROUP_MEMBERS,
-    CONF_ENABLE_ICY_METADATA,
     CONF_ENTRY_ANNOUNCE_VOLUME,
     CONF_ENTRY_ANNOUNCE_VOLUME_MAX,
     CONF_ENTRY_ANNOUNCE_VOLUME_MIN,
@@ -72,15 +69,10 @@ from music_assistant.constants import (
     CONF_ENTRY_VOLUME_NORMALIZATION_TARGET,
     CONF_EXPOSE_PLAYER_TO_HA,
     CONF_FLOW_MODE,
-    CONF_GROUP_MEMBERS,
     CONF_HIDE_PLAYER_IN_UI,
-    CONF_HTTP_PROFILE,
     CONF_MUTE_CONTROL,
-    CONF_OUTPUT_CODEC,
     CONF_POWER_CONTROL,
     CONF_PRE_ANNOUNCE_CHIME_URL,
-    CONF_SAMPLE_RATES,
-    CONF_SMART_FADES_MODE,
     CONF_VOLUME_CONTROL,
 )
 from music_assistant.helpers.util import (
@@ -200,18 +192,6 @@ class Player(ABC):
         """Return if the player is available."""
         return self._attr_available
 
-    @available.setter
-    def available(self, value: bool) -> None:
-        """
-        Set the availability of the player.
-
-        :param value: bool if the player is available or not.
-        """
-        if self._attr_available != value:
-            self._attr_available = value
-            # also update the state
-            self._state.available = value
-
     @property
     def name(self) -> str | None:
         """Return the name of the player."""
@@ -279,16 +259,6 @@ class Player(ABC):
         """Return the elapsed time in (fractional) seconds of the current track (if any)."""
         return self._attr_elapsed_time
 
-    @elapsed_time.setter
-    def elapsed_time(self, value: float | None) -> None:
-        """Set the elapsed time on the player."""
-        if self._attr_elapsed_time != value:
-            self._attr_elapsed_time = value
-            # also update the state
-            self._state.elapsed_time = value
-            # update the last updated time
-            self._attr_elapsed_time_last_updated = time.time()
-
     @property
     def elapsed_time_last_updated(self) -> float | None:
         """
@@ -350,11 +320,6 @@ class Player(ABC):
         """
         return self._attr_active_source
 
-    @active_source.setter
-    def active_source(self, value: str | None) -> None:
-        """Set the active source of the player."""
-        self._attr_active_source = value
-
     @property
     def source_list(self) -> list[PlayerSource]:
         """Return list of available (native) sources for this player."""
@@ -365,11 +330,6 @@ class Player(ABC):
         """Return the current media being played by the player."""
         return self._attr_current_media
 
-    @current_media.setter
-    def current_media(self, value: PlayerMedia | None) -> None:
-        """Set the current media being played by the player."""
-        self._attr_current_media = value
-
     @property
     def needs_poll(self) -> bool:
         """Return if the player needs to be polled for state updates."""
@@ -830,8 +790,7 @@ class Player(ABC):
         """
         # if the player is grouped/synced, use the active source of the group/parent player
         if parent_player_id := (self.synced_to or self.active_group):
-            if parent_player := self.mass.players.get(parent_player_id):
-                return parent_player.active_source_state
+            return parent_player_id
         # in case player's source is None, return the player_id (to indicate MA is active source)
         return self.active_source or self.player_id
 
@@ -1027,7 +986,7 @@ class Player(ABC):
         """
         return bool(self._config.get_value(CONF_EXPOSE_PLAYER_TO_HA))
 
-    @cached_property
+    @property
     @final
     def mass_queue_active(self) -> bool:
         """
@@ -1235,37 +1194,38 @@ class Player(ABC):
         Returns a dict with the state attributes that have changed.
         """
         prev_state = deepcopy(self._state)
-        self._state.name = self.display_name
-        self._state.available = self.available
-        self._state.device_info = self.device_info
-        self._state.supported_features = self.supported_features
-        self._state.playback_state = self.playback_state
-        self._state.elapsed_time = self.elapsed_time
-        self._state.elapsed_time_last_updated = self.elapsed_time_last_updated
-        self._state.powered = self.power_state
-        self._state.volume_level = self.volume_state
-        self._state.volume_muted = self.volume_muted_state
-        self._state.group_members = UniqueList(self.group_members)
-        self._state.static_group_members = UniqueList(self.static_group_members)
-        self._state.can_group_with = self.can_group_with
-        self._state.synced_to = self.synced_to
-        self._state.active_source = self.active_source_state
-        self._state.source_list = self.source_list_state
-        self._state.active_group = self.active_group
-        self._state.current_media = self.current_media
-        self._state.enabled = self.enabled
-        self._state.hide_player_in_ui = self.hide_player_in_ui
-        self._state.expose_to_ha = self.expose_to_ha
-        self._state.icon = self.icon
-        self._state.group_volume = self.group_volume
-        self._state.extra_attributes = self.extra_attributes
-        self._state.power_control = self.power_control
-        self._state.volume_control = self.volume_control
-        self._state.mute_control = self.mute_control
-
-        # correct available state if needed
-        if not self._state.enabled:
-            self._state.available = False
+        self._state = PlayerState(
+            player_id=self.player_id,
+            provider=self.provider_id,
+            type=self.type,
+            available=self.enabled and self.available,
+            device_info=self.device_info,
+            supported_features=self.supported_features,
+            playback_state=self.playback_state,
+            elapsed_time=self.elapsed_time,
+            elapsed_time_last_updated=self.elapsed_time_last_updated,
+            powered=self.powered,
+            volume_level=self.volume_level,
+            volume_muted=self.volume_muted,
+            group_members=UniqueList(self.group_members),
+            static_group_members=UniqueList(self.static_group_members),
+            can_group_with=self.can_group_with,
+            synced_to=self.synced_to,
+            active_source=self.active_source_state,
+            source_list=self.source_list_state,
+            active_group=self.active_group,
+            current_media=self.current_media,
+            name=self.display_name,
+            enabled=self.enabled,
+            hide_player_in_ui=self.hide_player_in_ui,
+            expose_to_ha=self.expose_to_ha,
+            icon=self.icon,
+            group_volume=self.group_volume,
+            extra_attributes=self.extra_attributes,
+            power_control=self.power_control,
+            volume_control=self.volume_control,
+            mute_control=self.mute_control,
+        )
 
         # correct group_members if needed
         if self._state.group_members == [self.player_id]:
@@ -1314,6 +1274,18 @@ class Player(ABC):
         return not self.__eq__(other)
 
 
+__all__ = [
+    # explicitly re-export the models we imported from the models package,
+    # for convenience reasons
+    "EXTRA_ATTRIBUTES_TYPES",
+    "DeviceInfo",
+    "Player",
+    "PlayerMedia",
+    "PlayerSource",
+    "PlayerState",
+]
+
+
 class GroupPlayer(Player):
     """Helper class for a (generic) group player."""
 
@@ -1382,425 +1354,3 @@ class GroupPlayer(Player):
         # This will set the (relative) volume level on all child players.
         # free to override if you want to handle this differently.
         await self.mass.players.set_group_volume(self, volume_level)
-
-
-class SyncGroupPlayer(GroupPlayer):
-    """Helper class for a (provider specific) SyncGroup player."""
-
-    _attr_type: PlayerType = PlayerType.GROUP
-    sync_leader: Player | None = None
-    """The active sync leader player for this syncgroup."""
-
-    @cached_property
-    def is_dynamic(self) -> bool:
-        """Return if the player is a dynamic group player."""
-        return bool(self.config.get_value(CONF_DYNAMIC_GROUP_MEMBERS, False))
-
-    def __init__(
-        self,
-        provider: PlayerProvider,
-        player_id: str,
-    ) -> None:
-        """Initialize GroupPlayer instance."""
-        super().__init__(provider, player_id)
-        self._attr_name = self.config.name or f"SyncGroup {player_id}"
-        self._attr_available = True
-        self._attr_powered = False  # group players are always powered off by default
-        self._attr_active_source = player_id
-        self._attr_device_info = DeviceInfo(model="Sync Group", manufacturer=provider.name)
-        self._attr_supported_features = {
-            PlayerFeature.POWER,
-            PlayerFeature.VOLUME_SET,
-        }
-
-    async def on_config_updated(self) -> None:
-        """Handle logic when the player is loaded or updated."""
-        # Config is only available after the player was registered
-        static_members = cast("list[str]", self.config.get_value(CONF_GROUP_MEMBERS, []))
-        self._attr_static_group_members = static_members.copy()
-        if not self.powered:
-            self._attr_group_members = static_members.copy()
-        if self.is_dynamic:
-            self._attr_supported_features.add(PlayerFeature.SET_MEMBERS)
-        else:
-            self._attr_supported_features.discard(PlayerFeature.SET_MEMBERS)
-
-    @property
-    def supported_features(self) -> set[PlayerFeature]:
-        """Return the supported features of the player."""
-        return self._attr_supported_features
-
-    @property
-    def playback_state(self) -> PlaybackState:
-        """Return the current playback state of the player."""
-        if self.power_state:
-            return self.sync_leader.playback_state if self.sync_leader else PlaybackState.IDLE
-        else:
-            return PlaybackState.IDLE
-
-    @cached_property
-    def flow_mode(self) -> bool:
-        """
-        Return if the player needs flow mode.
-
-        Will by default be set to True if the player does not support PlayerFeature.ENQUEUE
-        or has a flow mode config entry set to True.
-        """
-        if leader := self.sync_leader:
-            return leader.flow_mode
-        return False
-
-    @property
-    def elapsed_time(self) -> float | None:
-        """Return the elapsed time in (fractional) seconds of the current track (if any)."""
-        return self.sync_leader.elapsed_time if self.sync_leader else None
-
-    @elapsed_time.setter
-    def elapsed_time(self, value: float | None) -> None:
-        """Set the elapsed time on the player."""
-        raise NotImplementedError("elapsed_time is read-only on a SyncGroup player")
-
-    @property
-    def elapsed_time_last_updated(self) -> float | None:
-        """Return when the elapsed time was last updated."""
-        return self.sync_leader.elapsed_time_last_updated if self.sync_leader else None
-
-    @property
-    def can_group_with(self) -> set[str]:
-        """
-        Return the id's of players this player can group with.
-
-        This should return set of player_id's this player can group/sync with
-        or just the provider's instance_id if all players can group with each other.
-        """
-        if self.is_dynamic and (leader := self.sync_leader):
-            return leader.can_group_with
-        elif self.is_dynamic:
-            return {self.provider.lookup_key}
-        else:
-            return set()
-
-    async def get_config_entries(self) -> list[ConfigEntry]:
-        """Return all (provider/player specific) Config Entries for the given player (if any)."""
-        entries: list[ConfigEntry] = [
-            # default entries for player groups
-            *await super().get_config_entries(),
-            # add syncgroup specific entries
-            ConfigEntry(
-                key=CONF_GROUP_MEMBERS,
-                type=ConfigEntryType.STRING,
-                multi_value=True,
-                label="Group members",
-                default_value=[],
-                description="Select all players you want to be part of this group",
-                required=False,  # needed for dynamic members (which allows empty members list)
-                options=[
-                    ConfigValueOption(x.display_name, x.player_id)
-                    for x in self.provider.players
-                    if x.type != PlayerType.GROUP
-                ],
-            ),
-            ConfigEntry(
-                key="dynamic_members",
-                type=ConfigEntryType.BOOLEAN,
-                label="Enable dynamic members",
-                description="Allow (un)joining members dynamically, so the group more or less "
-                "behaves the same like manually syncing players together, "
-                "with the main difference being that the group player will hold the queue.",
-                default_value=False,
-                required=False,
-            ),
-        ]
-        # combine base group entries with (base) player entries for this player type
-        child_player = next((x for x in self.provider.players if x.type != PlayerType.GROUP), None)
-        if child_player:
-            allowed_conf_entries = (
-                CONF_HTTP_PROFILE,
-                CONF_ENABLE_ICY_METADATA,
-                CONF_CROSSFADE_DURATION,
-                CONF_OUTPUT_CODEC,
-                CONF_FLOW_MODE,
-                CONF_SAMPLE_RATES,
-                CONF_SMART_FADES_MODE,
-            )
-            child_config_entries = await child_player.get_config_entries()
-            entries.extend(
-                [entry for entry in child_config_entries if entry.key in allowed_conf_entries]
-            )
-        return entries
-
-    async def stop(self) -> None:
-        """Send STOP command to given player."""
-        if sync_leader := self.sync_leader:
-            await sync_leader.stop()
-
-    async def play(self) -> None:
-        """Send PLAY command to given player."""
-        if sync_leader := self.sync_leader:
-            await sync_leader.play()
-
-    async def pause(self) -> None:
-        """Send PAUSE command to given player."""
-        if sync_leader := self.sync_leader:
-            await sync_leader.pause()
-
-    async def _handle_member_collisions(self, member: Player) -> None:
-        """Handle collisions when adding a member to the sync group."""
-        active_groups = member.active_groups
-        for group in active_groups:
-            if group == self.player_id:
-                continue
-            # collision: child player is part another group that is already active !
-            # solve this by trying to leave the group first
-            if other_group := self.mass.players.get(group):
-                if (
-                    other_group.supports_feature(PlayerFeature.SET_MEMBERS)
-                    and member.player_id not in other_group.static_group_members
-                ):
-                    await other_group.set_members(player_ids_to_remove=[member.player_id])
-                else:
-                    # if the other group does not support SET_MEMBERS or it is a static
-                    # member, we need to power it off to leave the group
-                    await other_group.power(False)
-        if (
-            member.synced_to is not None
-            and member.synced_to != self.sync_leader
-            and (synced_to_player := self.mass.players.get(member.synced_to))
-            and member.player_id in synced_to_player.group_members
-        ):
-            # collision: child player is synced to another player and still in that group
-            # ungroup it first
-            await synced_to_player.set_members(player_ids_to_remove=[member.player_id])
-
-    async def power(self, powered: bool) -> None:
-        """Handle POWER command to group player."""
-        # always stop at power off
-        if not powered and self.playback_state in (PlaybackState.PLAYING, PlaybackState.PAUSED):
-            await self.stop()
-
-        # optimistically set the group state
-        prev_power = self._attr_powered
-        self._attr_powered = powered
-        self.update_state()
-
-        if powered:
-            # reset the group members to the available static members when powering on
-            self._attr_group_members = []
-            for static_group_member in self._attr_static_group_members:
-                if (
-                    (member_player := self.mass.players.get(static_group_member))
-                    and member_player.available
-                    and member_player.enabled
-                ):
-                    self._attr_group_members.append(static_group_member)
-            # Select sync leader and handle turn on
-            new_leader = self._select_sync_leader()
-            # handle TURN_ON of the group player by turning on all members
-            for member in self.mass.players.iter_group_members(
-                self, only_powered=False, active_only=False
-            ):
-                await self._handle_member_collisions(member)
-                if not member.powered and member.power_control != PLAYER_CONTROL_NONE:
-                    await member.power(True)
-            # Set up the sync group with the new leader
-            await self._handle_leader_transition(new_leader)
-        elif prev_power:
-            # handle TURN_OFF of the group player by dissolving group and turning off all members
-            await self._dissolve_syncgroup()
-            # turn off all group members
-            for member in self.mass.players.iter_group_members(
-                self, only_powered=True, active_only=True
-            ):
-                if member.powered and member.power_control != PLAYER_CONTROL_NONE:
-                    await member.power(False)
-
-        if not powered:
-            # Reset to unfiltered static members list when powered off
-            # (the frontend will hide unavailable members)
-            self._attr_group_members = self._attr_static_group_members.copy()
-            # and clear the sync leader
-            self.sync_leader = None
-
-    async def _dissolve_syncgroup(self) -> None:
-        """Dissolve the current syncgroup by ungrouping all members and restoring leader queue."""
-        if sync_leader := self.sync_leader:
-            # dissolve the temporary syncgroup from the sync leader
-            sync_children = [x for x in sync_leader.group_members if x != sync_leader.player_id]
-            if sync_children:
-                await sync_leader.set_members(player_ids_to_remove=sync_children)
-            # Reset the leaders queue since it is no longer part of this group
-            sync_leader.active_source = None
-            sync_leader.current_media = None
-            sync_leader.update_state()
-
-    async def _handle_leader_transition(self, new_leader: Player | None) -> None:
-        """Handle transition from current leader to new leader."""
-        prev_leader = self.sync_leader
-        was_playing = False
-
-        if prev_leader:
-            # Save current media and playback state for potential restart
-            was_playing = self.playback_state == PlaybackState.PLAYING
-            # Stop current playback and dissolve existing group
-            await self.stop()
-            await self._dissolve_syncgroup()
-
-        # Set new leader
-        self.sync_leader = new_leader
-
-        if new_leader:
-            # form a syncgroup with the new leader
-            await self._form_syncgroup()
-
-            # Restart playback if requested and we have media to play
-            if was_playing and self.current_media is not None:
-                await new_leader.play_media(self.current_media)
-
-    async def volume_set(self, volume_level: int) -> None:
-        """Send VOLUME_SET command to given player."""
-        # group volume is already handled in the player manager
-
-    async def play_media(self, media: PlayerMedia) -> None:
-        """Handle PLAY MEDIA on given player."""
-        # power on (which will also resync if needed)
-        await self.power(True)
-        # simply forward the command to the sync leader
-        if sync_leader := self.sync_leader:
-            await sync_leader.play_media(media)
-            self._attr_current_media = media
-            self._attr_active_source = media.source_id
-            self.update_state()
-        else:
-            raise RuntimeError("an empty group cannot play media, consider adding members first")
-
-    async def enqueue_next_media(self, media: PlayerMedia) -> None:
-        """Handle enqueuing of a next media item on the player."""
-        if sync_leader := self.sync_leader:
-            await sync_leader.enqueue_next_media(media)
-
-    async def set_members(
-        self,
-        player_ids_to_add: list[str] | None = None,
-        player_ids_to_remove: list[str] | None = None,
-    ) -> None:
-        """Handle SET_MEMBERS command on the player."""
-        if not self.is_dynamic:
-            raise UnsupportedFeaturedException(
-                f"Group {self.display_name} does not allow dynamically adding/removing members!"
-            )
-        # handle additions
-        final_players_to_add: list[str] = []
-        for player_id in player_ids_to_add or []:
-            if player_id in self._attr_group_members:
-                continue
-            if player_id == self.player_id:
-                raise UnsupportedFeaturedException(
-                    f"Cannot add {self.display_name} to itself as a member!"
-                )
-            self._attr_group_members.append(player_id)
-            final_players_to_add.append(player_id)
-        # handle removals
-        final_players_to_remove: list[str] = []
-        for player_id in player_ids_to_remove or []:
-            if player_id not in self._attr_group_members:
-                continue
-            if player_id == self.player_id:
-                raise UnsupportedFeaturedException(
-                    f"Cannot remove {self.display_name} from itself as a member!"
-                )
-            self._attr_group_members.remove(player_id)
-            final_players_to_remove.append(player_id)
-        self.update_state()
-        if not self.powered:
-            # Don't need to do anything else if the group is powered off
-            # The syncing will be done once powered on
-            return
-        next_leader = self._select_sync_leader()
-        prev_leader = self.sync_leader
-
-        if prev_leader and next_leader is None:
-            # Edge case: we no longer have any members in the group (and thus no leader)
-            await self._handle_leader_transition(None)
-        elif prev_leader != next_leader:
-            # Edge case: we had changed the leader (or just got one)
-            await self._handle_leader_transition(next_leader)
-        elif self.sync_leader and (player_ids_to_add or player_ids_to_remove):
-            # if the group still has the same leader, we need to (re)sync the members
-            # Handle collisions for newly added players
-            for player_id in final_players_to_add:
-                if player := self.mass.players.get(player_id):
-                    await self._handle_member_collisions(player)
-
-            await self.sync_leader.set_members(
-                player_ids_to_add=final_players_to_add,
-                player_ids_to_remove=final_players_to_remove,
-            )
-
-    async def _form_syncgroup(self) -> None:
-        """Form syncgroup by syncing all (possible) members."""
-        if self.sync_leader is None:
-            # This is an empty group, leader will be selected once a member is added
-            self._attr_group_members = []
-            self.update_state()
-            return
-        # ensure the sync leader is first in the list
-        self._attr_group_members = [
-            self.sync_leader.player_id,
-            *[x for x in self._attr_group_members if x != self.sync_leader.player_id],
-        ]
-        self.update_state()
-        members_to_sync: list[str] = []
-        for member in self.mass.players.iter_group_members(self, active_only=False):
-            # Handle collisions before attempting to sync
-            await self._handle_member_collisions(member)
-
-            if member.synced_to and member.synced_to != self.sync_leader.player_id:
-                # ungroup first
-                await member.ungroup()
-            if member.player_id == self.sync_leader.player_id:
-                # skip sync leader
-                continue
-            if (
-                member.synced_to == self.sync_leader.player_id
-                and member.player_id in self.sync_leader.group_members
-            ):
-                # already synced
-                continue
-            members_to_sync.append(member.player_id)
-        if members_to_sync:
-            await self.sync_leader.set_members(members_to_sync)
-
-    def _select_sync_leader(self) -> Player | None:
-        """Select the active sync leader player for a syncgroup."""
-        if self.sync_leader and self.sync_leader.player_id in self.group_members:
-            # Don't change the sync leader if we already have one
-            return self.sync_leader
-        for prefer_sync_leader in (True, False):
-            for child_player in self.mass.players.iter_group_members(self):
-                if prefer_sync_leader and child_player.synced_to:
-                    # prefer the first player that already has sync children
-                    continue
-                if child_player.active_group not in (
-                    None,
-                    self.player_id,
-                    child_player.player_id,
-                ):
-                    # this should not happen (because its already handled in the power on logic),
-                    # but guard it just in case bad things happen
-                    continue
-                return child_player
-        return None
-
-
-__all__ = [
-    # explicitly re-export the models we imported from the models package,
-    # for convenience reasons
-    "EXTRA_ATTRIBUTES_TYPES",
-    "DeviceInfo",
-    "GroupPlayer",
-    "Player",
-    "PlayerMedia",
-    "PlayerSource",
-    "PlayerState",
-    "SyncGroupPlayer",
-]
index 0f516676c4091e4d0a334bad5047f960e4d7f41b..5f193278413dea9137f759e1acd73b8bbe0fc161 100644 (file)
@@ -4,18 +4,9 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-import shortuuid
-from music_assistant_models.enums import ProviderFeature
 from zeroconf import ServiceStateChange
 from zeroconf.asyncio import AsyncServiceInfo
 
-from music_assistant.constants import (
-    CONF_DYNAMIC_GROUP_MEMBERS,
-    CONF_GROUP_MEMBERS,
-    SYNCGROUP_PREFIX,
-)
-from music_assistant.models.player import SyncGroupPlayer
-
 from .provider import Provider
 
 if TYPE_CHECKING:
@@ -59,24 +50,6 @@ class PlayerProvider(Provider):
         :param members: List of player ids to add to the group
         :param dynamic: Whether the group is dynamic (members can change)
         """
-        # default implementation for providers that support syncing players
-        if ProviderFeature.SYNC_PLAYERS in self.supported_features:
-            # we simply create a new syncgroup player with the given members
-            # feel free to override or extend this method in your provider
-            members = [x for x in members if x in [y.player_id for y in self.players]]
-            player_id = f"{SYNCGROUP_PREFIX}{shortuuid.random(8).lower()}"
-            self.mass.config.create_default_player_config(
-                player_id=player_id,
-                provider=self.lookup_key,
-                name=name,
-                enabled=True,
-                values={
-                    CONF_GROUP_MEMBERS: members,
-                    CONF_DYNAMIC_GROUP_MEMBERS: dynamic,
-                },
-            )
-            return await self._register_syncgroup_player(player_id)
-        # all other providers should implement this method
         raise NotImplementedError
 
     async def remove_group_player(self, player_id: str) -> None:
@@ -87,14 +60,6 @@ class PlayerProvider(Provider):
 
         :param player_id: ID of the group player to remove.
         """
-        # default implementation for providers that support syncing players
-        if ProviderFeature.SYNC_PLAYERS in self.supported_features and player_id.startswith(
-            SYNCGROUP_PREFIX
-        ):
-            # we simply permanently unregister the syncgroup player and wipe its config
-            await self.mass.players.unregister(player_id, True)
-            return
-        # all other providers should implement this method
         raise NotImplementedError
 
     async def discover_players(self) -> None:
@@ -114,22 +79,8 @@ class PlayerProvider(Provider):
                     await self.on_mdns_service_state_change(
                         mdns_name, ServiceStateChange.Added, info
                     )
-        # discover syncgroup players
-        if (
-            ProviderFeature.SYNC_PLAYERS in self.supported_features
-            and ProviderFeature.CREATE_GROUP_PLAYER in self.supported_features
-        ):
-            for player_conf in await self.mass.config.get_player_configs(self.lookup_key):
-                if player_conf.player_id.startswith(SYNCGROUP_PREFIX):
-                    await self._register_syncgroup_player(player_conf.player_id)
-
-    async def _register_syncgroup_player(self, player_id: str) -> Player:
-        """Register a syncgroup player."""
-        syncgroup = SyncGroupPlayer(self, player_id)
-        await self.mass.players.register_or_update(syncgroup)
-        return syncgroup
 
     @property
     def players(self) -> list[Player]:
         """Return all players belonging to this provider."""
-        return self.mass.players.all(provider_filter=self.lookup_key)
+        return self.mass.players.all(provider_filter=self.lookup_key, return_sync_groups=False)
index 286bf0f5f179546645f3df5f186263aa7f4311a8..1607b7982dd1a75dfb3103859db815e4820f669c 100644 (file)
@@ -53,8 +53,6 @@ SUPPORTED_FEATURES = {
     # that your provider supports or an empty set if none.
     # see the ProviderFeature enum for all available features
     ProviderFeature.SYNC_PLAYERS,
-    ProviderFeature.CREATE_GROUP_PLAYER,
-    ProviderFeature.REMOVE_GROUP_PLAYER,
 }
 
 
index 6d42ffebf1fd04408543eb5667605b43c8eb18f9..2bbd02833f0bdf56a09594552569c9ff1c96a86e 100644 (file)
@@ -20,9 +20,6 @@ if TYPE_CHECKING:
 
 SUPPORTED_FEATURES = {
     ProviderFeature.SYNC_PLAYERS,
-    # support sync groups by reporting create/remove player group support
-    ProviderFeature.CREATE_GROUP_PLAYER,
-    ProviderFeature.REMOVE_GROUP_PLAYER,
 }
 
 
index 737abe8e385ddaee5d0a0a512afb531eec20f737..2dc7892d4e7854f76d4dc1765f554cbdcce6fc69 100644 (file)
@@ -17,8 +17,6 @@ if TYPE_CHECKING:
 
 SUPPORTED_FEATURES = {
     ProviderFeature.SYNC_PLAYERS,
-    ProviderFeature.CREATE_GROUP_PLAYER,
-    ProviderFeature.REMOVE_GROUP_PLAYER,
 }
 
 
index 0ca2b909d37e1bbd5cde1b95a7953b6fe53b4ff5..08bc478fa3ba831ebc95f6cec65eaf0e52176ca5 100644 (file)
@@ -842,4 +842,5 @@ class DeezerProvider(MusicProvider):
             Blowfish.MODE_CBC,
             b"\x00\x01\x02\x03\x04\x05\x06\x07",
         )
-        return cipher.decrypt(chunk)  # type: ignore[no-any-return]
+
+        return cipher.decrypt(chunk)  # type: ignore[no-any-return,unused-ignore]
index eab00b68c8d713c5d293d5406abc2ca783f0a248..5d893e98e9f2a6ba46911d93c326750329333f9b 100644 (file)
@@ -11,9 +11,6 @@ from .provider import MusicCastProvider
 
 SUPPORTED_FEATURES = {
     ProviderFeature.SYNC_PLAYERS,
-    # support sync groups by reporting create/remove player group support
-    ProviderFeature.CREATE_GROUP_PLAYER,
-    ProviderFeature.REMOVE_GROUP_PLAYER,
 }
 
 
diff --git a/music_assistant/providers/podcast-index/__init__.py b/music_assistant/providers/podcast-index/__init__.py
deleted file mode 100644 (file)
index 599d482..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-"""Podcast Index provider for Music Assistant."""
-
-from __future__ import annotations
-
-from typing import TYPE_CHECKING
-
-from music_assistant_models.config_entries import ConfigEntry, ConfigValueType
-from music_assistant_models.enums import ConfigEntryType, ProviderFeature
-
-from .constants import CONF_API_KEY, CONF_API_SECRET, CONF_STORED_PODCASTS
-from .provider import PodcastIndexProvider
-
-if TYPE_CHECKING:
-    from music_assistant_models.config_entries import ProviderConfig
-    from music_assistant_models.provider import ProviderManifest
-
-    from music_assistant.mass import MusicAssistant
-    from music_assistant.models import ProviderInstanceType
-
-SUPPORTED_FEATURES = {
-    ProviderFeature.SEARCH,
-    ProviderFeature.BROWSE,
-}
-
-
-async def setup(
-    mass: MusicAssistant, manifest: ProviderManifest, config: ProviderConfig
-) -> ProviderInstanceType:
-    """Initialize provider(instance) with given configuration."""
-    return PodcastIndexProvider(mass, manifest, config, SUPPORTED_FEATURES)
-
-
-async def get_config_entries(
-    mass: MusicAssistant,
-    instance_id: str | None = None,
-    action: str | None = None,
-    values: dict[str, ConfigValueType] | None = None,
-) -> tuple[ConfigEntry, ...]:
-    """
-    Return Config entries to setup this provider.
-
-    instance_id: id of an existing provider instance (None if new instance setup).
-    action: [optional] action key called from config entries UI.
-    values: the (intermediate) raw values for config entries sent with the action.
-    """
-    # ruff: noqa: ARG001
-    return (
-        ConfigEntry(
-            key=CONF_API_KEY,
-            type=ConfigEntryType.STRING,
-            label="API Key",
-            required=True,
-            description="Your Podcast Index API key. Get your free API credentials at https://api.podcastindex.org/",
-        ),
-        ConfigEntry(
-            key=CONF_API_SECRET,
-            type=ConfigEntryType.SECURE_STRING,
-            label="API Secret",
-            required=True,
-            description="Your Podcast Index API secret",
-        ),
-        ConfigEntry(
-            key=CONF_STORED_PODCASTS,
-            type=ConfigEntryType.STRING,
-            multi_value=True,
-            label="Subscribed Podcasts",
-            default_value=[],
-            required=False,
-            hidden=True,
-        ),
-    )
diff --git a/music_assistant/providers/podcast-index/constants.py b/music_assistant/providers/podcast-index/constants.py
deleted file mode 100644 (file)
index 46eb24d..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Constants for Podcast Index provider."""
-
-# Configuration keys
-CONF_API_KEY = "api_key"
-CONF_API_SECRET = "api_secret"
-CONF_STORED_PODCASTS = "stored_podcasts"
-
-# API settings
-API_BASE_URL = "https://api.podcastindex.org/api/1.0"
-
-# Browse categories
-BROWSE_TRENDING = "trending"
-BROWSE_RECENT = "recent"
-BROWSE_CATEGORIES = "categories"
diff --git a/music_assistant/providers/podcast-index/helpers.py b/music_assistant/providers/podcast-index/helpers.py
deleted file mode 100644 (file)
index 858fa8d..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-"""Helper functions for Podcast Index provider."""
-
-from __future__ import annotations
-
-import hashlib
-import time
-from datetime import UTC, datetime
-from typing import TYPE_CHECKING, Any
-
-import aiohttp
-from music_assistant_models.enums import ContentType, ImageType, MediaType
-from music_assistant_models.errors import (
-    InvalidDataError,
-    LoginFailed,
-    ProviderUnavailableError,
-)
-from music_assistant_models.media_items import (
-    AudioFormat,
-    ItemMapping,
-    MediaItemImage,
-    Podcast,
-    PodcastEpisode,
-    ProviderMapping,
-    UniqueList,
-)
-
-from .constants import API_BASE_URL
-
-if TYPE_CHECKING:
-    from music_assistant.mass import MusicAssistant
-
-
-async def make_api_request(
-    mass: MusicAssistant,
-    api_key: str,
-    api_secret: str,
-    endpoint: str,
-    params: dict[str, Any] | None = None,
-) -> dict[str, Any]:
-    """
-    Make authenticated request to Podcast Index API.
-
-    Handles authentication using SHA1 hash of API key, secret, and timestamp.
-    Maps HTTP errors appropriately: 401 -> LoginFailed, others -> ProviderUnavailableError.
-    """
-    # Prepare authentication headers
-    auth_date = str(int(time.time()))
-    auth_string = api_key + api_secret + auth_date
-    auth_hash = hashlib.sha1(auth_string.encode()).hexdigest()
-
-    headers = {
-        "X-Auth-Key": api_key,
-        "X-Auth-Date": auth_date,
-        "Authorization": auth_hash,
-    }
-
-    url = f"{API_BASE_URL}/{endpoint}"
-
-    try:
-        async with mass.http_session.get(url, headers=headers, params=params or {}) as response:
-            response.raise_for_status()
-
-            try:
-                data: dict[str, Any] = await response.json()
-            except aiohttp.ContentTypeError as err:
-                raise InvalidDataError("Invalid JSON response from API") from err
-
-            if str(data.get("status")).lower() != "true":
-                raise InvalidDataError(data.get("description") or "API error")
-
-            return data
-
-    except aiohttp.ClientConnectorError as err:
-        raise ProviderUnavailableError(f"Failed to connect to Podcast Index API: {err}") from err
-    except aiohttp.ServerTimeoutError as err:
-        raise ProviderUnavailableError(f"Podcast Index API timeout: {err}") from err
-    except aiohttp.ClientResponseError as err:
-        if err.status == 401:
-            raise LoginFailed(f"Authentication failed: {err.status}") from err
-        raise ProviderUnavailableError(f"API request failed: {err.status}") from err
-
-
-def parse_podcast_from_feed(
-    feed_data: dict[str, Any], lookup_key: str, domain: str, instance_id: str
-) -> Podcast | None:
-    """Parse podcast from API feed data."""
-    feed_url = feed_data.get("url")
-    podcast_id = feed_data.get("id")
-
-    if not feed_url or not podcast_id:
-        return None
-
-    podcast = Podcast(
-        item_id=str(podcast_id),
-        name=feed_data.get("title", "Unknown Podcast"),
-        publisher=feed_data.get("author") or feed_data.get("ownerName", "Unknown"),
-        provider=lookup_key,
-        provider_mappings={
-            ProviderMapping(
-                item_id=str(podcast_id),
-                provider_domain=domain,
-                provider_instance=instance_id,
-                url=feed_url,
-            )
-        },
-    )
-
-    # Add metadata
-    podcast.metadata.description = feed_data.get("description", "")
-    podcast.metadata.explicit = bool(feed_data.get("explicit", False))
-
-    # Set episode count only if provided
-    episode_count = feed_data.get("episodeCount")
-    if episode_count is not None:
-        podcast.total_episodes = int(episode_count) or 0
-
-    # Add image - prefer 'image' field, fallback to 'artwork'
-    image_url = feed_data.get("image") or feed_data.get("artwork")
-    if image_url:
-        podcast.metadata.add_image(
-            MediaItemImage(
-                type=ImageType.THUMB,
-                path=image_url,
-                provider=lookup_key,
-                remotely_accessible=True,
-            )
-        )
-
-    # Add categories as genres - categories is a dict {id: name}
-    categories = feed_data.get("categories", {})
-    if categories and isinstance(categories, dict):
-        podcast.metadata.genres = set(categories.values())
-
-    # Add language
-    language = feed_data.get("language", "")
-    if language:
-        podcast.metadata.languages = UniqueList([language])
-
-    return podcast
-
-
-def parse_episode_from_data(
-    episode_data: dict[str, Any],
-    podcast_id: str,
-    episode_idx: int,
-    lookup_key: str,
-    domain: str,
-    instance_id: str,
-    podcast_name: str | None = None,
-) -> PodcastEpisode | None:
-    """Parse episode from API episode data."""
-    episode_api_id = episode_data.get("id")
-    if not episode_api_id:
-        return None
-
-    episode_id = f"{podcast_id}|{episode_api_id}"
-
-    position = episode_data.get("episode")
-    if position is None:
-        position = episode_idx + 1
-
-    if podcast_name is None:
-        podcast_name = episode_data.get("feedTitle") or "Unknown Podcast"
-
-    raw_duration = episode_data.get("duration")
-    try:
-        duration = int(raw_duration) if raw_duration is not None else 0
-    except (ValueError, TypeError):
-        duration = 0
-
-    episode = PodcastEpisode(
-        item_id=episode_id,
-        provider=lookup_key,
-        name=episode_data.get("title", "Unknown Episode"),
-        duration=duration,
-        position=position,
-        podcast=ItemMapping(
-            item_id=podcast_id,
-            provider=lookup_key,
-            name=podcast_name,
-            media_type=MediaType.PODCAST,
-        ),
-        provider_mappings={
-            ProviderMapping(
-                item_id=episode_id,
-                provider_domain=domain,
-                provider_instance=instance_id,
-                available=True,
-                audio_format=AudioFormat(
-                    content_type=ContentType.try_parse(
-                        episode_data.get("enclosureType") or "audio/mpeg"
-                    ),
-                ),
-                url=episode_data.get("enclosureUrl"),
-            )
-        },
-    )
-
-    # Add metadata
-    episode.metadata.description = episode_data.get("description", "")
-    episode.metadata.explicit = bool(episode_data.get("explicit", 0))
-
-    date_published = episode_data.get("datePublished")
-    if date_published:
-        episode.metadata.release_date = datetime.fromtimestamp(date_published, tz=UTC)
-
-    image_url = episode_data.get("image") or episode_data.get("feedImage")
-    if image_url:
-        episode.metadata.add_image(
-            MediaItemImage(
-                type=ImageType.THUMB,
-                path=image_url,
-                provider=lookup_key,
-                remotely_accessible=True,
-            )
-        )
-
-    return episode
diff --git a/music_assistant/providers/podcast-index/icon.svg b/music_assistant/providers/podcast-index/icon.svg
deleted file mode 100644 (file)
index 52c2eba..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   width="512"
-   height="512"
-   viewBox="0 0 135.46665 135.46665"
-   version="1.1"
-   id="svg1"
-   xml:space="preserve"
-   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
-   sodipodi:docname="icon.svg"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
-     id="namedview1"
-     pagecolor="#ffffff"
-     bordercolor="#000000"
-     borderopacity="0.25"
-     inkscape:showpageshadow="2"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="0"
-     inkscape:deskcolor="#d1d1d1"
-     inkscape:document-units="mm"
-     inkscape:zoom="1.4142136"
-     inkscape:cx="256.3262"
-     inkscape:cy="247.13381"
-     inkscape:window-width="1920"
-     inkscape:window-height="1129"
-     inkscape:window-x="-8"
-     inkscape:window-y="-8"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="layer1" /><defs
-     id="defs1" /><g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1"><image
-       width="135.46666"
-       height="135.46666"
-       preserveAspectRatio="none"
-       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAIAAAB7GkOtAAAgAElEQVR42ux9d5xcxZX1Obfqdffk&#10;PJJGI41GOaEcRgEhCYmcnT8HsgAJMMaLwZicTMY2JhnjdfbitRcbG0wwyOQgEJYIQjmiCBJKE7pf&#10;1f3+6BHGu2sveDrMiHf+0Q8BM93vVd1z47n8JSJEiBAhwicREj2CCBEiRIgIIEKECBEiRAQQIUKE&#10;CBEiAogQIUKECBEBRIgQIUKEiAAiRIgQIUJEABEiRIgQISKACBEiRIgQEUCECBEiRIgIIEKECBEi&#10;RASQL/Af/kOECBEifFJhPrWffjE1gFAIL4Y2VvKlz7ZVVgQbN6sqISSUFvDRCYgQ4RPvBosAamPF&#10;nzvBdesuGzZ6OiL4JNiH/TgCoPECgPBFJ33h4BtvPuSue5NTJznSk0kjAhed/AgRIlAlRKzo5C/N&#10;uPXW2XfeEU4/UEGVVBQBdGVmI0F4CQpOOvHQa64OamoLKsoaJjUte2tJfMN6OAgIaHT6I0T4hEOD&#10;oOCUzx9yzVXxmu7x8urekyasfOMtu36j+v3fR9wPCYBpUqcoEHzxc4dde12ipgedqmGssrJ+8tS3&#10;33hd16wGFGBUD4gQ4ZMMTxac+OXDr70uUd3Dw1OkoLy6buKEt199lRs27Pf2Yb8iACFUGIAhDYwJ&#10;jjz0yJtvK6jrIcbQiFBETKysomHSxOVvLdEN71ARqKgoKNAoGogQ4RPj9YsxoAts7OQTj7zmxkRV&#10;NayhGCEpkqgorRs7ZumLL8q72y1AUvfTbMF+RQAGACQlKlRz8MxDv/edREM9VETkw/GBqajq0zR1&#10;5ZI3sWaFAKEw0Mj8R4jwCQIFHgVFp37xsGuujldVqVBECAgUyjYjRTVVtWNGr376Odm+ze+/2eL9&#10;igBCElDQhk1NR951W6L/0BgEIvKhTI8qDJyprOzTNOXtJUvN+vXw6sRH5YAIET45cCZWfPqJh159&#10;VaKiOwKTtv4AFBDQgkZsQY8e1aMPWP3YU9i7mz6KADotmX+I1p2oDho664d3Vw4dYVVVjAD8GwEo&#10;NKUMiDBeWdVrctOyJW+alauIdoaPSgIRIuz38JTS00+afcUViapaLxShAFCQoBJU0CupyuKe9YUD&#10;+6595HHT0hIRQKf8AgBAT0OSRlyv+un3/aBu7ARjg/aM3t8Vekmms3xGhLaspHHK5FVvL+Wa9VTv&#10;DA0IYRQNRIiwP9p9CoEgUXDaSYddfl28ukYCy7T1/8D7IwASAhACY2xZvwZb32vTY09a71PU/axx&#10;vmsTAAEBU6KkEqrlFRN/cHf9jJkgP5z3/0cBg2rSVFb1mjxt+dtvcdVKJT1FNGoPjRBhf4QAsIk5&#10;Jx9y1eWJqhqlfpD5+V/NBJUkoFo7eEBrReWWJx4PnNP9y0Ps8hFASKPUQti9BYmht9865NgTjMQh&#10;+gGv/1OPwBq6oLSkz7SpS5csDVZvsD4UhUYEECHC/pfuCAoLzjjl0CsuDSq70Zp/Yv33GQgkxVsY&#10;Srzb8ME7rDQ/+yII+v1nQrjLEwAppLaaoP6qbzadeLrG42K80shHyOcrPNWCqVhZZe/Jk5YuXaqr&#10;V4S0VEVUD4gQYT+CpxTOOfmQqy4zFd1Ab8VQ/1tG4H/afzVeKAS9mljvkSPW7djmFi5CRAB5fpfS&#10;/uIE9NZ4g5p5Z06/4BtBSXn6dclHs97SXg8IRCQoL+szqWn50uVmzdq0khBovAijBtEIEbqu3TeG&#10;Ao0Vlp1+0iFXXBcvrzSBNWKYtiD85/aBFJAgaYRMxHuPHrvyrTd11Wo1QiUpXT1d3IUjgPZUvWjs&#10;uE/PvuYKU1lj2tM+/4rv7l2rVFX1mTh1xfKlftUyAUIaqxrVAyJE6LoQAoiVnXHazKuuiFVUaLot&#10;/OP/HFVAFcXFdWNHvvXyy8GmLYTbD6qFXZIA2pk7XeYdN2b2Hd8p6d3fUNgBZQfSWnhWlDVOnrRy&#10;+Qq7ah19CtF8cIQIXRm0QfE5p8+88lvx0mpa+0FvyMe1FCnSqIfYwqraiqH91jzypO7dpSS7uIHo&#10;kgTQHneRqR7dpt13b/XQ4WICwpMd6dFSqDGashWVvSdNXLZ6pVu+DIgkIiJE6KrwlJK5Z826/NKg&#10;pBriRQwVJPTjEwA9lBACZHGPXrZ37aY/PmJDh4gA8kHrDC0YLxl113cHHHKEsTESHbP+YBpiDSVe&#10;Ut4wuWnVstW6ZpV6b0jQeBPVAyJE6AJQMULABGVnz5t96RVBWYUJLMXIPs+f/4p9gJBMz4qJdBsw&#10;8P1YfNfTT8OrEXpSabqifeiSBKCEgdRddfGYE79Cm2CGNT3VIyVFFb2mTF61fBlWLLeki+oBESJ0&#10;FaNGELGSc+YcfNm3YuWV2Kfzkzn748QEdcMGbNiyLVy0OASNp3RN77BrpoCsjZ/4pRnfvEAKK41k&#10;fDSP8MYYNRWl/SZNXr56FVeu8RrVAyJE6BrwNl56ztxZl1xoymqNNem8v2ausVuhHiKJeO9RI5e8&#10;siDYsBXqPbUrNo53OQIggOT40Yd/5+aC2t6kFzGZjzCgCrHwtqyivmn8qtWr/bKlHwyBR/MBESJ0&#10;WjiR4nPOmH3pJbasWuApJt2r4zO0/lABBxF4BWxpeeXwfqv+8Ciad1ntkvXgrkIA9MYKNcaCluqK&#10;GT+4p+qAA4yJp99u5n9ZWjCIRkSCsoqGyZPWrFyFVSsdlEAAqETZoAgROlVawJBQW1h6zpmHfuvK&#10;eFmFWJvWgkT7zFDGPND0unFDI2JKuvdmXfctf3wIpHjf5bzDLhMBCBgKnNFhN98y4KgjQhMLIGnt&#10;vmz+WvU+acoq6idPXbtyBZYtFcKDkf2PEKFz2QeqIij56txDLv5WUFGhhIjkQLhNlVUDG98Nw+bn&#10;nuuKVqHrpICMCILSs+dMOvdsKSwJVAiFeGZ3rz2VxjK0ZaUNU6YsXbfeL1tl4FQZEUCECJ0HGhQW&#10;nzfvkG9eaMuqxRpmtOr7z5nHMNZzxJDlb73pVq6mENqVigGdnQDatzQQIOTAKbNuvClWUWNIUJ2o&#10;KJnltb6EU1hqKiitbJzctHLNar90iaNEekERInQSODGl5559yLe+acqqhKGI/W8GJJsRgEIghYXV&#10;gwcuf/hP3L2HXSpD3LkJgLCUkCKgq6ycdtft1cNGiDHtLfsQZn+p+779AVaEQXFJn8mTV6xeqytW&#10;KjwICzphFA5EiJB7CA1FYIPS8756yKWX2ZJSYy3Fcp9YQA78s3ZbRFPSvYfUVm976DF65wVdxSZ0&#10;agIQ2jaCdE5k4E3X9jvmKLFGIGB+PO+QKVta3qfpwBXrVmPpElED0Coj+egIEfLgH4qE1NLz/232&#10;xf8WlJZTJBcu4T8KBcDKxj4b9+xKvvQSwK7SNN6pCUApIK0x8f/3/2ZccIFNFAIxpRfmay2PETpT&#10;VtI4qWnF+vV+6XLCucj6R4iQn/xAQcn55xz6jW+a0nKxVpjPjCzJMEj0Gtpv5UsL9J1N0K4hGd2p&#10;CYAGRk1bv8bZt99WUNfbwRp6Im80T4IQMIwVl/eZ3LRy/Tt+yVuqJtohGSFCjuFFyr427+CLvmVK&#10;S0X4t6qv5q00Jz60pRXF/RtW/9fvpK0tIoAOv+PAaGBG3fX9npMOtNaKUJjHIA9Ee75PKKa4qN/k&#10;SSvWv4Nlb8O76EJGiJCbO6gUBrHK88+bfeHFrKgQk97rzg/+i3whFBFFcX2vvdbsnP80RFUCi069&#10;YbBTrzim96Vnzx146CFKojO13CihNIketbP+7TxfVBxdywgRcgMnoNIMHXrgV8/S8nLjQfWdxMIa&#10;VRXnbGzMySeaIw+hghp28gJhpyaA5IgRU+edGcRLbRb0HjrmhsA517plx9O33+l3vx9dywgRcoNA&#10;Qfrwrddf+PefaMtOr2o0xs5hx5QAJa6MV/c46OKLXHU3owg7tYntxCmgMB6fePedNaNGi7FK5LfC&#10;8z/fderdTY9cdmn4s58bNao+upkRIuTAwnohIUptfuqF9+NBr3FjJJYAPSh5NxBUKkUFBoxVd2st&#10;jb/3yJOB+s4cAnQ+AhARWG9Q/bXzJp46x8YTaWWezvDRPEKv4lzKbX/3kWuubv3hT+BdpAoRIULO&#10;Im8qoEqv8O79F57fU17Wc9QwMBAj6WQL85cqJiH7KoWk6da/78ply8JlyxRKQgkbEcBHeMfixHHE&#10;yJm3XB+vrGFncvzpqfRu784nrr9h1+33FnhNUhWGiCKACBFybrxUds5/vq1HdY9RQ8QkBKKk5rtY&#10;mP7tbfBBIlHdv37Zfz0YNLeYtCJp51MO6HwEYAQ2PuaO73YbP9F0stS/9y5s3vn8bd/ZfsOtcKkU&#10;HUCjjIKACBHykCwAHdp2PP6M79OzZuhgQNJruTqJ12jVBN2qkja+9S/zDUBFJ5wQ7nQE4Awr5s4Z&#10;f+rpYqx0MgLQ1tZXfnDvusuvgjoqCLGqrmsugogQocsTAGGUgXfr5j9dMGR45cBGqzGf3tyYd1uh&#10;zokXDboN6Pf2awt0zTrTKWeDOwcBSHvlhDSpfo2zbrq1qEd9aCRvmg8ffpFQKFyoCJsX/vony8+/&#10;hKlW8Wk5UNVIDy5ChLzdTSjgVU1b28pnn60ZO7agT29RlXRBmHmcCYNQhMaI2OLi4l51a3/zexMm&#10;O6FEUKcgABKASRkl5IBbrq+bPk1tYD06QyjnlQSdtq587NFFZ51v9+6mqkRy0BEidBoQtK1uzYvP&#10;1U+ZXFjTXazRf3X5e0Y/Vfufpd1qN7e1tD3zQid0FjtFkyoVxiNQCY49ZsgxxwvjAtdJbKxTbdO2&#10;bS8///K887DzPYUPlJ4S3boIEToNAWgQtnH58ie+et7utavhUt6nFJ2lNueCoilzTnODByOKAP7B&#10;CxQv6kuKJ9/x3fK+g53A0CtMfrs/2+NHdXuWvv34mefa5cugajydiFFECqARInQeeKOBp9m8ZeXm&#10;d/odOC0oLKIIwc6QohWlKSllecnGP/xBOtlUQKcgAGcMabpfcM4Bn/2cicUNSUgerb+qKpACoGjZ&#10;tOGxb1yI+X+hZ3oJDFQj6x8hQucKAhSAeufcm0u2IGxomsp4ACg7QbCuhKEp79Nz1fKVWLpUCQXZ&#10;ORbLdoZUBi0lObBx3IknIRb/W1SXT9+fBK0qdu34y803md897BD1+kSI0Kmh7e62vv/dO//60/s0&#10;lewkLRpKKNUWlU386tzWwuK47vvbKALYFwEEI799Td1BMw1Np+jhparCpXYv+Pcfv3Pt9R5h4CRF&#10;FY0c/wgROn80oFufea5w9Kiy/n07yywRFcaWdKvd1tLc8sJLXlX+xlmf7AhACTvroMFHH2vFQjpJ&#10;cVUV4epHn1h2yWWxEMYjJGLRtG+ECF2CAMDY3uaXzv/azkWvd4bNXM6r9w5ebSwx8Stfbu7VU8FO&#10;skQkbxEAQUCskbZ4cdNtt1QMGyI0jsgXX3tVeIQCqvcu3PH66/NPO6No8zavDpre8Ba5/xEidAF4&#10;qqj6XTtXrlzab9b0IFHqTEhIvirCQhoaIUGJlZWGieC9R5+Q9lLjJ5UAAFEqyZKT/9/400+nTUAo&#10;+RvjptIbJypQprZtfezc8/DqaxDAR3Y/QoSuBBWIQsDk2rXvJV3DtCZji/K4SPbDFs3RV/fu/dZL&#10;z5t1Gz/RBOAMLRCWlk/+3g3FvfpZLzRewHwN/zp48c6puOT7f7n5O3t/9jOoNwpEef8IEboaCFDV&#10;et2zcGGqX0OP4Qc4iu0E9UWBoLgwUVr8zgMP0aU6wefJE2JePVB71im1w0YLkLLeq/P5s7YKpzQe&#10;bukDD7538830BlCfnUQd/3fnIEKET5SJzppXq1DAEZ4wHksuumzTS690kgZ8R4DoO/PQ2BGzOsPn&#10;yVsEIGJb67rNuPnmRHUPY4yQks8WIPUuVHD7ogXPzJkX274D6pk1999AvNG4BGqMVxXCS0QFET4x&#10;tl8oCMRSQYGAAqFk7rLpB0EAADBo3rtm5cqG2dPjRSWpdFY3f9MBHrQqGpPC2pqV//nbmMJD87jL&#10;Jm8RgNL3O+9rJf36i3SGfb9U2tbtG5+7/LrY+o36t1OUJS/AWG9Ss6fFP3e8p3pq3HdGrfAIEbLk&#10;BSetL517RnJQP9ArEXjx2XH+jKqH4PkXXrjtNrbtsdSQNPnr6KOqA8hY74kTy75wAlQJdfnLTeUt&#10;Amgd0H/GNdfGKqoBSP63uUHb9j57553bf3Cfyf5+R7HiZx18+B3fG3jksWt37/R/XeLoTCQwF+GT&#10;EQCojfe45vIZF17Qvalp+TPPY+cuhcvG6ScghCeNhrsXvipDBtUOGiAmYD6njSiAccJEvLS2avn9&#10;/6lhKDCSp7Wy+SEATw64/LI+B8+kEU9j8i/67Fc+8eelX72AyVZCstuiS4YzZhxxx3eLGwba4qK+&#10;Eyes2vVuuPA1QqKCc4T93/0XU3/NFVPmni2J4uJedZXjR62a/3Sw4z2QWfGAhEZBqDhsfW1R3SGz&#10;imtqNX8LhBWgatLAKotqqjZu2+BfXpztlENnIQClBNTQSjh40PRrr4mXlVCM5I+NvQLqnde9a9c8&#10;Pvcs2bDBOM2S9aeAJE2g40cffscdxQMHBCYmQhYW9m8at27X3rZFiwBvQJX0btGIDCLsR26/iIq6&#10;INHz6isPOuertrDYWEOxxT16Vh8wZMWf56OlmVCBeBELydjYjUI/cKx2797w/vZ+B0+VoJAfmjnN&#10;pf0hQdKQJMGgtKZ2+f330zn6TwABQKi0cWi/qy7vc+BUbwwp1Dwq9qlTcW27n/32jXsefDCWPivZ&#10;+ThCetG2IUMOvvfuyuHDUiYIhKDzPikF5b2axm/csSN89TUvjHlJGTCKBiLsTwRAAW3P666efNY8&#10;W1SUXp0OQFVKe/csHjxgw58ek7YWQmMejllasyp8c2mysaFu1Cjh35pCc29+0r/Rey2srdy0fXvq&#10;5ZfhPwEpIAN6mtahA2dccUVQUaUUSUti5IkAPLyqW/HwQ8sv/FYslaKqz9oeidAY7dl75o/urh0z&#10;0dp4gLTaKcHAEkFBomHi5PXNu1ML3wyZMtHccYT9Cz6I1V173dRz5klBXEx7vx8VJMmgvLGejQ1b&#10;HpkvoQuZXp2b+QsgoKPf/sri6oMPLO7WQ72KCPK4NQxUa8srqpf++temtXX/JwCBUab6X3Fp7wOn&#10;U4L2oa98PP601r9637Ju9VNzzpatm9MHTuWD7rFMX4CK8gn33lN/0EwRCoWqjkKleK8ioWdQWNjY&#10;NHHd7h1uwavt6+wiRNgPfH/AGVt/zXVNZ51mC4pB8O9S8M6LKky3gUN3Vxe8/9jT0JQgKwGAIQCr&#10;e/a8s/3d/rMPM4kE89qCGEKNMqip2LplY+vLr+z/BOANUn0bZ1x7TaysgmnB/5w/ew8o4NRTvbbu&#10;efLmG8LfPcR9JXhqJj8RKYYaivh4YsT3bhl0/Ali41bSW6sp6V2YIgSNiIhIPN63aeyGPS0tf10k&#10;6gVwRoRROSBCl4RQvBgGQf313546b15QVNzu/XyIHEgRiIiRwPYYMmyHxd5nngeYjRSob9/l4VNv&#10;Lwv7NnQfNYJCzd8OeQ8V0FlfWl6x8te/EZeCmhxXRHNbBBY0XPqtfjNmqEi+lDlUHeCsM55YM//R&#10;1V+/PPRJZEeAQg0dKQa9r7x6zKlftraAVPzDDgR1mpREWcOkiZt272p99VUQcWdCieoBEbpm2keM&#10;N6i/9vpxZ8wJigrxfyt9Sc9xo9Zv3558bWFWRQFEddOiRX1mH1JQ082ns1B5ekIqpEpRTdWGjevC&#10;hYsVKrnN/uaUANp69px+zTWJqm7CdDtsXlgXoDqwbeP6v5z7db9udXoEJSsEIOIg5WfOOeiC801h&#10;JSFJCcX/o74nelgVL4mgT9Pk9c17wlcWO4amU4gGRojw8SNgG9Rfe/3UuXNtwhpj/s/xW4phPNFr&#10;5IilbyzRtWtIgWZrbUq8ec/mZNh35jTYmMmTCr0nFDShaBAUlRYtv/83MRdqbjsAc0cAStSfe27f&#10;o44Wa5VgnoaQFSDoXOrlu+/a+ctfGlV4ZnAG68NVZEPh0Ycddv0NQVW1ULzAwIP/cNsl1StFPU1h&#10;YeP4CeuadycXvNL+oSNE6FJwxva+/vrxZ84xBRbGCD+C0Ds9IFKUqBs1euWT87F9O1WzYw4piDW/&#10;8Vp8xOiawUPE5McWpRPOTmAohVXV619/Q99emhIyh9vCsk4AKrAKb2xbefnUa64uqK8ztMxf3k1B&#10;eLflr6+8OvfcYM/e9CxABj+KoXgJAvVemBoy4NA77yzvPQBiRJjWO/onu45JEdKk82OJRN+JTZua&#10;9zYvfE1AATyNibggQueGiiHVB/GGG6+bMneuSRSYj2j90d4aKjSFtTWFAxrXP/iQJJNgVgYkDVRV&#10;31m2rN/hh8fKilTpkOsd8iT3zQSA1khpwcZf/5eHz6VuXdYJwChCQVyk8vQvD//il1I2FqStWZ4i&#10;AOcVe3fOv/xKvrIIWRi/ThmJKULj20pKptx7d934Jmf2TXd9rPDQKwtsw8SJm/c2N7+6AETC2xQj&#10;xaAInTvtQ6gU9r7xqgmnnWILS0Tk46ZXSZJS0qsurKze/sgj+NAgV2YdU1EJ392yt6Ks99QDQ2Ms&#10;fH76UgBAQ2h5dc3rC56LrcnpnoCsE4BAvKA1Hp903XVlfQcESDde5S8C8K1vPvrwlkuv9gpmgQAs&#10;xBFq44NuvHb4pz5Hk/DirefHHj4nIWJiRX2aRm1oTSZfWRzCmUgsIkInjwCCol43XDNx7hyJlZoO&#10;pFY8bbfB/Te27km+tDAbjppSDGDgt7+2qNvMGYXdugdprspPPZhUlUShs9j+uz+puv2EABRQoSgL&#10;jz18zJnzGIsL1BPMx+IvBQht3rThmXnnmHfeBV1WPAsDwhSe8uUp53/dFpZ4qtXQifm4EQBVAVG0&#10;SqKsccKEDa17Whe8zPRuyggROiWcCfrcfM34U0818VIxkA5ccg9v47HuQ4YuWfiqrFmbecNHUapC&#10;gtZwc9vewYceprGE5k8kyEFBLS2vfuOPvzfbt+8nBEBAxVgJBl99WbdhI0Uk7fvn2PqrV8CHnhK2&#10;LPj5fS0//q1HihnUG9l3bJQwYtz4sUfcekuiW08jFJI0/0rPazoSFitiNJ7oO37i5mRb8tVF9E5I&#10;bxjNB0ToNGkfAzFhLNb3xusmnTXPFhSlT34HPXTCmOJEzaCByx951DS3GnpmbjxA08P2qgrfunxp&#10;bNz4qv59CeZLmTg9GB0rLtzd1rLzifmgqNBk39vLQRGYbSOHTrvoIhSWmDw9XEcCYpzbvnzJwrPO&#10;1z27PJWaMQuqpCcMYIDmstJp995ZPmK08IM7wA4eDO+8FAa9JzZtbmluXrBA6eMeoTDSj47QGSCk&#10;s7bxhpvGnvYlW1Dc8W0rmo4AHJ1IcV03VNds/dMf21tCs9ESpNyyccOgo46WwqJ8EYASokiCpaXF&#10;y371ayZb9mkidXECoLV9L7qg4cCZRvKn++ngCE3ufeE739vz58cFGniEgkz1/xgoiIDSGrP9r7p8&#10;2AmfsiYByVihm0JSGC9smDj6nWQqueD1UFNGo3pwhE4RAISJ4sYbr55w1hk2nq76ZsAdNkjrBIlI&#10;UNu/cdP2HalXF4UG2eiQ8UKzdm1q6JC6YUPEBvkhgHZ32SbKyzdsWNu2aFHMmxSzrgmT9VaclvLi&#10;QTOme2OQP39VqVb9tkVvbLznRzFH60yKNJqx7v90a06SjB135LgTT1Rb4OklkwbaQ0kmbXnN7Esu&#10;KTnndE8TycVF6Axw1jbeeMX4006jMRnMoCvo6AlPqBYUT/r6BeHokVY7GlD/r7DqPcyyW25p3bR5&#10;ny3O9eWipyPEhyaeGPqZ4x2kjTDomhGAIZ1YA4RGqr78xRH/74u0gQKSpwjAq2rLnqevvy718gJ4&#10;5+GZUblN0oBobeh16F13lPbpLyLCTLYTsD0EMEJBLNF33OhNqbDtldfEO4IqlKg2HCHXaR/jhS4R&#10;73fLzZPmnGkShcbYDIb43LdBI33yExXlhfV16x74nYTO0qTaZYQzlQJCKGrefX9P7269x45LkcJQ&#10;FbncHExCwHTRsKisbNmzT/l3NhplWrugq6WAhAJ48aAddcVlZf0GikgeCUC9X//8c8suuiQIw2z0&#10;2FIImiHfvbHvQbPF2OwdEgCqHomiPk1j3mlNNr+8APQJj5CRemiE3N4pAUyszy3fGXfyl2yiKLvZ&#10;XVUoSxtqt7elmp99ISUhVSRzB9635wN0+1vLGo85MlZRKTRA3lLWPjBJl9zx0OMqLtv3OlsUJ6qg&#10;uInjek+YBGORP+sPwO3duejeeyXVgiytXqcUfOULo4462gfxrIdsJI2R0qrZl1xU8W/nwRS1Gkhk&#10;/SPk2EjFi/rcen3TqSfaguJsG0pHKmGCoqazzkhNmWjFGpgMRtiBkjBtVs3GDX/99a9D16oQyV9M&#10;LSY+aPrMsKrCZv8jZIUA0u6o8XbAlz4rZWWEAzzzVbRUXf/Siy0PPCgemVbaa1/p0lbfffL550hp&#10;jfisT3B40qb31pRVHXzRN0vPO8PR+qgfKEIOEQZB483XjT/ldMaCHNT2BICqEymoq5t42QVtQSxN&#10;CZm6w17gyIQT9brqjrv2LF9D1VBcvi6VACWNjZWfPU61a9YAHOhIX1bcdPWVxbU9hIaUXE/+KpRQ&#10;nwz37n3iisvN60tUM9lAQBKMeaPeyAHXX9cw+wiSKsi2zHV6jsKIWBEfT/QdN2ar8y0vv2rUCZhz&#10;OfEInyAIJbTq4kUDbr2h6dQ5JlEgYnKg606ms+MiNOV19Vv3vL/nxQUwyNgeXVWqV1UqTFtLc011&#10;r8lTSJu3lDXhDGMia+//rWR5Kliy8wWU0IpjjipvaMzXvh1PJUIHs/6lF1p+/5BTH2Z0cooA4KEI&#10;Tjhm2GdO8GKVoOZU4EjUm7Kq6Rd/veq8c0KxzmjcaaQWFCFrdwqU2MBbvz3ulNMYj+c4Rd6+RzeI&#10;TT5rXmrogGxsUSdgPFbd9YPdK5f7vD5qRVVvGI4AACAASURBVNB91Eg/qG+2awBZiQDSIndDLvtW&#10;zbADmDfdf6U67Gl++qqr7aLFrl3pL2Piss7SqA/LKg6647bSfoMtSPGeMLkUuROABrFEnwljNnnX&#10;+tLikCmjUT4oQnYyP4WF/W793viTT0Y8ZvJ0rwViyitiFeWbHnxYXJh5uyEM9jY319U2TGrKZkPH&#10;P7WfXkWFiUTzrl075z/FLJuQrPAo6+t6jR8DNXk7rUqv5p3FC/Y8+MeQABBoJnWfrddQUPfVM7sd&#10;MEG8SQmhNtfDWUrCCyCl1TMvuqj8/LmOkf2PkB3rH8QG3HzTuJM+zyCexyBTxQuk/+FHFh1/bDZu&#10;m6gqsO7uH+5dvxZ5EltRwosTifU5eKYLsjuYlnkCIFSgVZ//VHFtzzx5CVBAvbK1deEv/sO0tUBB&#10;hYNmUv6TJjVsaNNJpyEeo2GAtNx/blNApFCssYGRoKTy4Au/Xnv+18I8jTJG2C8hpCFTRYUDvnvL&#10;hJNONIliMc56ydfnISgKlBY2nXtOa3klA0OBNxlzNEVBuuCdrYsfftCHyVBDdTkU52zPoIiBIdF9&#10;2KiC6dPSa8O9ZKWNJvMvUoGksO+sGd5aZd6UlQhse2vxzl/+p3zog2UQjjr6G99I1NcDDvkqdPzd&#10;Y3empGr6BeeXH31EZLYiZO5cWUfp+29njz3py4gX0JOe+bP/IOAMDWy3saMbzp6bAjwl8Blz7ELS&#10;eBh1a+64r3XrJvFMGZp8BAIiYgoLGj5zHCjpvspsxPbZKQIPGtzrgDFUI/mrpGjY+tff/Vd8z27H&#10;bNwK2MMPH3L4ERSbr2To/4wbxen6V15+9/kXIrMVIVPwTDm6jX987L1lS51raaOqMI/+jgcAjXnx&#10;NjHqxC+ibz9RhJlzNI1SwTYTcsWypX9+1GtoFfkyYxRpmDSppajIEczOXEIWIgCy1wnHmspaFXXw&#10;+UmiQXeuW7Xl338G0Gbh7blYMO6ceSgrh3gVm+9LqgDgU2uffeTZ084s3PpuZLYiZMwGqRE1ftEb&#10;fz517vtvLBGf0rzGu+klwSnrjKC0oe/QC77qCcJk6kM5wonEQjEeS+/7abhrF+GVLl+Pv7JPv/IZ&#10;08KsDXtmjAA8SYAiKWv7HHygCogkctv97xWqGvpU6FIrHn/Mbtlp4DOY+xEhRGBYduKX+xw4PRAj&#10;MJLPy6Be4TTlwtSGV158es65iU2bfVQDjpDJQ+bFOw1DWbjw8fO+vmfVSu/Va74MIgxhIBY2PRYw&#10;7IhjfdN40GXqmtM7cc6rh1f//MvrFjzv1Oe4vfvvfLtEYZ9jTwBFkBVHM2NfjEjvq1UO6l8//AAD&#10;E8JIbrtiBFCSNOG721f88GeKlPHMVOuPEiEN1CRLSsafdrLkvA/6f7r9IUFV52XH4lefOm0e169X&#10;GEYy0REy62a0hwLA8y89cd7XWzZt8D7Pac/2mQBorKZmxNfOzdIex0D9kv/4rbS15G8VNz1N/YTR&#10;YUGhz04+XTL4ToSEsP7TJ5iKaooQBrlui4QCCN3q55+TRYsdXIpp3f+MxMIwXgVad/pptSNHgvm/&#10;AxL6JNv2rlrx+HnfiC1/23of+EgWKEK2bhddm3vk8acuvzL1/lZV1Xwr0FoxwmDQrNn2sEOykZcK&#10;VXf+5ndb3n4zzFsKCAFY3bexbMbBWUqmZJAAlMo2mj5TpxkGIb1VD+a0fOIIeiDVtvT+/4Bq3BlV&#10;mox9BAJsrSgb9cWvqEl0kkvptr735EXf1BdeNF7EIyk+0gWNkC2fQ40Xt+vHv3z6ppt88968EwDI&#10;UNQWVw47Y05oBBkmAVJtvHnP8j/9GT7M33f0Gk/0PvqIVHpnfaclAFEScH16dR8yFGTQ3kCcUzfZ&#10;I/SiW99evPuhh6GqcAqfuWOq3rL+9FPKhw40Jm+FX6/q1Xn1gEu1vP/MDTe0/v739KFXp6r06X8V&#10;IUIWQgAN6ZSubdvN333pxz90qWbvQ5c/46iAoZAccOCMxFGHQ6xhBmcxVZlyoht+/NO2LdscPNR5&#10;5Jr1FELEeo8Z42ImG3NpGTPQjvBg3ZGHBzXl+ToQAith28pHn4i3JZGFp5UqKxvxxU9bG8+j3g6h&#10;gFBFU6nFP/npttvvFlXRKPMTIYe5F+dWXHz5yvl/gnog323Qqra4eNSZc1xg2oSCDKoPMHBw69as&#10;efFZVToaKnO82dATIKr69o6NG5MNq5Oxl2c8ADYeNF2YN+84hLZt3bT6Z79wPvNesIJ1J59YPngo&#10;HfOoFZ6iqqf3bSv+/Njb37rMaCpQtkX2P0JuEdu755WvXbztjdc1fxFnet5TjKExjU1T7eyZ9LCa&#10;sb2UokrAhOHy3/yWe3e79pJmTr+vAYXKotJeRx3lO3MKyAuSlWXdRgzPKAN/TMdE3bpXXrPLVxqY&#10;jD+qsKR4xOc/70zci0P+8uzWGYHfseztFy+4yOzdG3i0CAs8otafCLlOvyxbPf/SS8NtG/Po+/+N&#10;DEpKR55+sgrCzHlnhKaEVHn/4UffW7oUGgJgriMe9VAi6Nk0wZlOTAAOWjLzoNIefTSPnfFtrct+&#10;/3v1ofcZW+agBhSxYiu/8qWa4QckJBCxpMn9hVMAcB5h23tb/3zFlcGSZeI0pbDOO426/yPk1vX2&#10;8PB4+PGnbv++37MnDJ1qrk/h3/VhC/tOnRZMnZTBnU9OQafwLr579+qnn2YIzflkK5UCIdl9wAjX&#10;pxFiQGRw64dk6kAEtPWHzEQ8j2OxunPDmq1/+JP4jPvnfk8sNuILn2OQL501D6ZH2oykki/85Ef8&#10;7YMfbviMrH+EHLv/Cogi5v22W7+/5NE/qHqvLpU/JdpQYcoqB5x2ssvCZ6Bi6a9/63fvAJmXOWhP&#10;xMtLex52GEgLhpkT45BMHYg2stuIUY55s0bq/eqXXijY8b4ikzl66ykqhccc0XPkWOat958KqHqG&#10;qdXPP73h2hscff6b8CJ8giMAqyDYQi9tra9ecvnOFW86OBvmrV8+RjEmGHzQTDd4SDZ+vryycPMb&#10;i9S7XHMcAYAiiAc9pk11oCKTJJS5NtBBA2oaB1gKJB8MqV6TydW//YN47zM6oesoSQlGfumzPpHI&#10;641T0dSejWtfuuSyoLkFShOt/oqQvwjAiQI0Sk+JrVj73M23cGdLXu7+Bz4yoaZH94GnnZRxEWIC&#10;MR8un/8s1WvuPVxNl6Ol+/BhSCQcKZlb+iEdfC5KCCBg7eyDTVkpvOQ4RPLq063x25Yvbnn8CfVO&#10;1GcwCUQhRw/rM/lAkzc9EKiG8HDJ1PN33YUXF2gqRe8z2H2h+5aleUGE/dx279NG6eCrVq+qTlWN&#10;d+qSu37yyzce/LV3oXqEgHr1uY5QvXrScNCs2S1VVYFYFWQqU6KAg266//627ds097vimV6LjIr6&#10;utioYVBkcK+JdPC5UCGAJ+qnNBmKy3mDJNM7HDRc/+IC09yShWOFfqeeHJRWqMlbysVDoH7t009u&#10;vf0H2Wj4FIXuW4gaYf+GUaQPcgZl0j1h1L9x5Q27lr8BqE2vXsqtUla6ZVMQlPft3/3zxyvSneCZ&#10;/Ax++apNixc7yVuaC4WFPQ6ZRUUmBS47bn89mSxMdBs0mBJ45DpH5oiQXltaVv/+j9mQzE5WVg2a&#10;cbAxgclfxsW5cO+2da98+8Z4S0tWnq4xPjAho17S/R9JI14kHQpkCoFCSbNu7bO3fS/c826LOoWX&#10;3PbLkJKWI9PCwmHHH7c3MJkLANJRuMacW/PkfMnf5HMIWzthgjOSQSGyjv4gBZKEGTq4vL63Ernv&#10;khEAip1r3tn7zPPZ+Pk1nz+uqLHBIy/jLvu4Pky++pMf45kFLvO5TSjRRi2a3NRm5cNlhYgM9i8Q&#10;gCsqLJg6KWmZ2WjPE8bDkLt+ev/yxx43quKNy+1woiodVeAE6D5yrB07xmgGU+XpwquufvChcPuu&#10;fL1CS1vbf0CqtBCZqwN3iACcUBkYIz1nHWqKy4yQsJJzkWSSa197NbY3Y/kfNRASxjgbG3z0MSIB&#10;4HK8B8+peg1DqPf+vTcWr7npdlWXyalL0tGIsWpMxWknH/EfP+939dUuiEFoIULKJ4MB0jlxJfZn&#10;FW0xKjZVXnbAPfcc/qN/57QDDQWZ26OrHqrqw9Am21679qbmTeu9qM31TAAMCBgCsfLKQSeekqLP&#10;ZFGLIKjLlm18+/XQpZwPc+4UqsAX96wrGjfWUzOVBerQAzKent541Iwfk68GAPHKVMv6hx/LYGGE&#10;SgWoynEje40Za2AdJcdNN1QoDT18y66Xvn9P4fu7PDNZhghFQeehZvLEgy76ulb3GD/v9PprrgqN&#10;DUUD1dQngwE+6Krj/vwVxRfFR91x5+ATToj16TPr6mv31NVmqVinb7y++Je/YjJE3pom6Gn6HtQU&#10;llf4zOXrqVRqwvl1L7xAioolctzzThWxsXj3aVPZSdpA0zoVbYlYzYCBlPwoQDj1Ozes2/7YYy6D&#10;nT9Kgl6k4fOflYpqgkZzbQ4pMF68a101/8+7f3l/Cs61d+tkBsaDUFdeNenaq4p79Q8kFiuonDZ3&#10;bq/rrkrZwqRhfP9tM+WHIKQAoth/5ZQ0LC0ccc89gz/zWZOIWdju48ePufE6Ndm5sN6tvvW295a+&#10;4fK3NcyS5Y39q447wWZuYl8BeLWqm3//kO7e49QDkNzqApGksTWjR7vMGduOEAA9YbzX/o0VdXX5&#10;OtzwuuX1ZcH7222GDZYkY4n+06YTDI2jpj3FXNI9lQh37lj83TtiYYpq4t6EmTtwokJIvyu+2X38&#10;FMIokwL1BcUTzjir8epLkmJSHyLUzk8F/Ah/p4QjnUibta2xWGtxcWtRUVssaLM2aSQp4skPWsj5&#10;tx/CD/7gB7agizAdgLC4eOQddww87ngTUJSeJIPBRx1XMve0bGS9jJrEuzteuvdutrXk62t7egSJ&#10;PkcfFmYyHa0EoWx9bfF7K5cF7ZoQkmNrB0hVv36pRCxjZNmRj+MEMc+qKQfZotK8OXPwG5560kAg&#10;LlPm0agkjSueeWDNwIFGJB3s5DjACZ1Xti555KHkk8+IemhHv1y60z/cF7gakfhnThjzhS8bGxMR&#10;IAZDC/ii0inz5jnhhksul2RboJIyar067byGT9K3k6SKQtNNrYYSClIVFdK3b82wYSWDh5R0715Y&#10;WRkvK40XJCSwQUEcilRrSsNU297dLbt27t7+3t5163ctWbbrjbeSa1dLS6uknAGdhvvm7ykKR4iq&#10;o7ITKzAZmpCSKi0ac9cdwz/9GRhLEAIFSI0VFRz0tfN+//yLsVcXwTsFNXM5ZSXev+9n73z+Cz0m&#10;HSRUUYVY5tROGlU0jhu3sFd9bPWatJHuqG1I199UbVvrhjcXVY8Yrbb9ceaUABTlPXqaQQPx6sK8&#10;E0D6GqDH2LH5EoBTILlrx+bH/mza30RmDnEoGnjpe/wxGo/l6wIrEW7Zuvi2OwsJl6Fnlbb+RuGI&#10;PT17HnXhhUFpUQrOQD5ILhn1KCyceOYpArPmmxdDw8BrSkjXiR1fkqpKpIynB8urCg+a1n3mQTVD&#10;Btf26V1Q2y1MJAIJ2jNrSE8IEenlHn+7wqoAvIN3YUvz3s3b3l23dusrC995fH7bgpeleQ/hqXT0&#10;RtMVY3biYIAhJSxJjL7rrv7HHQtj+aHIRgFHW1LXMOHKq1799KddqwZKZCpjQzVekEy+cte9x40a&#10;5wqKFBSvuWwqEECBgtqq7scf9d5td6hmMtQR1XVPPDXic18Q2Nya/3TPPVhQ2H3q5HcXLszI6euY&#10;dptqm2HVwAH5IgBCt69eieWrVDNJAB6aKilpaJrE/G3+gibfeOjh2F/fCDO3kVoJ8VCyzXLkxd+s&#10;GDZcjAn+/hBTqJR4YdXUuWdB/IqLr0TYEjiGnTjz4UhK0FpaVnPorD7Hn9Br9PDS+l6MFXihVxCI&#10;Q5Uf6Hh9sNWDJDRd3VcCokz7qtYE8XhpRcWgQf1mHuzPOXf76lUbXl2w4oH/annyqeLmlErYQpcI&#10;6TsvA2hYWjj2rruHnPBpWPw3bRQqRSwE/Q+avm7e3M233W49w0xMuCqRhBqqVx/++jfrTj6xftpM&#10;WpvjFKICFHUmaJw1a8vtdwfOq8/kYtg9T8xv27KpoL6fQpnzrec0pmbc6K2gZOL0dcjAeaqrqKyq&#10;75nR8uTHex7vLHoT6kkIJFPbEA2QOGR6WZ9GaTcVefhuya1bl951r4WjF5+ZGADiQSAUFh51xPDP&#10;fMoKHOW/HSNVptMoriAxbs4ZBNdcdAk1hc46JOwpfsiwfqd9ZeDs2RWN/RGPEWnVPhWyfRhIyfYA&#10;ut11T1/ltMAqAFIJEKKAh7ane6FCSlGidtjQmqFDR376U9uWvr3k0T9u+uEvsG7tB7qHnSwQIKCp&#10;0tLR997T78hjGPzvW7kFCqhLJMafefYf//RY29tLxGfge1BhlUpvPehTf/3Rj3s2TRZT5ACbQ0uZ&#10;jtBI22vUqBfre/q16ySTPxyyZfO25asa6vvl2Po7KgEPqerXqJSMBG0dKgIHsIUjRhfX9pBc7/5t&#10;T8r5VNv6+U8EoYNXpxmb0FPDXocfY+IlOe4PTCcZQ5/yYeuSJx/mojc9O578/7vXHQq0uHTyhd+I&#10;V1bRBIb8bxKnRkiBGAloEoUlU884q+GGb9MGEArzPB8gpCWdhRrAWFrrJk8Z8u/3ferRRyfNO6dy&#10;2HApLDDGijGgBQ1AAYkPNfxwX7Zrnx6OAQyQ/s/QXimhQVrUUCiGNBQjxtjish5jJxz0jcuPfuLJ&#10;oXd+P3XAUGeNGlFJh02Z0djpkP0VEZpUZcXI++4dduzx8YIC0pj/2Qmz74sasrRP7wMuvtCLVaab&#10;6NnhdImnqgIe2P2bBzYuXJB+pLl8DgYkaMUkaupqjzuGoNBYZMxcG6dbFr9O7zS3lUEhSRHVyrrG&#10;sKZaAwMG0rFOpw4dV69a0zSBsViOfSACCvXQ1ne3bn/6OQ+vGd3TkwoSfUaPdCbXYQ2hSgI2uWPH&#10;23fcZ+GMR+bOLZyoJ7ude1btyNH/J7cp4EgkCifM+UrPm77tTOBEQ9E89gQpmBRYT6q44UMH/vCe&#10;z/zmN8O/+MVE927exjRtybPL2SQl1tB75Mknf+pPf+x/x+3af7CnITTdSMqMauz8C8+nraJo7D13&#10;DzniKNqAH+Xyixt0xJHFxxxJeNA5UZuxrAZjob7+s19qKsl8xUgivadPFaRj2oyNBSuw8Ym/uFRL&#10;rlvD01GsYWFNVfEBw+g821se8kMA6gyqBw9SETKnCQJVTet9bl+xLLFxq0/7eBn0IMaNK+/bT9Xl&#10;eNNiWl8RLlz1/DP6ysIUfCiSwbsjoOvbb8JJX0as6KOcNoIqEi+omHL6nIabroUpYl5HplTUeLrK&#10;7t2uvvy4P/x+5Je+Yrt3D4yhEZIGOdjXrSphXBAEiaIeDeNPPf2IRx7occlFyeKq0IoRyds2VABA&#10;W3n52B/c1/+4TwXx+Ee5ECkAHraodOy588KikkJaACEz9RTVw+/41f2b31ocIj/6ORTTc8Totpoq&#10;D5/BOSGotrzwwt4tG3OtDKpKeBCMJ8onj1eIoqN7QToWAYhU92lIF9HywO5ONy992zj1xL7GjEw8&#10;ZKLvkYe5omLrvM91hQei8G0tS370U6NaoJIpSUXuiyEHX/C1kt59P2Llx2j60AnixRNOPb33zVeo&#10;BJ7tTRW55wFPw+OPmPHQfx70tQsL6hqU6c0//Ns5zvpnIjRQ0AOeAFnYq//Uiy6e/tDvzKGzmg3z&#10;WCgJK8rH/+DufocfEYj/iJkJ60URAKme4yeWnX5SMyWz0y6isHvbljzwW+Py9mCKu/UsmzkNRAZ1&#10;gQSqu7bvWLk2x3cgXZoyAGiqhw5UYcfNXse0gIpKS+vrvSp8bl0fVYGGLtzyzIuAs06ddlQmR2AM&#10;4YxxJqgbO9KQMGI1x5N+otBNixftefRJOk2pt2HY4S8mKWsDUmnCkSOHH3UMxepHs1TpbaRCiiBW&#10;VDL51DMabrreBQFEhIY0OVBIVVJJKzZVWTngxm8fe+893cdPkkTcGFoxFGY2+Pu/SVGYFmMUwIiJ&#10;i8QShb2mTDnhRz/pd/XVLeWlYgwMvIE3lOzvjhYKaZJVVWN/9MOhxx4bLywQsfxoDCAGRmht3CQK&#10;J550UqqijDQ2k86cV3GbfvSLXWvXqUMKDupz3U4cmN6HziAkg3VKhVXl5tffgs+tfQDbi1bCip6N&#10;oAHgOva9OvQ/xwb2K6qsyPkdhIgA9Du2b3lpQSZ9O8DC+7ramqFDjBcH0dyW9KgKHy793QPxVDJT&#10;UZXxsN63Gk0aHnD+ufGqak0r535csidRUDTu1JN633izMxZwXlyY/cdjlADaJo6b/sD9Y+ada8q7&#10;U+k6T98N91F3Ze3Er5174K9+3jp8uCOtF1Hrst4cQQ/bWlky/r4f9T38aLTn/fnxvwOrBg3uftYp&#10;okhl7iOnBbV0y+YVzz4V0hkvCkrOF8fXjRoBE/MZig+V8PSi3Prii+qS+Tp35T3rXHGRUTB/NQCU&#10;jR6GgjgpyPESAAWAnRvWce3azHma6Xorqw+dHavpLkIociz/4FR3r1u76Re/ymA6IxQV9TE1sfHj&#10;Bs86VGwsSf3XhLoUjBeUTz19Tv+bvx0GRQ65UMhLWVPw5S8e9csf95gyw1hrqV4cO1//vTVgrKhh&#10;1mHH/fwXBcefALFWU2Qq2zchrC6b/IN7+x95RMxohx5LEB//2c83V1cZZiyu89C0t7z857/Anh3p&#10;Udoc2wqFVDb2D4cMQOYOjdLT+/dfeCH53nv58juKqqvZ2BtQ6ViGQDrwZFF9wGBv8lD3Uqgqtq1f&#10;U5C5JdRp/YCQ0n3KJMtYKN5orgd96FOrXvxLbPO7RjMm90pVRyTBQWefFqus8upiDv+C5y6A0jnx&#10;iMVGnXxq4y3XWMayvfXJGVt70dcPu+WGkl4DlN4JABE1nZAAQFp4I7ZkyNBDb/tO0ZmntRrDLKdG&#10;XUX5+Pt+0Hjk0VaoxnTAaVDjfcnAQXVnneoyuU9VFTQqbc89987iv6bgFDlXzxAJCspqD5uVue8E&#10;46GAbt60fcM7+TpuEk9UjxzuOtyV8bEtQXoPMAgvLOvdT1yQdpVzCa+q3m19fUlGe+TpqElBj8EH&#10;QCSg0BiT29QWW5vX/eq3DmEG96kaiAF12MAh0w8xNghMIOZfm2+mhTEUEcQSBWOP+6wMGUhmZQW0&#10;MFADlyhuuP66GRd+K17Z3RiJibXpTmjmIrf+8e8F0wl5Iyzo3vOQK6/sfuGFzoqQlnBGTObypOkR&#10;NWtixYfN7j99Omx6aqEjz4Q0Vmxi1AnHhcXF6TvuBR18u/SgeufDWFu44k9/ts4pRDW3HUEkjNSP&#10;Hecz2E+tIgrr3HvrVkO9wgMeOVY/NfGiocO1fSVubiMAprVzybIedTD0yHVvOAmGyXdfXJAplY+0&#10;tItRmIY+lQ298tToqNtWLN85/zkBM9hLnhKFSv85p8Zqaj/M4v8C8QNwgCfh/Eu/+HHr0qWEZiNI&#10;SplUKijsf/O3m+aeaQoL91nOLiNP7aFaUXHghed3u/TyNmudIO41zFD2Oy3q56le/c4HHlr66KMK&#10;+ExINaloTf/hlV/4tDK9Zztjb5eKDb95IPXuJiiM5lReRRRK1g4Z5IN45uYAlIBRvvvWEtVw3/Lh&#10;XJ/PysY+HTd/8q+dP1CS5aVF1TVKr141t0IB6jX57nt7//rXTGkYftD9VnngNFtZkweT4b0Pw9XP&#10;PhNvayUkg0V1A2mtrR52yGGQju3rTCunedVkav2LL6z/9g3inMlOF4RIYtD114499RQTlAiF7GKb&#10;CSi0NLHCyhlnn939gq+DsaTJmB5Zu36dwvuwsLVlwaVX7F25wkM7SC8KD3VhIjHsc59piVmIiCKD&#10;JR67cuXaRa+A3uV4lFwVMCX1vTBwQMZ+JBVUqt/x4ktoa9N0sTDHp1SkrL4HhB1sb/1XCABAKGp7&#10;1RdXVlOVORcKFnLnxs3m3W2ZXD+p6onuTROFeRCAIxm2tq76zYMOLh2LZPBpdfvK5wv69GEmqm9G&#10;kdz+/gvXXqstLXHvwywU9JyYnldfOvaUk8QWqnVdcVOXwT696LKiA//t/MLTT2oXccnUIyKshxck&#10;ReMrVzx7+/elOfQdPoJGLcXXj51QMHVKZt8sgZhi9RNPSxhKDoclFPAgQFNc1m3q5Ax+HQW8yO7X&#10;X2/d8b5oHipSChTUVKMg0UHPQj7+4RNHY8jK4SOYKBIJjMm1ZkKobvvG1d479RmLvBTU/8/ed8fJ&#10;dZVnP+977p3ZXrTqxSoustwbNtiOG+0DDCZACAkkgYBtesJHIJB8CV8KCSkfKZAEktBCC6GZYmPj&#10;iptcsWU1q1iSJa2kXW3fmdmdufe8z/fHnTUmCcTaOXvHtnztP0A/a2bOuee89XmfR9z8E0/IN94k&#10;6Q2EcXjbRr/+Hk0JS324+YPUydpXvCKKWqSxIJQAaJbWHvzyF+ymW1wtSYMmfi6jOYminve8/QXv&#10;eHfU0e0iuKdfrf8punNRiVVVXdTVe9kffCR6xcvpYoiauBmCugb2ymCAGtQgaTr66c9uu/XaNE0J&#10;AEbMxiAJFCqxRHFn9wlverOqmEQBsxYPO/DNa8pDh/KEzgugIgQijRad/zxKneRPG18PgdS7QwPj&#10;h/Z5EcAzXzegRE9vny5a1KAB1FmYLIA0th9/XLOIwRwwtPMxRwAWUBw5mdczf/kyy3VRmfgwvCb7&#10;HnjQJUnwCxCdd87SU041ijXWpBLQg+Nbt237+N/MRciTqazEL3/ZRR/8nai9w+zpyj56hNvmRNoW&#10;Lbjsox9LT1hrUufbiQPx7dR1yqz2wF/+nQ0NZuSkjfLDiBx3wbm+dx7gJZyurwfi/kMHN27yyLVZ&#10;mvGGeZW+1WtMJetthDpb4m20/yDMmtGgora0tR5/XINX8YhfsIqIQFQ7jlmOJnGfSFKb2LQ1Qkjd&#10;aRO4U05qW7gwb4JvEQCslA9cd4OEv9kBdAAAIABJREFUNqxeZOWv/HLU08cZiuQGsi7ztcq9X/h8&#10;++DAXOxDLK5y/AmX/vFHWhctV1XnnpGx/39/YeC615107p//Sa29sxUOQBKIbycjuFag5e57N1zz&#10;TalNG32DBNUEWleu7P3F1wAh52CUiL3vv/MutVwdAGECAta74pja/Hlwro5jDLMoju1+3IVEzh5J&#10;mhkV2085SXPOAAQAaETn0sXNqs+yVh3duFkZEoJCkSUveL61tIJ5M5uCqBwcHLvzruAfbq0tqy+4&#10;AOIoJnSzMweov3EO3Pfw4L/+i80NkrscubP/6A971p0u8mxTZzdRER5/6YuWvf+9FXUaFDllKs7i&#10;FH7L3/zd5P69JAnRBoocAqgrHnv55RRYQP4cwoT7r7+BE6Vc7b8w+/a2+QvbT1mX0gLWqxWY2Laj&#10;WV0qU9exYrlqvg7Akx4wjbp6FzzZG+W58tLYqN+9K0XIiyTggnUnRxIj77qWgujf/EhLuItRZ8CP&#10;XOtlly484aRINYKbxbI8kMC8pSnNTVce+td/bqlUEJAfSQTORU68i+a/8+qTXnkFYoE0kVF/Lt6u&#10;OkGkznW0X3j12wu/8HwRDZi5ijcygbeWx3Y/fM03vc+mJBsr94muOOOM2orlGm7OQwGA3LR1eN+e&#10;mRKV2ZyjB0XgnDjVSAstC19woUrGoR/GYBEYe+TH3ldmiNxzrRw4le6lKy1vKgiBUtJC3NLT2yxo&#10;duXwYSlPhcXepiLzli+HAMiZ4AketUP3PhCw6k0BSKWufM3lWig08NsspgidMz340EPj3/iOgQE7&#10;/iZSMCYCnHDC+e98e9JaUFpTJVXm9inOX3DWh38vLbaEHp4gACEf+8Q/T+/bLeDssr2fvHeiddH8&#10;Zb94hQRKsgXwisiAJDm0cRPrJGqa8/RQz/HHsd4gCZbalHc9XhubyN8QZoWstnnzkvzpoJVI+3pb&#10;uzqaVACyiYFBlyZh9zzpaO9cvoQw5NukstSzNH74ppsD75FiqlBcftY50IaqAaAkSp9UHvrqvxen&#10;p5yJhasLOEoirLrCaR/6YPeaEwoSKZw+E4GfT/HiaLzmoosXXn015gZq3LGvf/MPf2C+mjSWpYlT&#10;iwsrLrnEB9L6JkBREVHjobvXS1JjXcU7x3et0r1qpQk80lCIHQGikdHK0AiYOx6GJNExrytpTLdc&#10;Z7fs1qWL47bW5th/oHzooJsxUKHQFMXly1oX9BHIX9tgct+ByqObA8a9AqSK+IxTF6w6rpEdyvRw&#10;IvqxLVuHvvIfgCXiJJAMXsYnQqD9ZS894ZWXi6hQEtVnrfkHKGQhPvttV1WXLJ2Lz09hOz/12enh&#10;YdfYGfaA87Lo5JOT7s5g4TfhBUIO3vqjdGJC8maFBiFdS5dYIaaQ4YoHUZJODA0zf2VowkQK3Z1o&#10;b8vbAXiR9pWrpKUlb8MPZpD50f37DAKYMhiaouOUM+LWbogq4zyXZcCh3TuL5SQg4sJEC94tfcVL&#10;tb29oW0hTOk9t99wQ8v4mJk5pgyk7kRIopFF0dnveEfc1ZOJE8eAPHs9gImA6Dnh2BPedXXqdEZP&#10;IZjmjxh047Y96++1BjMAmoh0LF/RduEFmY3QAObKwyiAPLZraO9OCMhcsfMC9szrs6XLo3BdpowD&#10;pzxy0OBzjh0piIi2rj7X05uvAyAIdCxblnOzjjNvUbwvb9vpLOMqYagP7z5pLerhZ84C1jbwyKZM&#10;6yfYZxKJuuVnnsHGUviIIoQND+z8ytck/F2lwqJXvvqY857nn3XIn//+snmo0KLolNf+YrriGJcB&#10;qiTYBVHQId3+tW9K0pCTVkqqdC5a+aJLLSwqi3SpH927DzATyZduXbStve2E4zKp04CVmJG9+4U+&#10;f7VUAq61tbh4Ua4OQEWpWli0QDXXSFkEhIDG6lR5x2MzXP2BHIBI75qVqJvLfEPQ2vTQ+vVhIa2q&#10;rtbbNX/tugYFbbyAsD0P3IetW+YkItb4eW99q+vsivAsLvw82QJlJTV0rTn+2Ldf5dWJhmQ6SkW8&#10;cuy6a4cf29FQcE0SXiRafMZpaaQM6gOENvzIRpgPhsZ/6ufNuZ7TTpy54MFMx/T+fmEq+S4nY8Fh&#10;FLWvXJEzHTRN0L5gHvMueWUjyKyVJ6uHDlFDcpASaFu8wM/kN3k+U+OjpQ2PxBYSc21kzzlndSxb&#10;1uBHCkxTv+eHtxbn5mUXL7lk8XnnECHX/jQvAgEOAlM96fLLqz29QWvHooTzLqqUdt99dyPjLF4Z&#10;GSE6f9Ua39dnoUdjDt7/gPgkf7AXo6hr1fLAR02k8thusAkidYRQpGPFslzpoD3UMS3OW5Q37pUC&#10;pCZRuTLpR4bE6kQQDVo4zcYdo7izry875z6/FZFkaWBYDw+nELVwYbBw/vkXuKio2qi9Kg0eOPCt&#10;b4d0iypOxFSpbu2vv6HQ060qepRkAOIyPQMn0nvscQte/xqBDxjGePHC1Bn3fOsbvlLyJLOpgCN8&#10;InGqBXXStnBZzwvOj0S8RAEz4+mHH5kaGxGYSb6Qa2rX8jUGH3CW0Rkn9+zhVM1yRQ8SNBWoqOvr&#10;y7UElHmelo52yfvyZKU7JhOTWkvCbSREJW1va+mZJxCALtc5AI7073XeZ+3BUMfSgPknr6Nqg4G1&#10;wR/YuLHl4OGAF4ZQg8RCrli+5oLzlS49Oqz/f7EceuKrX2Eah/St2WCVaOmue8b27BJjKtaQuJDT&#10;vuedQ0VYCTZ/eLg0ONiMfj87e3oYeP6AyeGhWqnMudHG+DlGOEOCtvX15ZoBEGaCtq52Y850XfWe&#10;b3lkxCHYVpvASJvf29E9T6EmzG2qWUSEGN39mINQJCC1deLi3lXHNA5NFvqDd97lgpI/kDAIRRf8&#10;0utaVqzMmKXk2Tv89bPrNW7ZOc/D2WcxXPkrGw4S71tLlf6Nj9BSaazQLuoWrDs5EXH1exEIOun9&#10;WP8h5P7eHbS1r8fiQsBsRgA3MTFVqeTrzrL+uVGlpaenkWLMLF4ARZ1ra22GTIeQNj1ZqiNSAl0c&#10;EWlbulRaWusi1nm6cfOTO3dIJmwWronE+fM6Fy8SNCro4SdLe6+/IZWAxSkoKEBVojUvenGkEdVc&#10;lt0dXQ9FxHX1rbjilWFHiGaANTxwx11G79iYXRKZt2JFqk5Cae/VoZMy0d9PGvJuJLK1qxNdHaF2&#10;PGvgRNO1WqmUMwqIAhCmEjcG9dYjXbCIsliM21rzhXBRQBFRojo6pj7MwXEQRUyRrrXHSxwjEoeI&#10;cx+VEDB4evq0Or5hoxGxTwNSULSeeFJbnampobWM7zvIrVsdJGLAiMkoJiuXLzvlZKgqVHD02X+I&#10;qcDJ6gsvStUFRIICMECI0RtvSsbGhI02mTuXLkTP/BnEdRhaCDFO7tplNM0XOWNAsbXLz59nEkpE&#10;BDSAqIyN5HyAFACc0FrbW59QOJBZfs6ROr2WlpZCUZsxsaNEZWwsGIQLIqCQxSWL883g6mPwViqV&#10;9+wT0oCAOsC9p58K1cxrNvIjB/fskjRRhkS4GeAMi1/yosKCPhzFjxKA9B23StYcOxc5Z7qvf2zv&#10;fkqjWWBrd1fxuNWhrP+MDeH4zp3ifc7TsyIiLa1tSxYHzDwIKFktTzUlj1RK3NrKBjSz9UhXCxJt&#10;bYWWVsl96oGgiE2PT4SqmmYqtyALPT2i+ZUjs3EzAydHRzA0IgwJiaZI94nHaRQ1WM6i94c3PuJ8&#10;PfcPlwIIxC244ELGMY7uR6Dx/N75L7xsLkoHcepHd+9Ew+U1FuLu0096UoIRJnqdeHQ7pqby5tEX&#10;YRy1LV0SMNoTUQWTcgWW61pImEBFopY2qJv1imZj9Vx7hxZa8l1wvb4mxnRsLOSJAJy6jvnz853/&#10;qgdU0xPjMjX9pJAwzNN5zFLfMMCc3g88cH8LNFUIwwxtCqBAtRgvOnmd2FEJ/vkpVw2VwpJzzwm+&#10;E4SIyNDOnTBr8FyZaOexq7I5zGC3jrTDQ7XSJJG37pupa1u2NGj/UoSYHp/Mea6NEBPC4FrbEM2e&#10;nktncWrR1WGFYs7AjYyZ0sjk0OGA5YiMfTju6hNRQU59HA9REILpkdGInmDjMnWKOrkiVTu7ekzh&#10;6qxtR3ZxjTCm3ls6OVJ5+KGqmXoPhsnWCZiILF/au2zJUYj8+el7pEIxkQXHH5dEERQBm+ECik9H&#10;N2yir1mDdMHquhctN6GG02f2YDQ+VimN50wnI4KYcN19ioBa4uYh06Uxk1xZhJ0wsyFxpCy2sBG7&#10;caRPoa0td96L+rkW2vTEeNBSDDyZM7OpzJQOpycnQs7AEgRSpy29va7uEWafbU0ODevA4RgioRUS&#10;uk8/rdjRiaM7Acg22QSdS5awd15GaxgypxYZfuQRK5cbjHYF2to3L/zUZ5KkpUrORkQAQls62hkU&#10;wk5BOlnO+TjPHBWJXGSFGMi40XLIAMiWzs7m4DZIS2u1ibFwKC4j4KHFYjHf1B+AiHF6dFRC9tYg&#10;Imlne0t7hxg8DTxiRy2SJbUsDxzWakIaEbRFQXSdcRriohzVCUBdw0Ulal+wqHjsGooYGLA2TVAP&#10;HiyPjTR6vAztPV0GYbhJV4EoWJko05j3rqu2dnXNIjP+mWshAPjydO49UQoEUC20sFisn5wj/wlH&#10;jgISae3sDDgVcmSr9mlaqYQLwSgAFXHeDcmMx4jVicmwEYEB0tVV7OjMqFI5y6MFApNjYxR6BK5t&#10;imjfqlWmzmDAUUIB9DMLNQ6ihdaeU9alCDwLYkRcLk1PjLHRc6VxZ6eJCwqTExDT5XLuZUAS4trb&#10;GDTqIoByRfI+zAIIBVFcYBxlhB95ZABCYXtL6OHwp2aWRMTgK+VAGgCSDYUbELfnWQLKGqpMxU9N&#10;jgcsAZlAVQu9fdraIU4jiY48/c/mLVSAqYHByGZ+bsg6lbTMW6xQoeAoLgMpIFARiNO2VWtEFBCG&#10;48ZRQIyl0bEGOfdVUGjrlNbWgEUTpdHEyhOUnJvA6gTSVgwoDE/QmdjkGH2uPQDJkg+hFGItthKz&#10;VLufzRwA4giSM5FHXQ5AzJCkgT/XibicIxHJrKpNlsKeCTMrdneLa3S2SATl0eE50AAQ77Stpzvz&#10;M3juAQC0z58fng6PEGCqNNU4H0ixWLDWlrBHQYG0Vs17EhgA4AoFhBxqIIC0Vm3GcZ5B+kVOnmyf&#10;59QBmIgUCs26vZZ6SZLAnxlpVGgCJl0JXyqHC6zr/qzQ0yWN1dcJKlgL6pyeeLxzLd2dxqbc/adn&#10;LiDtfX3MxpTClURUREibnGocXuwKBQsq/0eBENXKVFPaQMUoltA8NtPlcpPKmSKiWixkLAmz88RH&#10;ngFEzaLvpZkx9QFlAABAlc1QohWjVWuB1wIUOjsaiG9m6j3eo1yZi03RONaWgoQVGXmGP669Izw1&#10;JqGUZLLcYAmINIliFgoBX1jWAUtmJmCaETYHDj98kjQjoiFJiGTaojIrINCsFOWjGCToEQ4a/BRq&#10;EgJ6M08LpSdNZKRcInmrm4EmhFg6NRXq1CiV2Wo62p+cnx1xE2AG95lOTM7BiWaqEOecehzdcwBP&#10;Pg5RFAFmDNlYy4jWqtOlBmM1FWVUcMVYTRDMyImJWZrkrgkGo6hzYYmMTSieOcfEAkDEAXQSxdGs&#10;r9NsYKDSHATfHJijJ4rczSpHz8WaQnJahN8XiaLIRTjKAUA57LkgiPZhFmNmE1t82h/+Zp1qNrWg&#10;KQ2sbDYwUOatBPCsveo6F83nMG9nrti+abTnjP9/MoRBqdbC2rqZYxBQvr7J7pVg+BYmm9jUamg1&#10;OrsT27z3J0+v+9HQt3JOghEL4gCoLpqTN23efArgOQzQT98oCXy7CADqIjZ+Ws3gbU4GndiUvX62&#10;4c9os1/SkaOASCSJAcy/hiuAOBcVAn4cQHijT3J9YawTNWhLHFAHWAUU+MlylpHOjg1OYACFRGfb&#10;XKxdafRJSvH0eO4BACS1GsRBQ8Y3AieQYqGlwb4CIZYmVk0sJHKSStVCUfOeJYKCMG8hG9oioBQK&#10;eR8aAhmBmCFN01lLWc2iBASkabPCZ1FhFLbzLDBamrsxohAatbYx2OfVZ8OrY+M/IQqZdUgWOe3q&#10;npN1V6usNIU8/ekb/ftKhTQhnIU8XxRGXR2NdieFltSkWg1uq3Mm4PqJ2fReA1sQuDiGahNWQ4L0&#10;aYrZdjNn0wS2JFVrTh4VRRGD1s0FdN6bz7erUSfuUG1rC8ZKSBopkHRsQrw9kQTMKi0SQlvaWucC&#10;pBGlaWViUiEqz6GA6m9ufHBASBgD0u4ZDALX1d4g4yaNSW1ap6fC3ncChbaWnOHXJEkktTTgAHK2&#10;gGJ7W86IJkrGZQAafbWWnx6AAKwl0qw+gFMJxtsz4zSNzDsDIAATcR2dQUkWoGRtdJyJb6xiK4R0&#10;Llw4F0megqU6A9JzXYD6MawOj2jdagcMMgigvaujQTFfEanVajo9JeEIdLJsNWpvyR8GSoBJomG3&#10;mYgKReZrEjMyQRHASO+fMGY84vt4xC9PrDxlEOZevwMhToudnUEFCmnGWqWcY0Mqc94SQQrdnaF4&#10;dhyhBqOl4yM2PQlvZuls0GkGI8V8y4L5NvNzA95TRykPHORRzwQHmsGnRkuT8s7thHllwElggXiN&#10;2rq6tbEDRkNSKqNaC4hyETgRRIX2nEVUMv6pWmWKIacQhSKus1vomnGI1JKaVqsy20RvFn+L1cnJ&#10;JmGeBM5pW3vY9E2BtJZvE7jeoJW2nu5wn1mP1zgxUS5NUjHLlqIgY83tnDffZjL0gJJVhIzv3uP8&#10;0d4BzqZpBLBqZWzzVlefvwt5rZLenvae3kbviGB6sgTzQTM2mkhre1vuSaAI6CvlgI6n3nptb4Xm&#10;rG3ATEjKpzVUq8QsscRHngGA1clJmke+cm5CUITq4u6ecC18BRAB01NT+S4FAL1IoWcegykTZeU5&#10;amWqOjaWBZOzUBnhjPpy28IF1c42qIYl7RTByAMPsXq094EJGsXMSocH092PG80hLMOK6MqVxd55&#10;DQ90sDw65gQhsxMyFWnp7kDeZROBWXl8MqQiWMbK39GWOxm0ABS1tFZFtYqMTjyfQbC0XIb5/FN4&#10;AtCopeGg5j9nACK+XGmCCRBp6+wIWFfNVuSI8sSYgSI6mxKQAKCRHX190fLlJlDCMeQlnNq8dXpi&#10;HHZ0iwFQDCLC8QP9WprwGnosRLDgzLNYbGmUC0isPDCoQYs1FFhLMe5sh+ReN6clpVLYDABAlLsD&#10;qMeRpPeJJEl+GYAYbXxSkhT5inpTAJgChfnBHIDWd41T40OWSV/l5daMAkN773xzEUS9Noqqkhlc&#10;sJiVRw6qGQHSHaFREYFTiaLIudaOvnPPjwmvcUgEiHkePDC8/wCPei4gAdVz4NFtLk3VgzRYQHiK&#10;9Kw7CS5qkLjFjBN7H08JH07zVkV9T097a0/OPQCh94Jk9LBosIuuEAXbOudpvmsxywyY1Ixaq2FG&#10;ZmTuS0AqnJry1an8caACUJyErJtn9t9KI6N5djWEzGBUhe7OtKMNgSM/jO7ZPwPTamBRogvOPKOm&#10;4ow+qFRhlKSDmzZ7pjiKH9YPQjJw971zMQ+VkPPXHucoDdolTdPx7dsFISMjA+PFC+O6sGCej6qx&#10;cuBQYEUwQaGrI297KJkgDKwyBT/7q3Tkk8AApiq12nTOsKf6nJNIW3dPKF9LhUIpSPJ1ABARoRN0&#10;9PZg4XwINGDkR5Y27zBvAtEGDqU4XXDSukREhRY0Wldi4PbbXVJ9LgOYPnxw7PY75yLtTDra+45d&#10;BcIaO9hWmZrcuBlHnEr+fOcn3evWotgizH0OIEnL+w8EvOskTVBsb83dATAD5vpyBQ3wI8/mYstU&#10;pTo93YT7AvFAW3d3qLOYiaYTmNq3L08+P5vRdHZt7d1rVmWsGgG/fnTjZsuywoZqrLJg5Qrp7LR6&#10;cVpCvUUKD950y9ShoaPb+kOAwe07/P59cwGGaTtlXdeSJSaNUkyXx8as/4BkfOyhjKZK97GrLcof&#10;Nymcmp46eAhBhxANaOtqz30tBsIEU+VKI5D8I94IR7iklk6V8oZwZSqCwnjePKjIzDhJg6Go0Iwo&#10;79iFpAZvwjrBxpw+DiKIRAVRS+dpZzqIIQ7YaK3t2lkZGvZiDa6lc+mytuc/z6tFDNjzFwEKhwb2&#10;btgATzPzTSbTbc5jRqbprh/dXvA+1NYK1EEBNdFFL3mRtrZrBrk/4h9HWAYH4+TBQ3Fp0iRwE7h7&#10;5bGAeuQ9gV8uj7jRUbWAQEJC40Jnb8720KBASrJWnXIzkV4eXEAA4JmUp5syx+lEWzs6GDIbhQBT&#10;hwZ8pWSgz1mnSqR79WqqCBiQpFAmSxP9+xsHFfpCvPIlL1GG35SYtvP661JfNVHN8MxH3cPpocHH&#10;v35NHNS01jSL1XXZ2WdRM+XuWd1xFRN4cGTPbsETaJ0wPzWldS5bqnnrihBgbaIk4XRYs3AmKRbj&#10;tnbkXRLPmNGYTEw08lZmVQICK5PlnK+sZSJHxvZ5vSYIlZJaNmEwPFIaG4EocsElMCMlAUS1Z/Uq&#10;LxQx02BWMEr90M6d8A3HOeKWnHtuGkUBOVsEogJPP/KtayZ37TCfCngUkkIY/O5717sdOxMEQ9dk&#10;BHAKnVo8f8kppwuUnBWwSOsQQ/E2uGEDjQ4SsMbtC3HPsiUC5ssoI0aWDw9HPg1qrIW9Pe0dHflS&#10;m1ABUXWUyuhoIwzws+ECEqI6Wc59iKPeBS50dqG1JfujBk0mZ1ZUmKpWRsdI5GOMMvBD5gV6li5N&#10;1QFmEqrOLhFkcOMjjRdWItOF69a5k9dpIH+bybEKxYvEh4d33HpzLJ5yNCYAOl3b9rVvt6SphJyx&#10;QGRQoPcVL2lfvDwr28zi423GXmK6Onj7HZIFLeEMnFu8uG3h/PypQEhWxsaVDDkHQEZ9fVFHR87L&#10;kRkE4/TwSM4ZgBFaHTto+RZunUAB07Stp8v6+rLSpjR+YzKT5NPKyLAoQbVc8Oky8/QsXJgsWwqI&#10;s1DYZKbAoZtuSScrjcHKCUXU2bnil17jRYOAvrIzm9IiT6Hf/pl/qxw+7Kl2dKQAJD1oNNIGNj4y&#10;fu21pk7hwhkFKF3N8YSXvsoViupUBbMgzxWaR2LGsQO7082blSQ9GSxw7jzr7NauHooQufaBlRzd&#10;/7hHyD4fFV3HHi+FQu5MEELCYMngQEN7cuSHQwBUDg83hRBUROPW9pbly82TEmwWTYCJ/oPCLDbP&#10;dV1Rd+e8s880kYBTkRHgd+4c3bOzsbRdvAISH/PCi33s5uJ4yyNbdt/6I0MiR4cHoJgSqahPph/+&#10;2n+0TVUMtHCRtUES9cmSxcecc0aDFRuhmHBw5w5XroTt0VOw4OyzqBGFmnPdnH5yz57QmoLSsWY1&#10;NMrfGgog3pf7D+WaAZAAMdV/WCzXDj6RlSEd4kLn2uNmpM/DvE0lx7fvYuKZP0lxsTj/vOd5IOgg&#10;Alsr1cHtm9kY55qjOOrSk08rXnbpXJxv9cmP/+lTHBpMcdSoTNOYJIMbHj78uS+ITwELqLAd0alg&#10;6Rve2LF0RYO2xYlT+oH7HlQLXBQ1yPxTTkI99s/XbCbVsYcelsAOjW0rlkLzhrQSBGnT1fLj+xpZ&#10;zpE6gKz9isn+A/RNmOQkhOra16wiIIRjMHD66JZHM0go8mUqNuriU0+yoImHB4vk3jvvbBDuRkDU&#10;o6Xz2De+3s/BnIuDyN33brvuJrUUTbAHTTi+BouT5OEvfiWenKypCukCOb8MGJ1GhbWvfnmj6lQC&#10;UtLJ8r7rfhj8nbBY6Fu9SuG0QTnzI3+qpcnqzl0zVYxQDh09yxZ55N/GEgBptZocPpxnCYhUU7Cy&#10;Zxdq1byXCyigqt3LV4qqBrP/IFDZunG6MuzE5kir/WevS+evWp12tkk4pTMHSdWGbrilOjJYpzci&#10;Z1H3FBGKONgJF11WO26NOHVw0GDlIKFFSB/+27+rHNjr6UlLQP8sdgKppIL+B+4f+PyXxbzzJuGq&#10;0QREEb3iJctPO020oYCCoIAj+3bZpq3Bzrk4EaFGft2J81asFkcgj34bn6SUUhqasMEhBCa20875&#10;C0TyhjIbUqpMlUZ1ZCRPBwBATJAMHK5Nlpt1jzoWLUnNgJCbnh4amDo8FLCs9JQvBrpWLO8486yA&#10;RRCCBkR7DxzcttUk44mdDYwn211T6Vi44Lh3vE2hXinhaDwNogZu2vTQl/9dvPfQmFA8azmCkkgw&#10;Wrrvk//QVinNiVFQOeM33ozWdi8NHWMx9Uj3P/TjKA0T5AlgwghCwbJLL5WW1mzqJc+6iYAT/fui&#10;TNggnK1Oi4X2+Qtklra04QxgbNwao7KfzY82oRsdq0xONukeSeeiRT6KELSYV5ieHtt3wIzMGZUu&#10;ai0dC154aSgMUAb9IxGntf6710uampnVVWhmEaQrJGJcPOXlr5hYsshC9qrr0mhFn+76f3974N57&#10;4D1Bk2dtQ9j56c3Xfrf6rWsC1v1/6mJe8ILjnn+BSNQoMyWJqan9192gFmxGIaMr8ILFLzhP4nim&#10;R51j1Gwc3vVYREKcC0huuGBBx/wFIsJ8A0eFgpwYGXWN9WJ1dvc2rqblsbFmXaS2+X3S3YmggyRK&#10;jO3dC0rOnlwBh3jZOWeJhgGSsU4MK56+/2vfSsYns7s3m53KAhsqqJ2rjj/26itBZ+HmNxVMVSGI&#10;R0bv+cu/TkeHAaAZ0nq5PBx/dOeWP/5jZ3NR/Baveuo7rsK8PmuYWpzC0T2Pj99ws0kYDjgCjpIK&#10;2FJctO5E1NWzmKsDoI1t36bGsBlA++rVrrsLuQ8zZqqCleFh51yD9ueIDWVkFLPKyGEiVw79n2x6&#10;z7x4zfERGZCDm4bRzZvIWs5CJQKqYPHak6fn9QWLdbIUwOg3bdr3yEPeSCazPPUZDZiAUXz2639l&#10;+pilDOcfvdH5lAal1a79wX2f/6xVqzTLqGgA4pmPDjIQ9Kn3yejQzX/1F9GuvWDCgIdMRARwBfei&#10;y9a+8OWRiKJRkgXPdM+9dxUSUiFyAAAgAElEQVRKFQk1myLIFG8K55w575hVM5FODsEWAXojU9p0&#10;ZfiuuyASWWrhzlXPWadBIyE037koMgUx2b8PzDsDkEzPdGL/gaaBNqK49/TTwuJSlDhw13qdnspZ&#10;2zOTcmxZvHDepReHTy/Mdt74Q2FCRA2Wbpxq+7ErT/7d/62ck0srsN1/+pd7brlZ6kcMASlIm/gI&#10;kcDRVx/6wr+lX/12RCYacgCKkFQUMc56328Xu7saVoEAAalM7/r6dwqWRqH8VL0+Iite9mK0FPLc&#10;/izVMIeJgUPT23bAzIOhxk4o6F57gmgTclYRJz4tP77PGntHR64HIPW/Nfn4PlqTArQ47jn1pFTA&#10;YOUIUdAe3T7ZfzBnaso65rTQsuLlLw5e/hby0Fe/NtW/T9Eo15xC1BXOePVr/AUvmBO7TMbl0bs/&#10;+HujWzZJmpp5e6II9YzOAEj4ZN9tt236k496m5pSb0AcrtEUQRy0801vPO6iixg55xrGaNEGtm6c&#10;uu32VOnDDVoCSJxbdv754vJ0ACBEBSTH9u4pTJRAWrgAhqJda1YbxZqRq1pSHd6wscHAbjYZQIYn&#10;mdi6DU1yAB6Yv3pV2AzAiMJk6fD+fsm7BJRVSN2ys8+0ttYnX5ggEYrbf2D3gw+KJY1SdwgJugWL&#10;zv7d96VxFBwq64jItLD90Vs+/Pulg4OOkGfFWIAQE49svOP9v9s+ORkZItPY6DUY2DUV2IKF5777&#10;fSi22pPTyln/YLOdN9xQTGqoUwCG6QEIIGuPXbru5Jynvk1EQAcObt/prF4uCUW97p3rXbI47FDq&#10;U9/TtFKp7nlcRXOdBFbzYGrk+JZNVi6bpd5nero5VoAg3cuXpVEcDpJCEQg4tGlTzr5cIQpxTuev&#10;Wdfy4hfCOYFqIOpFIdT8tq/9R1qtNviOBKLQ2MUnXPbS3ne+XeNCLNrowNGT7xLpaUyS9Lprb/6j&#10;36uNHbaUPk0MNPAZ5goIgt57835y7+4bPvDBaOtmeg9mAF0EBAExkhP+8EPzTl4L/UklYjYMXwZP&#10;MLXSwf17Pv9FmIHmEVAHAotf95pC93zRvA0l6byvDaxfnx0jbbgDQBER+Ej9sqXzFi5VmEjeyxJg&#10;fGhQhw6TvjH7c+QlIAMcwIMHJ0cOe6AJQ3CK7gULbNEiCViuEShl4J71tFpTjIYrFFe/+nKFy4wE&#10;g20Vp75/w8CDPw7DM0eiULzwXe9JTjxhylHmoFwmZPnzX7n9Y3+dloZUoxlM0zMs7CfEK6cHDtzw&#10;od/T2+8QyhzdEnfFFaf98i9rw5qiCnOEid95++3Yu09mAohQz5S61Redb87lDPPNDFwyNnJ4/X2B&#10;d97Yc+YZUVdnBkbM/4ROHh5GtdZgdHTkXEAZ4skYl8qlQwcE4lQl7xkIifv6ep93NsM1cwB64cRd&#10;66uHB5tjNVRXn/eCcncnhAFRgikY1aY3fvMbTKZCbLyISPvSxUtefEnRU+cG/KxMhz/+d7d+7C/T&#10;8UHx3rzPRDSfKfbfvJml1YP7fvDh3/ff+Ib6JFP9DL5XFFl3yUXW3SkSa2O1bS9mYunk6KbPfDb2&#10;HmZBjZrg9NNWnHqmQpT5gyz8xON7dM/ecOZHBApIz7lnsVCkQHNvAXiflvb3q7HB4Gg2MNAnHODk&#10;wCHNiEPyZvWDRfHCs88K1QQWggYvwMChod17mlR8lu5jVvVe/tJZkrj/jCcmQBn84ldHdmwL8rlM&#10;kgc+/6X+T32OmCNFDwEjk3Tk439/00f+pDo4EuXP0drg5RRU+/tv/NBHql/5Smb5CxQ/B5dEyIf/&#10;5M/23XgDzLw01FcQqCJ9fP19cvs92R0PSZgjOO4Nvyg9vSR8zsEiSPDQ5q3FcNxlQgDqRRavO1E1&#10;kzbOvwoiozt3uYa99GwygDqBCTmyazdpnj7ntaeEwPWdekrAANRHLBiF0r/lEfqU9ClyljyAFFvW&#10;XvFq75y6kEgFirWMlx75zjdtuuLNm9ksqqBG7+mrU+V7P/e5nf/7fYVK2XOONohgoh6S1EY/+U/X&#10;fvgDpX17vPdIE88043Yxe9rNBxjoYbU0TVM/uXPHd9/3/uqXvywGMe9pKfwcBUnFwcE733zlYz/8&#10;gRlpNLCG2Qwa0ywtlx/+whfUEj6hlNdoTgs6EY2qba1rLrkUrj60kOt7IZkke9ffEw78CYEpUx9H&#10;fSuOrVMUI3c2UF8de2SDAia5TwI/8Yxs2qI+BVVy58+h6IJjVqeFlnBlB6EgMj9w2x3mPemUsJwJ&#10;nlRWnXd2unp1Ei6j9KKOorRD//DZid27DJKIFztyEkAmltojX/7Szt95f5QXD6DS0i9/5bqr3zm+&#10;8WEPpxSKzySJnm4OQGhiCtjg/ff94K1Xyne/pzQ3082Zu2OUgm54eP2V73r8tusNKSDOw45cZpKQ&#10;vffcP/Wd72k4iKpBIiPhu1/20gXrTkklhiB3DQDWJkaHb/kRLdgXRxSv4o85pmfpkmadN06URjdv&#10;AZB3CejJz/gDD7NSlryH4JCpp3QuXeqPXRUwhDNCzCZuum2qf7+RGnZm/KmUa6DFxctW/dqvuXDo&#10;GkcQmFbvBgcf/I9vIqnGVH+Ejo0QX+XDX/zStvf+lqvUcut4CaDeJzf/8LpfeuNj37/G16qpqaRq&#10;8rSrCCWGdHp82ze+/sNffoPefZd5n2gMRnO9UxFRNBYP9d/xG1fuv/nmqbQkilkMM7I88eBnPhvV&#10;aj7c3ma2KY2itW94fdTaWawDHCxfW8HBbVtad+9FMMlVmIgJ5l1wvps3r1n2v3x4mHv3z7Rkm+QA&#10;uG//5NDhZsCAqCS7Ohf+wvkBbQ0gJuKGxwe2bXYwCjXfhXmBaOH4V76kVox/+oc18JnqvTL2KsC+&#10;f/jU6PZtgFCOoB5KAElt49e++uj7fstVEwkKDfwfv9oLCx5u9877fu037vrYx5KBfV7N2dMMFkQm&#10;Bw786I/+7MHfvLJ4oF8oCkb0AfH+P2eLDJpAWg8N3HLl1QO33wX4I260krvuXp986xoQjgH5tZgq&#10;9Ljjjzn/QgKgeZjLmTXHbN+PN6hPfLh1paKErDjv+XRxs07c2OChYjUBmuoAdLI0emC/iUm+LkBJ&#10;7xiLLjv/HBOlQJH15Ru6w0LCqJb23/2Akcwfd0IAWLT21O5feh1UVcScNnjExOA8SA9jy/DQ/f/2&#10;BatNafqU9srTJ5YmU1MPf/VLW97xrmhiEmY5T/9lErrifVwq7//on3/3197cf8ctVp1KzVJLaD6l&#10;GWZKHnP/wowkCSMM5i3xPq1MPPbDH3zrjW84+PGPt0xV4UkazZjPXhFCU+9hLO4/8KO3XLn39ptT&#10;75n9Q28/uyGQgjSk5qujww/+/d9aWouC8pR6kVSw6i1vbV0wXxWqGsMhX8ggp6cHbrqlJojCkZY5&#10;+tRh4bq1KrkjmuAJ72kj+3YYvBcq8p0D+Kn00+nwrj2OeSu6mogAom7h2hPpIkf4kIIM3Pvd69Kx&#10;YWsG+pyEj4unvOGXa5Ga0pG1YPeFIjL2T589eP+DT/GFGZ15v+UbX9v4nt+Jpqto0sOZTMiZT26/&#10;80evfMMtH/2j8q6dNBpVzOrM8kQOB3HmoIkJzddK2zfd/H/+z92v/RWsv6+QMdg1LzcRWEv/gR+9&#10;5T3999wOeDH10J+TnzsDxAzc9v3v1266pQAhQu6hF/O989de/kKTuEmsHhzr3zt5+91hi4ae1HkL&#10;e9asyv39AhAPwPzIpm0R2Tg7e0PWxdJ0ZONmSdOcQ+UZLRjpXXVcbdUKFTUJGq9v2TK8Y6vlngEo&#10;VBVUXX3u+a0vflFsTow+kE2RjJdmuvLA33/Cl0b+x8UR9LXJR7/2jc3veG9cGm06DpMACfUeleHh&#10;P/+ra17+ih9/5l+mD+xnamaWsGFE9FO9/FIVWjJV2r3j3n/4xA9efMXQ3/1DoTJZSC0DRTWxNqVm&#10;ar6wd8+P3nLVvnvugk0L5OdVy1S8sPL4rh//1V+1JDPY/3Dv2Wm88jff2nP8CQVtUtOe7N/wUOtk&#10;SeECRuviXM8ll7QsWiyS/x3Q1JtUpoZuu1toQqE0sQQkMnTXeqtVcw97hCI0FLr6Flx2EbPqT7if&#10;4Jjsuf8hZ8hZHEYEAGNQO7tOetubEi0kKo5h7iQBJZ1J+Tvf2Xzt9fA/ryhKgEm645rvbXjvu7Uy&#10;JYzwdHiIyOAMgEW7du15929/85VXPPhvn6vsPei8z8VfU5OpyvZt9/3jP17z0lf0f+D35NA+ZrQJ&#10;gBdAELFpPoCqDpHB4j27b3vrVf0P3K/8Of0Akqkk/oHPfaH46A6TLI0O+Pul2tZy0uuvoBabFT0w&#10;SfbdcDPhTULixkSw+JILnSsif/EiIladHBisbt8RpBfX2PQgrLrt0ckDB+dI4ehnlp4gESSK1BXi&#10;FRdd4tVFlHCvWMTw+Le/zXIp/2MrUFUnzh1/0YvcRedEgASEGNOIRGiP/ulHx3Zvr6VZjZg/Xfbx&#10;5lGbntp0zbcfvuod8egYmJJPE5lGMqvAEOrN0jTe8NDOq9/5rcsuuv0vPjr44wd8aTL1ifcpzTw9&#10;zWZOJjlDxGNAZrFJI+voeatz4Rjr/2WGpTeap/nUm09rtbHBvbf/6MY/+P1vX/bCx9//Qbdrl/cp&#10;vLk61NOUGX+ONS1X8pYwVe/FW/Gxx3701rfvv//uNE2MmUooSXjSm6Wkp6TG/ffes+9vPyE+zXZV&#10;2GiLXwVQ+EhUdOFvvGnhKac7SM5TGymMpJmV9u8Z+d61JMDEh7NRNZFFJ58oCuQNfzRTT8PY/j3R&#10;2LgYAWvwN2gDpgpOJCqVh/btb1rMI1hy6jqLCgyJ2KQX+vUPDG7b2jz6AUZdXSe+690mkrpg2U2G&#10;SBeSO3be+4//LLUS4f7TfacxRXXntddvePs7oskJPM2e//o+lBbv2z3wkY9ef/GLv/vGN2744ldH&#10;tmziVMlZdrw1Q8qwjpgzhUd9dp2AKVKBKaiss00IM/qhzGMwGZ8cfPC++z/16a+9+vW3vPTysf/3&#10;j50Dh/GzR0T49NgmM7Zs337jW9858NB9Yp5eUgiFQktV1ASefmTo7j/7s2KpkoaDu1FEGLWkqHUW&#10;z/zVNyQaa+6QLQeFiDHdu+FhHRkNbXKAY1bMP3aNWcDRgiM4/Aoe2r4tlL2LGvk1YojFhrduW3Xx&#10;xWiGKgIhXStW4ZR19uBDAa+e0Iq16t677lx0+ukotDbHs0l8wqUv2nTZJe7WOwAf8ACJNxWM/NOn&#10;Hrv4/GMvf7U+aeyYgE/9nuu/++BVby+Ojj1j5Lg8DGmxPD593fcfvfb7W1s74uc/f9mLX7jg9JMX&#10;LF/RuXgZOzpFxKlC9YlYgXWdEqnzDAlgJj5Bkqbl8mR//+CePYfuf/DAjTclmza2TFcj+Jg0QQKI&#10;ILbcJ+CP8KmK73h0221Xvuuyf/30/NNPi9EmDlApUhKk3qbu/+KXcNPN5hh7CWfLRCBwbt6Vb110&#10;5jk+ikHmPv8LAlKb3vP9H4gZg1aoCel98QvjvgUQ5N7xESEtTQ7f/1DzHQAAE4nIA/fe+7yrrmxS&#10;AoBiR+/Sl7304IMPB0wBYqIqtuvr3zrrN97imuMAYHDS03nWe991/+13RWlILhzJpvzT9OE/+OMl&#10;607tOnYt3Qz5flrbfdN191/9nsLYiIk8U/h3lDARBWMvnmrlKX/rrXtvvXW/6HRrix6zsvfEEztP&#10;XdexdGlbb29Lb0+h2NbSUi/gUqU2NVUtl6bGRqbHRscf2zP56M7xrVu5f29crQoBlZgmkDSb+jeN&#10;KFkV6em8J0KKaSKMtmy55cqrX/iv/7z4zOfVJ6gFHrXB9fc99tE/azWNmZo4BHJnQgC+3N1z4Rt/&#10;XeLWqN6c13zvDpSYPHDw8Hd/EAvDYtRNsPzSi1WLIpJzBQiEUNJSaeSu9XGgr27IAaiBwPj6u6oj&#10;Iy2LFzfp9usx51+0X/88DncjPVWA5P4fH9i8ceX5FyVqsalprjlO5ISIj73ohRuveKX/+jVefWwg&#10;ImMSJg8wb1seveWv//qVf/Vx6exQmjfsufW6+978tmhohE+bYsZTLTwQBBJYpsIrPqPUS4uTNWze&#10;WNq8sfRNmWGvE6jMiHiAALzPPmGmEMInz144q1eDXH1Tnhl5EUkhBQZBYfPWm9/xnsv+5ZMLTz4z&#10;cpEXq+4/dOsffKQ4Osa6eQyWzKQOjrLyPVctOOkUkaaIelJooOy8/654dPgJnmw2+qEA4KPIWlqX&#10;rzsFSoHmPP8EYQKM9+/j7l3BzGeD2+IF0f4DQ/seb1qjX7DolBNs0eI03MswIcAWpo/dckuCNGJk&#10;mjcthMGURHvHue96R7U9jkgvmqqFPE1ik1/40oZ//5KagbLnlhvWv+Xd0dAInmkP//s/4385KVTS&#10;0SJvUZK6JHFJEqdpTMbGiMR/Pyv0DNclI1Ky5aGHb3rbu4c2P2w0mZ6685OfaL37fpkDmiJnmD52&#10;5Rm/9iYfNQs5JmLCamn3178XhWv8EuoosfdtLzivd9UaSiSE5BsNGCnmB3c8FifBHHZjVBCgwKlP&#10;h3dsb5Y+sEJaFy1Z+PKXuXCxhgpEIOb3f/mryaEDSElSmPMCmQpV3fLzXrDg6reLi50hCgcw8UDR&#10;a+xrWz/8kf133LbrtpvufPNV8cABHAUPQRNmXNZGGmgCe/au15l5Jm0Pb/jhO39r+JEfb/j6f5T+&#10;9pOpJXNipFzxtA98sGP12kiaBh32YocefaRy/Y0+JK2FCITqllz+v9jePiOBku98A0XT9NBDG0LS&#10;dTTmaiWm1pQD6++F5U2eXN8TFUbx8pdeFkppKCuRK2mi0a7de+69l5I6hBRpeWoLcxkaX6LC8992&#10;VWnFchMIg60xplQUsYkbn7jz6nfc/da3dQ4OPRtEeJ/yK5aZFvAT//tZ6/CEhKawwn333/LGX9/6&#10;O+93c8RRJNBLLzzpilc7iZpI2CpMd910WzRdUQb7ERFIyLSLVp13vlMBPIU5nxolOF09cOPNrJ/i&#10;5mcAliKJUjt0y03J+IgHyTRnrhiBOWDFaWfXenplJtVvRBypHhUS9Kap3/ntbzGdAlzO3t4JIlGn&#10;sTrXc9zq037/g6KaBupCEPC02PuUFEtkx2Px3v7EkiZC2HMuGf23/z5rHyPM4FP4FFsf1cOjCX3A&#10;DqaKiEJdVGtrPe8Dv63zu2e2Ob8nJTy9Z2rmK0NDe/7t301C9n9TpYnFp5+8aM3xAlU4yX0MjMTw&#10;wcf9lg3yNMkATGBCBfyu3cN7dqmnieYeSwmAjmVL+l78Qv4kBAj26RPfvWHk0a1ivokWgi4+7dWv&#10;8b/4ysiexYWK556cnF/w6+cIIjbhsve8a/mFFzrLRqTyjY6FJk7ovEj/fff4HTtiIqASswcIWfma&#10;V1lPW7PeXSp+6NFt8VTVM1jE0lgJKEtFjIVqMrB1C5iAmnOphJkzbGk55lX/y6tk9Egh+UxKpS3X&#10;X2+WNBH0LZCoZ8HF73/f9Lx5guee556nl0dJFEq1k08596orXaFTJEqFLufh8fqkM12pvPUrXy+k&#10;KWgI54UiEYviYy64QJvX2xCmh+6+x5EBCVUb4wKaQQsKuP9HdyT0YnlXETKGPKFbfs6ZvqszwKr+&#10;8/nmvs98sTw4NPfU7j8ngyfJ+WeeddyHPmCizxmd556n0yNCtYhn/sn/LS5bRdBEnKnlK6YhIpFJ&#10;KunAlk0T37sehlRCahskIM86dcmpp7jmOQBMlvpvvjlsatVgD2AmCSAO33KbHxoS9So5v3gVERe5&#10;eSvXdr/qFaIqEpLSVgnZvfex22625uFEnCqcRq549q+/TV95uYsUElGeSwaee5qVkkJVTFUlgqqo&#10;9L33nSde9hKNYlWNRFShmuv59BDAtGZbvvf9uDwJmhoCDusV1B372l/Vjr688WIk4I0pwJHH92DL&#10;DiIkZ3ewcLKw7+Chx7Zb6Lm7I1hJHK955cuBKCwYSaix+S2f/SImx5uX+tXpTgvzei76yIdqixab&#10;piZ8zhI99zTlIZBSikYTb2J23jnPf/e7rS3S5qkhOBKQyp7H93/+C3MxsjMVRysveb5CTVzee10n&#10;P/b7Nz6iaRoZg8EBQzkAASLvD/34QXiPZkXKoqued9704kVhz6BXemV6x5271t9Ba1IjQABAnUPk&#10;Fp52xskf/WO62DVPju6557nHUapKFUVXz/kf/Uhh+UptioLSE/fUCNY23XhDfOjgXHx+4cKLFq1b&#10;pw2LsM+ixMFMdL1WPXjLbTCvQaerwzgAAils/7U3yHTStBQA0r5o+ZLXXSEAw2U2Eb3QFb3f8MUv&#10;sVplM4Yd7CdeANDCqa99Xfd73g5rrvrIz3BT//lPBHiuVDUXe9vkRwEhTKKVf/rh5RdcHKlBnTYP&#10;/K+U6aHDez796eDcowKY4Phfeh1bOr0yb/uWBX/G8uDg8A9vdGSiM4nB0yoDiKnT99w/sm8HfNMO&#10;gcXx2le9gi5iOAUiM8BSMz/9re/sue+u1GjwPl8i8Cd8vgAiTtq7Lv2t98hFF9BFUFXkjbzKvtEU&#10;CjgRlawTo1QHVcn+D5yIQhWqGWBaRVTAJ/373FOPn/7TtgiyUfR6AChqIpBs/1Sg5oTZrjYx4o4E&#10;GnW85VfP+9XfdHFrpLFKzhK5mJF6IADPdMsPrtctjypD0iZStCBxrW/+8b9wvtdU6TTfELAuQe3R&#10;v3WTOzRIUjK98qdbBmBAXJ468PBGatMAkyJu+VlnJM87y80BbUNcSzZ+4UtWK4lp/hTnT3phBki8&#10;ZMWFf/5nyZKFTmBCl6819QIAkUEAgxCOAlNzMICm8CKUzD4JIRnvAiACffL87XNP/dzyJ7mSQjLB&#10;Ya8EHCgKZoPoJiKiKlrwEmVY52Z5UYGQ+IUXXPTh/4OOnmblKJnxMhFPJqMjW/75XwxRWOZnCiFc&#10;+Poruo9Z7SQWIP8Kh5KQdP8ddzubqz0MYRRgzmzfjbeiNt2sixRBXOe8E970q3MUikx+7ZuDG36c&#10;Mck00VwooK5l6TnnnfM3H0ta2qk5K1fCxJSkc0nkxImPXaoKqEFNFEQMmFIEEak0R4hIIpY4iIg8&#10;wcQvIkc3lklmtkAgQggkFUIhqipqEREJBCpKBYWJ+FqEmlPvlE7RNK1dJMuXXvyxP2xbtTJyzXyD&#10;BMxMvN9+042F+x/IpgFCvh+gFMnaV13BllaHTF4z1z2niAmSseGB7147F83tKJxRENAGrruhcmiw&#10;c1Vnc9JS9fCFEy6+eGt3R+vIhIQu1LhqdcNnvrTk9HNcS1sTTQaAGIS6tZe/evBP9w2+/w8AIyS3&#10;4fsM4V0T4blnL3/ta5effEqho316uprWTOCT0mStVAKTytjE1GSZxtLOnSiVk6Gh2tBQMlWx8XFJ&#10;EkmTyOrhVMbdLPUbfaRpekN/62ft2s/ZTflpA/Q/1BB+RmhZZ5cVIZBEikKBUey6e9Da2rZ6tW9r&#10;6Tr+OLa2tXd0dvT0motaF8wXEY20rbW1OlXp37z58W9/J75rvTSDxCJtbT3zL/9i4Vm/EEEspGbp&#10;rG4lUD08svETn4zoYiY+nD+i0BmSU09Zdua5IhCYhyjzrbzRhDi8fSce3TEXLzoK9xqEEhUOH96/&#10;8eF1x6zyCqEIci0LkgK13mNPWPD615U//cUiamV1sYeFUtSijX7lK/vf/KYV556vcUGesAFNiIEE&#10;AhTaLnjzVTftOjD+T/8q3igJ6EQ853gYz4maQ/ub3vSS//uHnceshMzoamUbYcYZhn7JVGWypokn&#10;fZpMVcoTYz6pVsslq/rS+CSStDo+lkxVSsNDfmysMjiYHD48PTxSGx5hteomxlGraS1xGadZpmtJ&#10;qAiMKmD2LahrWrmsRvpE/CaZ+iM8NKODBkBxIBUQZMnTk2uqnMlK+EQT2xE/UV8Vzuw+ssXVW/RG&#10;FYFzZuYBUefjWCKXtrVLW7t2dbQumB/N6+tYuoTzerv75kWtnW29vSgUurp7tKCFjg4pFNu7ewrF&#10;VokcVOBcVuUnCRF90gAgyTUvevGZr3vtzX/wkekvfyUFCp71fZ9bzy8UUadrPvqnJ736NRIXBc20&#10;/img9KlPtt/8g//P3pvH2VVVaf/PWvucW3NmkkAQCEGUQUQFZbCV1lbbdujXtt/uX7c9vLaAqCiD&#10;oNKgAiKDMggOgHTb3Wqj7cgYEgJhCGEIUyBhzDxPlVRqrnvP2ev5/XGqQrBBBerWvZWs7yefgEXM&#10;PXefvdez19prr6UPPQwiYjj1kJBc7aB/+n+lieOLeObwtWf9o78jJbXymkcfUuZ1LQACIZjCVtxz&#10;9+s/9JFgJVMTjqh1DCIEYlp648c+Nv9HP85zBEKGr9tdIDAQn7zu36Yd/hZNSy+xIRxZjBbaWo87&#10;6yu3bm2PP/sfBXORBkNe5V0hgWz6jD//6pca9tobLximoYHYcQVo6OSaO37CUtLUNHbCRBGABkWM&#10;FkIgyWgiwmgiMJjkUSoZs6yrr5dZzHv78/7+rNLb3d0Vu3r6tm0b6O3LOrbnmzb3r13X1745dnZK&#10;V7f29maVqDBFVDKYFvH0oj/KkHGgIhY23CBKCsSGLrQDqqYCUHMZ3FMgFxJiEIYESRJbW6ylNYwd&#10;m0ye1DhpUsu0vUutLS3jxjWMH5uMH1dqamptGYuGhsbWFqShtbEpaWxiokhTUSGkyN8lcyOhASoB&#10;gUZCBFJEgooiNrpDxn7X26ZA06nT3v3Vs26ePz9ZudJElGEY+7q8nEMTTCf965ffesInZccGqIZ7&#10;f0ZCK+3ti79zZTXOZqlWGTdxxp+92yTUSucS0nq7Vv/mlhCrkoQ+fNeaGQ1IiE2/vrFy2umlKfsN&#10;xnpHdIsgAkLDvkcevfCYY3jvPCNzpQzTyEVhDvT9/Jcr/vETrz/u/VStbQg7CaqmyZQ9P/CNr9+8&#10;YVPjfffnMa9I1c9Xo+rED39wzN7TRf6ouwi6w1MSweBJlgJBQU1CUWibqYHQJAGhEKREM0mO5x4y&#10;WNCYEgMA0aJaqyrImAJ4X+0AACAASURBVJvlMEN5oL+3d2BgINvelfX19fT05OVyf/uWcldX37ZO&#10;dnX3rFxa3tKebdyC7l70dadmahbJLE0QEqYNobUljBsfxo9Lpk5pnLJHMnZi49i20pi25jFjwphx&#10;jU2NTS0tobkpbWlubGhoaG5FQ4MmgASGxESUJtCibrxqjqJ8/GDPDCnGwBBVtGhRL9KghApBGERC&#10;ITaUIUGV37fztZQoaam0z4wpH/zzbT+4GiZxJIpThqYT/vHoU09Om9rq4fDGEGnx2ZkzwxNPWBWm&#10;fYJk0t//w9gDDkykZn4OxTY9+2z20CNVCjwNmwAQBDSHhLXr1y98fO8/37sBajKiIyeAgZLnOmbs&#10;/p/6xyXz5gN5YjJclTyVTJFJnjx21Q/2O+KYpLUVYeSdwp2+LxFFhAPNrzvg/d+7ctYnj08efoTQ&#10;au8EAzH5zW9WSWOI+koEnoBBZTCxlUM/IwRiClCk2N4Kdtr87nh5TAwQkqLKCFOVUBKmQmFDS9PY&#10;ic0iHEykJIhIE0DMBGCMyPJyb2+lXKn09WXdPX29XSLW3Dq21NqWNDYmDaW0qUlKJU1KRqgWNbeU&#10;gKpi6KCdg8k3IpBcRMAgGoqmkUV3eiAgQIqfiEgcWh0QqIAAFdQi32conCQvJPq++IzipUhNTXMF&#10;obrHEW/dRlEwUwarqiWS9P9+/LhzztfxY+ulew51YM3K57916XCW/RwafwK5Jgf/9UeZNJpQa7TK&#10;hbb24cfSykDCkFXhnC8ZRmNUtGNNDcvmzN3nfR/MtVHjSMcIFappicCBx7130f77NCxbMZxpYQRA&#10;i1l+68xnZ9920Mf+SgICBTUq0CaiAQjSCJXxBx74/muunn38p3TRU6HKpUuVsaG5BYnqy0/Hl7sV&#10;ttNCepGVL4LqwE52cTARfiffbvAnAcAOn7xIN5X/9ddCkBSTLwCApEAjmtrGNL3o1IYv+bDhj/pC&#10;SF/0fEFenCAylKb/O1sEKXRu55/Jji/yBz9yMMamirQIyaRN4wghYrCqTEIKokgqIfk/H/ngt76V&#10;TtsrDOc9y1ezBoXIJQbTWMke+dl/Y8kyyrAVx1HRimpLtAFl04fev+db3xaE9qJ5OwKhXe6YDNbb&#10;veIXvzahiVXj9lFV3uT6395S3rQBQq1RuqQATVOn7H/ivwAhq0JVwiTaE9++tLxpk1DroJVIMVeS&#10;8Ycd8ifnfiUfwTEf2XwIqcJfVJOLysPyoVKdsfnfGzsNhI0Z96f/+uXGadMCRUiwhiVpaYIQQ1S2&#10;L3ly3RVXy3D3Hghkv5ipHvTP/yCNzRGiNqKTRIY2CAJuev7ZgYcfE0OVqmtX5UU2rdu4+tEFgRFa&#10;u0ChlA770EcHJk4M1XmI0sKFC2/4DfJyDfsE/E4IrnfN6vn/9tN0xMpW+02u3QAtjid6Oub/10/z&#10;ji3RoonUpCDKjoUdxQYkSn/Xoz/8N+1op0o6rBdhElpJgr7jyBnHvhshkVpcuRaA0ZjlK+bd15hV&#10;tGo3faqk5PnymbdLHlk7IyGQlv1nTDv+H6w6V/eMsuTii7c/+0xNd0M7LDH716ya8/nTw60z1e2y&#10;M5zryIAkUPp+cN3t37zIujsUWuSk1mSiGZjQRPLld9/b+aP/DmAwGVbzyCjIJBz46X9Ox42XGANp&#10;NdrHVnp6l//3LyIiRUJ1hrs6xiuy/Tc3daxcydodFqmKlhoP++u/zVrbTIVSVFQetu8rMW9Yv3He&#10;tVejvxtgBIwY4Y0RaRHI8kr3ypU3n3ZqNmumRgO9baQzjEuZxpx5jrzc9f2rZ19ySblzSxZzszwj&#10;DXkNvIGIrL39oUsvC/39MTdj5LC2So0qOPgNB73nzzVNQ5KIShjpJocxMs/zuPbxR2ThExIJWpX6&#10;kVRHAIRpx7YVDy6Q2jUZL7IuJr/xwHH/+LephQDJhjVcbyJKdP3H9SvunZuxKIAUR3pXRAWtvGHj&#10;zDPOtFtnJwaKR2acqiwmAImx+4rv3nHRJbFnay4hjYiwXEZ0wxEYDfGpn/8P5j1YFXFRUZPpn/5k&#10;w5S9auV0KUWYKOLSWbNCrHJCR3UGEQFY8T8/Z19PDX1XAfLG5rd84u+7W5uDJMNYgUyABGIaQmXg&#10;kYsvq2xYXUFuMtJ774pV+tesnnnGl+y3NzTkuZhZbUtEOru4N2ClWOm8/Ht3fesydmytxFyQJiMb&#10;AjXLtyx+/NmLL0mq05wjULIZ09/00Q+zdq0fc4UJezesWfeLX1R7MVfl5QkgTLK77tu85Oka7kgV&#10;AMNeb37LhH/4OCHBhq2YEoEoFGhC2P0PPPKj/1DLlDrCRdkqGzbO+tKXyzf8SoFcGIuBr/4zuI9R&#10;l4zA5LMoITHbdukVc799qfR1K2GwkTrqI4G8r+/BS69o2tg+7FmvMujZ48AvnFza63Whli+SAfmq&#10;hx9rXLuh2p9VHQEwjZKnA5Vn58zO8wGLmY240VAIoKWgobn1Hf/v+HJziuHN1zfCcotR87jiiivX&#10;P/wgIxGr7gPkzGnozys969bc+JUzKr++QXIaoxRFbjgSZwA2lKXsbSnrIT4jg8nx1TdMBsRIy5M8&#10;33rZ5XOvuCx2bkUGWjTkRqvOcQDJPMJoA3lWeeKW3/T84haDyfDFRgRiEoKIqJQPnPGmD31YpaRS&#10;s7M0MY39A8/+6ldS/UJj1REAIhgrki3/8c8r7dsIlVqWf5fJhx7a9i//FAgb5vvrg9+pqav30fMu&#10;KndssOrfCAuWREHe3j7rrLPDL25qNNauBZu7ArW2/bX76NS49eLL7vrOlVm5g0iEIVbr/EmiqJA5&#10;Sz3PPf3cVy9OYpk7qscOzzCKghVlFBx8yuca994zmFjtyj9ExPbnnuufNceGqh+OuhAQRYS0pueX&#10;Lp8/H1bLfFAA1tjyjn/65/6x40J1DLTEWL7zzgU/+k+t9FfdA0BW3rLxjrO/NvDzn0Wr9EmWUFKO&#10;bIXaF9fPdGoZ96nRi4hmSV7eeNG37/3u9/Pu9phXUlarI2RiAiDv3X7P5VfoquXC2EAZxn2PChIy&#10;pWaHHHzohz6CpDEG09oVO9I8WzLn9qbunhG4fjz8b0wACA2SMoFxyS9/IVl/RNVrFP++XbNg0qGH&#10;7XnS8VW6TWcIoK276NK198+vUgRmx9jlW7bcfvbZvT/5r5QIZDCkxmzEr1zn5bL7APVg/SsD/TUy&#10;VZZD0xg3nXfhvO9cmZd74lBBpGGf+QYTwzO//W3Xf/9cCELLytJw9kFlpjBJDj3j8417ThMWuUY1&#10;CwH1t29b+V8/zWQk0kqGXwAIGAlaZC5k9y23bXhmsVKldjG1oBoaGo74xCeyPSaKikowhQ7fujHk&#10;amBP97zzz+1ZuyLmeRxWHYiMOVGJ2cCmLbee+/WB/7pe82gxFoXUcgAjK64l6vonFmZZZpH5jjJo&#10;KIp0kuDORz588S/nD3tXL/yKhA2Vkit+QgNzRLPcImMcWLfwYYFysLXMSGoPlIaYJ5XK+gu/Pf8H&#10;P8x7O6INTnwyf40R+miMhggzMmO+6YnHnjj73IY8FyNpMqwXEDIBqPHYIw55319qKAVV0dIIN7gn&#10;o8EYjdFWPnRfeG4JkEQdhR7A73yvtFxZesscxIrUroJUETFsO2DG9FO/UFExiQ2UfLivbSUidv9D&#10;91/5fav0qA1rQJQhWMw72med//X8Rz9ppEXljrbEI29VM2XHzNsr7ZsBVQoMpETQBkVedlTYBzwp&#10;9bU401JMIxOA3BHtIVQYo+QDm7ZuvW0OGE1QwxvgpZhvOecb919zDfq7zQTGTKK8tstZAsmUaqJE&#10;7Ng67xvnN2/YbFKVb0mBqRx2yinJhHE1s1ECIUzFyn3P/uyXFEs4Er3Hwser/sVky4rlr//4R7Vt&#10;QqhRaSAbrO+YTt7ndc/ddrtu22pFN9Vhmk3FDTMxBmPPY4+XDn7D+DccOFi0cVgMrmWVzvY7zvvG&#10;wA+vY56VxYRSYg3Pfomt27YF2fuINyWNDYSSIiza1lJsqMtW0ePkdxe28wrMoKC4X25GJWTwtnm0&#10;sqh1dNx/2bezW2YCRXcE1OqkLUCJSu/c+7ePHzPt8IMhSSqK19bw2cCENEMeuxd8/4c9116XMQar&#10;yoYnhFL6Vx/9ky+cqk2ttQr9F30jLHLjIw8tO/s8xoqSfKFq+qgVgEQSdHfqm96y55vfpKq16Z9I&#10;gSATaWxpKo9v3nbDzECV4YubKGACUwRCgHUPPTLtPe9umTpNhknwbNv22y+4oO/qa2OR8sNQopjU&#10;TAEUMOXAgwuWL18elShXsnL/QFdHpbNLBsrW32/9fRiIkpugSI0lWPy+o86t0MXgZf1VwAxG5BFZ&#10;ZP+A9fRaT6d1b+/b2l7p2Nq9Yd36B+Y9cMmlnf/1X0VP5ZQaJdaq9i4lBArEtt19b1/bmL3ecriU&#10;ml6qvvUrWrKmVNKWzbzl6dNOZ0UCI4a3IP7Q41Wamo++6tLxBxxgCDXbpFIIaqws+OE1PfPmK8WU&#10;I5CHJNdX3VhIVODYo//Pb28ojZ+Yi5SKxntSg4UlwMDWzbf80z/ns24XViVvOYiY0D70oY9cc3XL&#10;1L0gUnRHfqVflyQMZUZ0dc385nkDV10LK4Na9MWtm4oPkgcxDWxogCCGkjQ2iKgEjUkpNDeFtpak&#10;uWn8G9+A5uaGPfYIra3j99yzYcyY5vETWiZOHDtuPJqamKQGJEKKKlCRHAipCVVoCIpdBg4KIQgl&#10;qUZTQTRKjt6+3q0dXe3tXVu39Gze0r9xc//mLdnmzduXL7fOTvT2SFZmNPT3wRgGMs0rStTNqcrQ&#10;fBSUm0ozLrroHSccr0lzSMREi+TrV+oMZzFTw7YlT836q79JnluC4e6FEkQqAYlJFIw79fMf+MaF&#10;2tBAaK0EILOoQOeSp2/40/c2bdgyYp+bVH/SC0F76OG1C+bv/4GPNOTKBDXppF58Xmnc2DeffspD&#10;c+9Oy1k1OmflAoGEmbPnX3nl+7/2dTa1QgSwV3rcUnRYi73dcy++cOCqH5YYK4OVLOpo3QNMIsU4&#10;dCunF52FekFVDBARkl1332MARChYA1DUQmBjI6buNfEdR409/C17HXLQpAP2b957KkoNCUUoFMrg&#10;2XKKXQUikipS7PUs7+veunrV1meWr7//7nX33y9LVzT19ptlosI8KkBoCit6GquBHNpU110OLnf8&#10;s1TOV3/56yEkR37ykwxtSlY0JqaveL1LKHeuufsb32xYtjpi+Kd8rmiIrATEvV73jk+dUGlsaITV&#10;qD8EACRUii25fU5je8eIhu+qHQIqQoElQzvigX/xAUtTquhr9A9f0+OEcdOmbdi+feDhheDwC0AU&#10;UYpI3P7QIzZ9v/GHvl6TksDkFc6tLFaynm13X3hZzxVXMpYjLDVRiNVZKk1hpzmUATiYvlIcDIMc&#10;9FcCinZxhFKFFItaGQjbtmdPPNE5Z9bqn/30qet/tnbJEsvzlnFjtLkpl5CaRlWph+azw7X/N5oY&#10;e7rWP/rok7/61QP/+tWl37ig/ZfX9z24IFm/IQyUzUwsMhY96CE0IcPQUfBOvc7qlKInWgWVrjnz&#10;+6ZOmnLoQaKaQKnyilLaSeb92++7/Mrua//dwGoEO1UEonmSHHzRN2a89wOqSdFvulaltCLiwMb1&#10;951+Otq36ggm9VVdAEQRTHNB3/PL9/iz41pfNy1FENTsmoUZkMjEfac/feutyfZtwz+xKCYiYGLJ&#10;ugfum3Lk21un7yco7Jj8saYCknd2zf3WJR1XXCaEEEJVoIZx/5cP8Q0qm7zYEISdflIUqJOiWa+I&#10;AEpRig7luSSGtL+cLXxy0w03Pzlrtoxpm7z/60JDUyh8iNF/WkAAjOXtm5+dOXPeV85adsGF3bNn&#10;h/XrYXlKtaHj2xeKlQgFpAhFqEUPRg6Ocx3n0goGW3SmsM1z78qnTJly2MEaGpWvcMNn8amf/XTF&#10;Vy5Qy6Q6Ho8gCBJ9z7vedc7Z2tKikKiqlNrZpfzZW2/o/uFPI+NIrvLqewAEQSGTPOtqazvgve8N&#10;ITVKrXqF5WJKSSdO1DGNG2fOTkFKGN6+jjK4ni0tl1c+uWjf495VGjdeBFFUaL9nKZAEkccyO3vu&#10;uOyS7d++iszUitueZhhNt2/54n/nS/wXEgZa8bVZ3B+IWbJp0+ZbZ67Ysm2ft71Zm5pFkYsqc2IU&#10;OQO2wxeynDTmA33L77przumnb7j8O+mSZYi5EqAJ8WKX7kWveIfFF3IUSaAQNAtZtvGue+O0100+&#10;5A0kTCGiMPyeButEpGmWl9feM++REz8TersKN7I6sctgjaV3fv+7Yw86NNFEpAhLjOyunxCxHAbT&#10;bFv7fV85CytX68hesq++AOxE13NL9vmLDzfuOVUNtVIAYVEyTffYb9rS556Lzy+x4oZCNUZdEt3U&#10;vnLViv3f8+60dbxAouRqL2vIis1d3tN77+WXbr348pLlajTZ3Wr8iyBNH3906cYN+xx1VGnMuKTI&#10;sRXRUeMJcDCtD8iR929Ye++3Llt+xum2dFmDQcio2B3K6AVy85y5su/eEw97UyKpgrki2MvqeKGF&#10;259ZdPcJnw6rVlf1bSeKiWd+8bBP/H/UNKjWbJ4IQgxUWzF39rrLrjLEMLLJvCMqAGle6Zo4cd9j&#10;34GQ1ioGFAUCplRtbh23755Lf3VzOlCOWpWaKkQIMFu2ZG053/+YIxBKaQgvL32sxHLW13vfVd/d&#10;8s2LhVlZLRh097tAmyDmYPbUc0s3rJ1x9NFoaVUtEg1HhwCQBpFIk2jbnl86+/Of7//pT5lJMANp&#10;MnjrZ9d/jyRZ3nT7vdxn2pRDDhCRBOH3HP9Vsry8ZvWs078cHri/2vvgysEHvedbFzdOnKoCkdoI&#10;gIAGixT2bL/n3PPs2WcTg8mIKsCICgA1dD311L4f/WjjpD20VqpLg6ipKLRp8pSuEHvvnBeqU6iI&#10;CgXJUvnRBR1NTXsfeaSmjcWbl5ecD1298676zsYLLoRFGBpY7AZ2v7prEiAMwvyZZzcJZvzJMZo2&#10;UKxWC/VVvHkRQbT+9Vtu+vSJ6d33aLSoAIwCJRLuHqKuUAuSZxvnzNF9p086+EAJDZCXjYLGbe2z&#10;vvq1/De/MknEqlI5pvjcPEnectWV095+pAaVwWOpGuwtcpiYZcZ19927+twLQAqhMqILfkQFQGHa&#10;3987edzexx4TQgowB0c48iaiisGXToS9Zhzw/BOP2apVxTEVZTgTY2UwC8bEbPsDD2XT9pz6poOE&#10;gYNxKDGQiIIYjbGr++5rr2z/+sWwilCEJGx3rZ9DECTVrPfxRS1Hv2PifvuCKjpqLgVQskp33+yv&#10;nWO//jVjLFo1yO52922oR0WoVNbMvSvst9+Eg14vpiKaF+dkFGMkhTGLPZ23X3xh97U/EsuHvW57&#10;YfpVRCQgkbEnnnjM504ODU0ioQj+12qWq5B9lXvPOzcuXlw00B3h7Z6O+MLAyh/+uHv5shyI1EDR&#10;Wpg4GXqY0tQpR331zHJbmxCBECIf/svXBJBk+TNfPmfJzTcZy2AQIg8mgEKJkA30zf+3azd/7WIg&#10;FxR1XbzgMgCk5fIjV1yVd/WPomxQA4zp8zNv7fnPnxShRf7vCbGb0dTfu/izpy/7zQ0ROUGl5ipC&#10;CgOAPB948N+v67zi6haLLxS+G+5FaIIs0GYceMypn9WmpprLcTAlwvqH5/XdfFut5sTIhoAAUJp6&#10;+rqnTpp+5NtjEhIqUTPXXgSK0Lz3lD5I+7x5CQHQqnNAp4JSZWD93PnNbz54zIx9RZBAoTTGvK//&#10;0WuvXX32V5GXjdZgEgVeOrN4RVEgK1a0vuc9bfvvGySMiofOaP3r1t75uZNbN2001/FBb9gk619/&#10;+70Nb9h//IH7ApIgQBER2d/7+I//Y/WZ54S8XBFWMUSmwZLS2676zp7HHBtCWvOkMgPZ2zXnm+cn&#10;CxfXapqMbMlTgRJR4urvX9exfCmRE2ANX4OYiYk2H3H8J0vvPS4TDu2+q7EAKFRu37bgpC9snvdA&#10;RASFZOwvL7juulXnnJOaJabBQllFvdXi0JRRUiw+8/PrWclGy6AkMT5902+Tp5/JvNzRTl6RmoT+&#10;zgUnfXbJjbcxDkBoIpplz/z2V0vOOBsxI1UYEkpenfkvopNOPv6AD38wsFTziQ0A0VYteDD/xc35&#10;C8Vzd2kPYPC1Etrb2z1pj+nHHCuJmtSs3ItAVSSops1jJs444Pmbb077KpCqRF+K67JqUbu6lj/0&#10;0OSjjmiaspf0D8z/92vWfuV8ZP1qNhgWJX33v9MORUykd9mKff/vx5onTR50jerRrhqAokb3wOZN&#10;95/6RW7eGMxf5I61NrjjSvoH1t55T3LQgRMOeL2aPX3Lb574zBfT7k5jUTGFNqyvVwVREUQgWn7L&#10;4e//1iXNk/cczmYgr9QOkAJmkisl7+m652vnyOLnaljca0QFYOfZsOXpZ6f/+YeTPaeWjLVP7xNp&#10;mDLRxoxrnz2zSjcPXzToHdtXPPTo1CMOeua2mSu+dF5TNqBm+S5T82C4vcaEsBhL7zhyrzcd9sJV&#10;zTobLAJDBYy4dO6cDddel+a5C/lLr7ZKtnnOPc2HTN/2/PMLPn1K2tlFskrdr7KgKZEHVprb3nnt&#10;NRPefHgIKaV200dExIIJRFfMvWPpBRcFy6V2B361EQAApXL/1tbWA959LFVVax/bJXXyGw5Y3r6J&#10;CxfTrMpzgNiyafmvb9l6061pPlDRqPRgwcuMlUoARNDb0HDQhz7CEERkMM+yzp5UBGYmlcqDV1xh&#10;jz4OcPe47/XKjQ6Igd6Vt9628Tc3J90dAEumUa0ag5Ui5Coqyb7nffXNf/P3kjSIUolabTojabAI&#10;ybe3zz37q+HZ58Pv3gYfYQ+7VsuFsvm6q7cufJJSrXu4r1QCkjHj3nPmGb2HvrGoaVLFr84gpHZs&#10;K+W5AI1Ri4I/zv/2FJWIwgB0zL27b/NWLbrN1KVaFrGL3o1bNs+cFYhMFUi868FLrgBTtnb3N/R2&#10;KzUYK5pjuE/4i3GPEgGRj3/4Hf/ySZYSVQgs1u6dENSoQj5/55357NkpZEAloGY74JoJgBGNnb0P&#10;/ega6e8lLZIWLVrt5mSSBAkt02e866JvVcaOs6SUCKjVWMAEc1hxS4A0Rpp50s/LxFWMpCHG2LB5&#10;U8fapWZGRNRjaRwqDOTGpYuaNm3OaWk0Q+4v9iXWvkFz5Iw5SYtGE8NQRfFh8cU0gQSR4tJ9PmP6&#10;+8/5WjJ+clBVgSDUsKZIEBXVfMuWJ75zZchjZjGJFqtQlrjeBaBYFv0/+eXKBfNJSQgJrOFFHyVM&#10;IFKa/u53zjjv3KgxU02rXHufO/3u/EG/qWNzO+p2/w8QyBBXP/jwTuV8/d3+gclfDa8xZchVM4UJ&#10;+1uaj7r0orY3vnHnzLoaTiAxM+RP3XxD8vDjQyVga0mtimCgBEYlBwYeueoHWcfWDBaJGqa/CCiw&#10;lGqNLW//538Y+//+kZKUgy/gOgoHbV+5GgAHS0TX3QMKRPr6Ns+5S9zu11iGzYgGJiKlGWd9Zf/3&#10;vU9DQ53sGqJl3SuXPHnpZYh5PTyP1uolUUwgqqF8y6xnb58J5sFqaW5JkjELFki2tR33lbN49Nt3&#10;uqXsKTo19wDQu2ZdTTcJfyiyQfRt2tr75CJ/WTXWAIlKDqg0fOKvj/r0CSg1B0arjxUsFh//yY9L&#10;y1bXrCB+PQgAgGgQo8W8FPMnLrm8f816U6thqRdRVUlTUVVNpdS63/7vueTCfOpUqKgoNAmivrRq&#10;u657lz5Py6WmWRMva/0RCbSvWpl2dfqrqrUASKLMjzz8z87+WsOEyakm0KC1W78GkIyMFuOmRU+s&#10;veqHSrI+7ojUgVEj8NTixT//OWL9HO4RopOOPPJtl347LzWYWKCV1X2AGjOwpV1iXrf5UkpuWrKs&#10;wX3FWpNAuqdOee+3L23af/8dV9BqOjEQRUjFQP+C71+nXdsF9XLbsy52tcFsyeWXb3tqkdHq4XmK&#10;WpQJGg/62F/td/7XLG2msGS+smpMuX2LZDmKZit1hkDE8u4lS2A+UWo9T5qaj7rq21OPOipoUg/P&#10;kwMaGbPK83Nml398vdCKe+MuAIOkDGFrxwPf+27s76mPAsgCoSkklN52wvETjv9kWaV+3tlui1Qq&#10;qFTqM7WmiGd2LloU/UJHTYmq+5/31f0/9FciSZ2cxptEQcy2bXn00stzKasVXZ7dA3hhx20JtfvH&#10;v1gydybz/txIYw2rKAaRgJAoJEjDmHHvOuvs9C/+gkkqkoioKZJRUpZyF4OVSjSyLg/kCcl7ugeW&#10;LfUMoBopsMQA0XTCFz575AknNTQ0BRXUx7mdmsXcHvvFr+ShRzWXwrrViaNY+wGiIAoIJrH8xEXf&#10;6d+yKSEpMKmLVR2hpT0nvP/iCyuHHgqJFGmwpIYXN3Z7Eajf5+rr7Mq3bvWrvzXy2ZGYJH/zsXd9&#10;5cyktdXMUDdvggxbn160+sJLqtHnYNQLgBApSUFZIhY89uiPf5JZHwCtg0LqAgTVRNKWAw/6s6uv&#10;zPabTgmZ0pNCnZcQgO2d2tMrpGtADQyZJnjPn/7ZJd9omvQ6VQ2hXnx0kuzpeuC73w/tm8TqbuNY&#10;Fy6SAYA0RRGLq799xeZHF7JuAqkKUDQxTj3i7e+45rI4fjxgUYIvcufFAsCe7R3p4PG0h4FGmv5D&#10;Dnz3Fd9q3WsGdg4e18N7oD0ze1b/z64HNKm/BIH6EABSLIskaNrZMf/yK2LHNquPF1nEEZM0kVCa&#10;cdwH3/a9yyptbSKEKjSBKoMrgQMS5Y7tqZnA74uM1JgHiAiTtDx9+p997+pxBx+qGiTstDWradE3&#10;MM9z616xbPH558c8I2Md1gevo8k6ODYm8tubnvrtDbS8Hl7ki4QqpDM+9pFDL/kmSiUTU8TUqOYC&#10;4CAA5e1+BWxkN2dMRCjjJxx79VV7HH1kwkTqxvkyiiFBpeeBa66x558P9Ro01vp7qagwf/rcb3Q8&#10;s9hitHpymhIKAQFuxwAAIABJREFU0zGH/tMn9rng3BCaompUiMeCHEDFOtu30nNAR3LLKNI3bo/D&#10;r7ly3z99T5DGIKGiCPVh03LGyGzF3XduvvoHGiPzOk0bqT8BAIQJNq6df9l3Ym+vQOrn4JwiDYaQ&#10;th11wqenXPAVIs20Hir6OXXgvjJm7e1EXVaq3uW2/sU/spaGt175nRkf+sugJREzjQmZ18f4J2R5&#10;3doF530zKedqKBp+1OHcqDsBIKmWa2Y9P7l+0W9/mcdKbsyZ1cVgKSQgSZKkbcw7T/zs1HO+rAji&#10;JSKcosF553YxIf3CYDUJmiDVECotYw773qWH/N//k6aNkoiqJhKCSC3v/pIZYMU1pqzvgR/+IDz8&#10;mOy0969D/7B+D6yCxSfP/eb2p58OQkVSd8/X2vrO007d4ytnRhXP+nBoVu7qJsRrQVd3Zx3FJKuk&#10;TYdccdlhf/33eVoyzcXqIunTRFIzgYBYfvfcLVf8MAqsvlPG6zpjoWXN6ru+/e28aytjve2qJFiQ&#10;lubX/+mx1lDyZekwWvf6DT4O1aYSQGG69577v/PtLDUnpmIk66OsghHgAPPu1cse+to3UelVaFLf&#10;l4bqWgAqEPvlrx//6c/Vsnp7NhNufvChez9zmvaXfVk6QrJc8UPgqgcGaFEkrFp12ylf7F7+PATC&#10;xLQuhj0CUSTt77vve1fJwoWBVArBep4TdS0AidFivuTr5214dEGMMYtGo9VuPAmAtDy3LF/72MN3&#10;fOrTpaVLQPghsAOJeU8X4deAq7wGjRqZZxW5486Zp5zauXKpRWLw4IU1rtgYY8XiMzffuO3714Y8&#10;t9yMudW1/a9vAaBYsJBu337v1y8ob9wYaCZS0zraJCSHbXjkwXs/+elk+VJCBN7R3QHy3CoVt/0j&#10;6HJB75x3+8mn9KxdqaZDi7CWLliu2vf04oXnnBeyfLSYhPq+tUgxMBPDnXfe/4PvxaxbgRp6e5bl&#10;mVU2Pf7oXZ/+XOnZp0LMSwaKZ304sCyikg35ic5IWIeQDejsO2/+/Mmdq5ZorJiZ1c79IsmOrXdd&#10;cLGsXC4cNZOgzq+ti8ASA4Ubr/re0tl3kVbDMxUKtjzy8N3/8un0macNCkg5wKO+TrHzFI/+jPB6&#10;RKDkyR13zz7l1K6Va0DkqF0QKM8f/s8f5b+5USAyei6D1HcIiJE0GiUy6et58MtnbX3qqSzmMIuE&#10;ERiBvpoEYTGvxCzb8Nhjdxz/mfDUYosUM5hJpPeJcQDEvCJZRqG7ACPndTGnkZUBmzlr5umn9qxZ&#10;AUYiJ2BFMZ4ReO+wSFSyytK5s1ec9w3mZTWz0WMURk3hKtPQtGzlveefG7d3mGggKWT1t1wUwpTg&#10;pscfnnv8SfrccwoJ9HXuvORuwb2AWnjmBGbOmf2FU/tWrwALmyYQSvUNsZoarHfFkvu/dHba0zvq&#10;xm70VC6MyJnbb2588AfXsLczR06MhMZbHnMb2PTEY3NPOjl9+sk0Zo0M5nEf53fwFhE11YBgZbv1&#10;tttOO6Nz1TLGcm55LPyAKpNZbts23X3BRclTi0djFZDRIgACaGpmDGsuuujpWbMQK0kuUn1DLGT7&#10;wkfnHn9SsuhJMAilX6L59t/5fV6AM+IRAkgWLLn5tplf/GL3utUJqZARKM2tWfn+f//xwP/8PKHK&#10;KFSA0SIAFGYGGLN0YOCxM87YvGhRLnmsTq3QIp04z/M8y9YvWnj38SeHRU9GQiw3GugOgPMSMxSQ&#10;wd+dGigAkwx5XpEbb5l5yhc71662SJoZCEQwRg7vp7GS5zEvPzv7xrXnXWC5RcbRKP6jrnkFATSu&#10;XT/3y18b2LhGqtX0mUJAuGXhw3d96iQ+9TQgiXnc33HqPlZA4tY5s047s2/tajMhxKAQHb6ajSSi&#10;UKBsX/T441/8alLuBzVwVBqHUdm9KBcLc++858Jv5d3bqlEGxPIst8rmhY/OOeGzYdHjIWZphHm+&#10;v+OMCqMWy7zxlltOO7Vn3QqNWaTZcBbpEzMa84F1K+/616+GVSuEsUSx0VkVeFQKQIiBYp3X/efD&#10;//6fzLIqSIBuWbhwzvGfDYsXgwGQgcSXleOMDiJCQK63zJ512mlda1cGRgLDmDFo1NjbPu/iy3jn&#10;PUJVopzYKC0DNSoFgIwSIdnAinO+9tzNN1VihWav1RUgCLO8Ynm+4YnH7jj+M6UnFyYGsWi04Pn+&#10;jjNKEMvNaNmA3XDzbaed0blqFSJpxh13A165qYgACQNzRpT7HviPH3df82+IERYjEXKTOCrHanQ3&#10;sE76Bx794plbH5kXhXxtNXkoFGqEbV74yLxPfSZdtCgQisG4v5/6Os6o2ygKoTffNuv0M3rWrTAg&#10;7vABXrkzIGY5oCZituS2G9eefWHUyNF/4K+j/R2X1q679/RzupYsidFeSwKGZXlulS1PLrzjhM9g&#10;8eNgrsSAmlt+xxm9ZMhw0y2zTj29b+1ytYxmr/L+kECJLOtb++C8R75wZqm/Ww3CUW8edNS/YYEt&#10;ePjOs8/Kt2x6jX/TlscWzP3USeniRWIaKJkw8Zw+xxnVBs6CgPktt8085fTuNasFjIC88mVNqJKd&#10;y5fc9/nTk42bckC5KySGjHoBsBhhVrnx1tkXXljp2GZZJdL+2OsBBMiY5TGPG598fM6Jnw+LnmAE&#10;aJGDCcSO44xqA0GjZpndeMstp5/etWo5LdqgH1BcFX5ZYxENjMwAY2Se9axfNedLZ4UnFhV1wIzQ&#10;0X8uOOoFgAAFTTH2XfMf837wXcv6JKr8cQpgQkIo+ebH77/9UyeWFj2VmJiQnu/vOLsUFCK9afYd&#10;p3yxd92qfOhQT/n7soOC0AKVALWyfdvc88/jzLm7WM2PUS8AgQTRD5NY3viNix776fWW95T/uNi9&#10;xTyP5c2LFs498eTWJ5+MzEAm5uk+jrMLakCF5fKtt95+yun9K5YhxkgSiC8vACYMBouVrHfLvEuv&#10;KP/nTyAZd63N4agXgFwYBu/fa8js2TPOevamG0tl+2NkOhDtjz96x798Jjz1dAWaUg2e7ek4uyYJ&#10;EwuUm2696Yunda1eB4uA/P4GUybKrO+hH1y77YrLM2piRfvhXccJGPUCIARhagRNDGlv9+OfO235&#10;vNtjllnMid+9HlDEd/KY5zFbt/DROSecnC56AjmUZjTv7ug4u6wLYHnIkMc83HTLbad/rnvVShqF&#10;OYo0/2LtG2kwItJixjzrffzH168895vIMo15JGx01vzZZQXgBSUAA3JAks6O+Z85Zf3D881yUH6n&#10;ZSPFYBDELY8tmPsvJ8niRUIUfX3d9DvO7oBQkpvn3H7aad3rVmQSIliU8SsuDGdKAYVKZM/f+Ntn&#10;vnRWQ6WwIbughdh1BIBALkgslZzJqhX3nHjy5kULjRXai1J5LM9z69v0xKNzT/xc+tSTJYtNpuaB&#10;H8fZnZyBDJV4y8zZXzi1f/kyyStieWHfKUiJaFluvctn3vrkp09r7OmKxQ5zV0R3pS9jioGQK0yJ&#10;5Lln7/7MKV2LF/9OkW5l2LLw8ds/dRIWLyaCQAYQ1Tf/jrM7oYaEjLfOnnnaKd2r1xQXxAQgjBRD&#10;vuHOuxd85vPW1QkmgrirxoZ3KQGQyCTGSMKIKPrII7efdkbn8uejxWhWzrOYVdYvfOS24z/X+ORT&#10;YiIWI80Pfh1nt3MByEgiz3jLzNtOP6171RrLEC0yY8Zs48OP3H3yKemGDSFmZMSumxmou+wLFppA&#10;7pk/+/Qz+9YuE0MANi98cM4JJ7QuXkQYJPcTX8fZzYVAiHDL7bedekrP2qWA5oEdjz487/iTG1eu&#10;2vFnduHvv2uWORZAwQFCkeHWWbcn6fsuu6R769a5J36+8cnFERAmCWJ0AXCc3Z6MFbl15m3gn19x&#10;RV/n9rtO+nx8fjGIsBvsEHdNAeDg/QAlIAiVm2feMdDbu25D8vTzBoFYwpgLvcan4zhCARhn33XH&#10;SSdl27aHJ58GREy4G5SC2WUbnUikIKKo/BdZnnVH8VUVABHh1t9xnGLDSACalbM77y62j7rbfPXd&#10;4Zu6pXccxw3FbioAjuM4jguA4ziO4wLgOI7jAuA4juO4ADiO4zguAI7jOI4LgOM4juMC4DiO47gA&#10;OI7jOC4AjuM4jguA4ziO4wLgOI7juAA4juM4LgCO4ziOC4DjOI7jAuA4juO4ADiO4zguAI7jOI4L&#10;gOM4juMC4DiO47gAOI7jOC4AjuM4jguA4ziO4wLgOI7juAA4juM4LgCO4ziOC4DjOI4LgOM4juMC&#10;4DiO47gAOI7jOC4AjuM4jguA4ziO4wLgOI7juAA4juM4LgCO4ziOC4DjOI7jAuA4juO4ADiO4zgu&#10;AI7jOI4LgOM4juMC4DiO47gAOI7jOC4AjuM4jguA4ziO4wLgOI7juAA4juM4LgCO4ziOC4DjOI7j&#10;AuA4juO4ADiO47gAOI7jOC4AjuM4jguA4ziO4wLgOI7juAA4juM4LgCO4ziOC4DjOI7jAuA4juO4&#10;ADiO4zguAI7jOI4LgOM4juMC4DiO47gAOM7oRghw8HfHcQFwnN1SCXwIHBcAx9ntLL/bfscFwHF2&#10;592/R4AcFwDH2a1INLEkqIn7Ac5omrc+BI4zLFDEd/+OewCOs9shSSIhUEB3ABwXAMfZ3VYSg68m&#10;xwXAcXY/KEk6pk0hAeqpoI4LgOPsTohAxA2/M7rwQ2DHGQ77X0qS1hajHwE47gE4zu7nATSOGeux&#10;H8cFwHF2w4UUmiZMhkC8HJDjAuA4uxchSHOTD4PjAuA4ux2RRFsrfPfvuAA4zu4GRdJxY4TiOaCO&#10;C4Dj7F4IrHnc+DzxehCOC4Dj7H40jR8Lgu4BOC4AjrN7LSQN6ZhWgdIdAGf04BfBHGcYIJE0Nwk8&#10;AOS4B+A41ZmsBESE9VdzgUDbxMkCjeoS4LgAOE4VjGzdIkBjU3OlqUk8D9RxAXCc4TeypTSkoU6f&#10;jWhqa8vHjfGOYI4LgONUgTTVkKBeM+3TtrbS1CnuADguAI4z/JQmTLJSKnWZai8qmpYmHf4Wvwfg&#10;uAA4ThUm65g2hECRuqy5TIime+8N9TXluAA4znBvssccOCNIsDp9OiDIxAP29/2/4wLgOMNPadqe&#10;RgD1mGxPkILWKZOjtwVzXAAcZ9hsqwz+PnbKNCYiRF5/CiBUGCbuNz02t/grc1wAHGc4iYKWqVMF&#10;KvVZc9kAwdhJk5J99nUXwHEBcJxhmqOEAHmQtj0mCwQiWoeJoAoKtblp4nF/4vXgHBcAxxkeCmvK&#10;8ePH7zmVAFmXHoBQIRaSSUe8xdz+Oy4AjvPaoQhFRbX58Lc2T56soiqi9ThvFVAI9nzjITEpxSQA&#10;9VizyHFcAJzRM0EJA0V07/e/V5KkngsCCWGQydP3w757BxqEXhbCcQFwnNcwQQVQDIR0r6OOkhCk&#10;fvfUBEwkhPHjx73/fVRVqNt/xwXAcV71phomEDAc/IapBx9cz+12CVAIgkz3ee97M6gA9MJAjguA&#10;47xqs0qoQfb7u79vaBtb31IlgpAoQqoHHH00p++fwxJzAXBcABzn1WOWtuz3p++MGkbF4wrQOGmP&#10;/T71DxTJPQTkuAA4zqsm0dD08b/c86BDEo4aayoaDvvwR/qn7pVI8DfouAA4zquknCRv+9Q/WXML&#10;JI6KByZAWMvrD3zjGadmqnQnwHEBcJw/nqhiCoYgmkw84fh9jjxGIIZkdGz/AQ1pkja97e8+ET70&#10;F0hSSRJRpboUOC4AjvMHJyUlECVK+fBDjj755LyhETKabtcKoaRO2uMD37okP+JtBhXC74Q5dUj4&#10;uI+BU28CICIIvfvt9+4fXjn1sLcFCSIiKqPlXlUElVEkaRo3ceo7jlz59NOlNWsMJTD6y3VcABxn&#10;p/3y/0rvF0XvHnu8+0fX7PPO94YgJmaiSsho2UWTpgRVYc2T9tjnuONWl/PeJx4JMb7U13UcFwBn&#10;94MCiAqK6LiYIoiahoE3HXrcv107/bj3aJKKqIoqREZPDEVEFKoCUYUwHT/29ccdWzr8LWueXZK0&#10;b1cRFQhIQR6QYLDDpSuD4wLg7A5Gf/CXAEohxESiUql9Eybuc+Zp777w/MmHvlm1FHXUH1LlQGIh&#10;lkqT3nDAAR/8UDZ9743LlmB7l8ECxUQJVVIG7xK7Bjgju1m53sfAGWEBwGAwh4BCKJpp4CFv2O8T&#10;f3vIBz44/g1vlKRECAQCU0lG+Tc2QnKI5qRGMfRv3Lj8/nnP/+IXPbfPbejrF8bC+osZAPMp4rgA&#10;OPVvx4faMu7Ys/6RZQ+EAopQNZ/2urHHHr3HO9+5z1vfNmnGtHTsJEUqAglqQjWYIIzy7JliUEgY&#10;IRLFJJJCoty/ffWKNYsXrrtr3tY5c23t2lIeUzKaySsoeSrwckOOC4AzcjMGSEX6lQkBqqkqVUQg&#10;ZhZJklQRqlLVaFTJS43W1qrjx7dM22vs4W9tnbbX+BnTJ0ybNn6v/Upj25AmqkrZDfMkSTPEWN6+&#10;vWPtqq2rlm9bsbzrqefbFy6yjZvR2SkD/YEMQCBBiEBUQBoYhWJCQuk+g+MC4Izo9l+CkJSspS09&#10;+qip73pnaY8JhKQNjY1tbRIUKkna2tTchIakqa05NDa0NDeHpkZtbETSKBqERRhIokBElLul/R/C&#10;LAqQx6giZJRypdLT29fbm3VvH+juywcq/X39RM4s7+7YJrSsffOGe+cP3L+gtbc7NxcAxwXAGUGC&#10;CCH5EW879tLzX3fkMdbQBAlpBFQImIAy2MgXAlByoQJKEQIghBQYqAjw1JeinzwhRadLLSJEEJDU&#10;IluIg6fmFFIIMlp5YOUjD83/0r+mCx7xKJDjAuCM4KRRVMaMP+6m/9nzqHeFJAEVMhSSGDoakMHs&#10;RgGgO/r6kiKyo0p+kfMyaPd2Z4+q+EUIoCBlx4AQGBQAYlA7CxcM1DwfWH/fvPv+8q+Snh6fk86r&#10;w0tBOK+YCGl53wf2PvIYTROVoCoqCFCVoKJBNIiqSIAEIOy0xy/iPAIpfg3JwO4+C4sRCMWFCBGB&#10;6GCqrBbXolUkiATRgBAQgmhQNJQa93vnu1s+8BdQEUnEK486LgDOiHgAuuexR1upcVRV6NkVCWHy&#10;sUdDVGEUrzPhuAA4IxKzaNtzCkTFK5zVVomDtu2zNwiC6gcBjguAMyKTxgAEg4mnoNT8XYgAURC8&#10;84DjAuCMxMaTgxUdlD5/auyKkUUSETNPp3JcAJyREAAfgvqSY38jjguA4+yOToDH/h0XAMdxHMcF&#10;wHEcx3EBcBzHcVwAHMdxnBeT+BA4rxSOmqcTfyOO4wLgDCdWdOg1SMiBpKp21nZqlssX7N1ODWkA&#10;sLgERYA7eo0BMBA7GtAUlUgFBGSnzBl5wYQOth0miz8pgx/Eoshp8X960Z8RymATx8GP59DjEJCd&#10;Wp8Nv7mXHf+mBBCDNkTmrgOOC4BTfQRkDExeVOqtKuhOpp8wgYCFJEQBIArABguQEgBNRAb/XU0B&#10;QkAxK0x5BIxRIkAhYMyLP2u2o4opVQgEMYgwJFGKYncYLNAm9oL5FaMMVu8ctPeDZT2Vgx/AUJ0o&#10;61DZVZKZgCG+UGPVcVwAnKqaf2xbtkJiZlrSatp/7rTbJYkIg0FhAkIUDDEKEWMmgOUZ86zcX7ZK&#10;JevpzfoHKr1dAz19ebkc+/q6O7bmfQNZb7/19qGnM+vqLnd1l3t6Yn8fsywOlJUcdBpKaSiV0taW&#10;xgkTmiZP0ZbWZMz4hjFtLRMnhLGtDc1jWlpb03Fjmpob0+bmtLmJISGgSSIEJVAkB4VIoAIgYCe3&#10;YGgAh8MvICnGrc8tLVwgL8rhuAA4IwM33nW3fPZEtpaq+SEEDSQIVHLkMSv39HZ1lbu2V7q7e3t6&#10;s66unk2b+jq7bP2Gzo0by5s2s6vbOjrQ34+B/kCDmURTQkVZVKA2kjSw6KUbVMVIQYkvCjEVnQoG&#10;gAFSVCIpArLoySg5GUPKMa1obtFJExum7Tl2n71L0/YaO3Vqwx6Tx4wZVxrX1jJ2XJgwITY0BEtE&#10;A4Ci1vOOb/baJIDFI8b+/s133gswV6SuAM6r2Mx5Qxjn1bgAoeEN133/0L/5u9DYIBRRJSgoOsKQ&#10;EFUBYGYiKmAEBv+7kkWHWxYmlRJzwKy/bOWB3u7ugZ7uvG+gu6sz7+/v3rShf9u2ypat3c88k2/c&#10;VNnabtu3J+VySqEVUfgi6mI7ngsjdCL6Ox8lxfeDCCGWpFlrq02e0Dxtr4mHHtYwdXLT5MktU6a2&#10;to5pamsrjRvbOm5MaEwREoQEopFa2PQi1jTkHxBSxJOKqNcLZxvRMmPC2Pv09T976oTPhZj7lHRc&#10;AJwRIoWWldY6Yd9zzjzowx8eu/c0KTXoUFhaCEQzQowwszzv6twKMlYqlb6+rL+3u6fXOroGOjv7&#10;OjoGurorK1dXtmzpW7s69vaisyvkWZplQis2zIOKIaRAjSASESHyF5091Mvud+cj6EGXQ40QaDCS&#10;opRgpTRMGJfsNS1MGt924AENkyc1TZjSOnFC0tLcNn5c2tySNDSWGhqb28ZAA0QZBIXCyuDG3was&#10;c+2aZ2betPybF6fbO31COi4AzgiiWmTeBNNKcxMPPKBx6pRgiBZjuRwHynl/P7IK8yhmyGK2vUPI&#10;NMvS3Fj0A4YVMZii1W3RJ5iAKQoJMYAiJpJalMH9r0SxofNd8EWHq/UV/kggBuYCU4SYCoqvTAGs&#10;SEoCVAw7mkGqgCIIQo2JxFLJGpvY1hpURIMlmjQ2hNaWpKFB0gRAeXN7+Znnxvb3Z8KhE3DHcQFw&#10;RmifGwCNSmU0EYHSSLEw1AheRM0AAa3Iy4wUISRQWOTncChzckeGD1/I5SwiKYVhLCI9QxEQ7hR2&#10;qV8BoAQpKjULuVOaqBUdMflC7mlxxB0YMJi0KkVjl6JzcvF/FhHSUCQ7KQAEikAMVNK8GJzzmjYr&#10;jvNKDRwjEDUWZpiA7Qh8FBaaiMX/2PFzYXHuWqTmv4zBLv4kXjDyQ7tb4iWSHOv30FMYd3wj2enB&#10;dchYywthIgCIiC/5tX7nnEGBoXEl63wInNHizPsQOCMmHD4Ef+RA+Eg5LgCO4ziOC4DjOI7jAuA4&#10;juO4ADiO4zguAI7jOI4LgOM4juMC4DiO47gAOI7jOC4AjuM4jgvAbor4EDiO8yprAf3x9mNkr7RT&#10;JBACMSEpMtgldvA5ikKSr7VzXr1+9xepuoShhrm0nduciJqANH3t4/DCmANDBc74B8enOmMi2FFB&#10;vyhLNPgQoShNNFikiFV816941Koyzjv/rcJX+734GsaHo2odSZXfaTXWggzz+LxiAdBX+JHVrle1&#10;o2csAYEaSCWFajQUPWRBqHLIErzGz6qn7/5yRI1CEQahUrIXupYIhSJUGRyw4Rh/Dqps0Z9cWIMx&#10;iSr/P3lfHl5Vea2/3vV9+wyZSSAkIYQZZB5EBgVELIpz1Yraam21jm29VTvc2l713t7rba22Xmtr&#10;HW7VWoeqVetY2zriPCOIjILMkAEImc7Z+1vr98c+CUnIOZxAEO/P/eyHBxLO2d/+hjW8a613QZVT&#10;Qr5NQgJqFKIQAbHs37Xu7iX7YZ6lh95rX75H/o+co/2xvrIf5rmn5rzHFIB0V22m6H1DNt/9cqRC&#10;u09BYCGCClk14U+MklFSgiF1UB9q9mG2uvvuIYdxSNj7WaIuRhCqPAcFcSulsPoghhpVAdoTUPaU&#10;PZWNVmnlde7JnQAoAaIhi3Jr50VQEJJMM5N2+5jI/l4w7fl55nZzq/vyXroP86P76xz17J7ZL+ur&#10;PT/PPTXnPaAAxJi9nbSQ2XxX31XdZ4HYRqgrRAI4y35+XmTUuN6TJkYrygtKSowXVVDQ3LKzpq7h&#10;k6U1732AZSsjiZaQUTfVWim7mVMQlByYu9kBPSX6U1CUtpmmYSvEnvVlU6z6BGcQlJXnThhXOG5c&#10;vKwsP78ABAUlW5obajY3LltR99Z7um5DtKWJe+JEpSAXZlJSzmZOCKTYp0fvWrjwfZOl5fnjxhaN&#10;Gx3rW5rbqzeMISUJ/Pra2uTmzXXvv9/y0cfRuhqWsCklkP7QKKC8/xrd73LGRNWIdGueBQAMVNPN&#10;syhx69x2ej2XajdJHd8dXbkaGrYfyORyZTwLSsROusRExGQ/t9r+vagVwm37OXbRh2v2+0b25/qq&#10;yK4zBaPI6iUhks1xkNQKdrF2oUxV2bX6PawAlFkq+03/39tsLErOdGvDC7H4Cb+lpWFb3baVK7e+&#10;9mrinbfijU0QciRWCQSnez4JTORaYVCGUSgBjhD0q6w4/ZSBRx3RZ/iIgtL+bC0BbR1EUqMIApdo&#10;qV3zycZFH6544pmGp5/2mhojakWTIBJSpNrZdvVcIGkIhSXTbrvVK+7dLcXliF2yJWhJNG+r27Z2&#10;bd077zS/87ap3spOSUWhVqCqQsaQOrjuKgUwWFkZqqLGBONHD5p/esX0w8qHDI4V9yIbZYKk+mmB&#10;iFSUJJD6+trVa9cv+uCTRx5rfO6f0WTSgTxHrCqk3XWQwIjMPuLgn/xIPGOc3aNmF3Wrn39+47XX&#10;GgWJdMt6UWaoUcOsgTD8EcMHfu2sfocdWj54RKy4EJEIqH1H3VByqDYnG7fWbVm9dO2Cl9fdd79d&#10;/akJO82HJmU7KWyMjZ928uiLL2IoxO4Ht23Xy25ft3bRt86zvqPserowm/Kf/mTA7NlgYe16bAK3&#10;7qUXN17zM6gh3dUoWK0dfdutRYOqiKnjZ9EORvChRqzWLvpoyb9cEXeBTxIetza4CUQOYMaom39T&#10;PHJMmwml7V/QJJ3IkutubHjm2Q7dyoyRMaOm/vp6yx6Is5hbDfUxEbU0Nblkormubtuna2vffKPh&#10;nffi27YbFRIBQZF1Yxxjcr/y5XEXXcAGJJGeWd/Wzm5EtP6V19ddfRU7CYDK719RNe8oNcJqQabL&#10;11M4qP/RfQ/u/MPdGgTp5I9Cg6FDp//yF7awuIu1UxKCwLdiNi146ZNrrumWDshOARAncwsHHnIY&#10;5+ZIBwwoJ4q1AAAgAElEQVQFWak4InUOBBGjfuOOtavXvPn+qrvu1tdeDSSIipEs+tppawSMiQQu&#10;gMXI0SMuv3T4nDm5ZX01EoGgg2oH2i88cvNLRo3rM2Ls+JNP27L4o/fu/VPNHbfHmskHQ0KA1aUz&#10;/2MBNcRilbOmeyW9u/XuTpUJKs4QRDiQhF+7tXr5JytfeG7DXfdGN2wUiJI6OCHyhLonDlMYt/OJ&#10;aeas8d/99pBZ07ioxLBnwK1yX9tvPoGwF6Hi4t7FvXpNHDdu/qkbFn648M57G/54N5yfZCXqNlbu&#10;iMu//OXKw2ezWk374XbWXACbn7fhF78OpNl2r50hjLJvfCabHDdxzBWXjzhierS0L1HEgBxDASZw&#10;ezcBqoDmct7Ainj/ikGzZrWce87HC15edMONscXLHfkx54J2gwuITL/KQdNmiDHE+wOu3LVnclau&#10;eNN6+b4TJnZZvX2vUSMHzZwVhne6/i8B1W+t+RTW6/B7+GQrJh7cZ9yY3bw0beeks1H2If1GjVv+&#10;wEPulVdYSQgdpQmMUgJcNnlS34MP7gTRtFrBgPOX9n0wAGwH1aBS2GvQ1BmIxLLDYXd9p3NOiSzA&#10;TiXwd9Zs3rj4w1XPPrf1gYdya2oCo9Z5pP4eT48jtRWVAw+dFXgR7qHIAlJ2Poi0vqkhyZTj1Kpu&#10;evedKT+8LFZU4rOaDsmW7T0bY1S9aN4L9/zZBg3ateEPkBlw8YUV8+ZFvGiX3+NIPUHzztrX/ucG&#10;dHPbZqUArDpHIhZiYOGhW+CTpuAjIrJManJLDhpXMmLcmBNPWP7s39699r/N8mWazNZ2gjEO5Ofk&#10;DvjRDyZ8/ezcsn7GhqERBacHloxhElVRBnmx0smTjho3fMPJX37lv681z7+slEB6JwxKAZOArfMM&#10;vG4Bb6YVOlOQknqUGykfmFcxoGrmrOZzL1j8zNMf33BDztoNeaKNmnTgbtrfKoZcr9IhV105/iun&#10;xnr3JWOgJOxAbIhArlPg2zKTEpMhEJsA8cL+02ZWTZqy7MSj3vzpz2IffczkXDeDAwyuHD9WYKFg&#10;ZAAJU8lYwlo+ZLAdM0IWvtdtD5sFJtb70u9MveTi/MoBaplVBUpkOJUO0GEPhPajYSZVmEDIi1UN&#10;mXzGoOEz5rz+u99s+c3NSkzOb/v/nihD1agYsWTQ0x5A+y5gEJsTsFF1nBWIYcUnVmIYYgBdfrkz&#10;QgDBKdonPWlEA2UmNqxdpwdpK8jksWph3tCzz17+2us2UO4IsAQWntOYgCnCrXJA250FDVMwhMDk&#10;SYcnsZIFqRVizbhPupgrY6BECiZDsF5e/8EH9R84cu5x2y769oePPvbpTTdxTbVkMYeeKBMUAIjJ&#10;9MjqKtpGCiYbd3BEAZP30ksfP/X0+K+eZQTGmC51W9jns3TcmPzTTmz6431pZIg2VJaPO/H4KKIM&#10;7tqTEBWV5U8+g6ee7W62W1Z1AA6p3t1G2jp6t/X13sOtIAIxiKHKCg6XQG1R0ejTzjj5Lw/Z+fMd&#10;si1HCKD+qFHTH3lg+mWXxfpWcQpfBxEHgvZXJyEOIoCYoKSsxCbef8aME+68o/DSSxysQwZ/HyBV&#10;iHL7F+/mu5Oyqgm7f5OCEBtQOfn8b578t6djl5xX79lUhmr3dh6CSRNnPnL/pAsu8PqUO2aBgghq&#10;QSmwW4h38zrDLSukrAgESUTs4KNPOOGhe/TU44Pun4nE4MG9hw+POBC7jLMR5mSJIeLcvIqvnAR4&#10;3XthkO9FB/z8P2dfdWW8/wAyUCUIG2HaJf21/YW2JDEQq2eUlCQwiFdWHHH1NSN+fVNTTrwdvEEO&#10;oiAorONWrLxn73Y7B+LYOVDEZTXpjlJnELu+p8MNEqMgBdSETYbbxw8gYA2Xvos7zC0KmEhZTHT4&#10;EXO0rELBHeUWrGPH6pB6XNtz230PWQWn8jKkExgMIlLwriS0bOdKUiskSsKsJozKeV7B8OGHff/y&#10;o/72BJ/1NZcabKbJFGICNJUq0FNrGj41PHpQUp+VhSG0+PpftWzaSDBhApd2fjWxYUa2zTnorK8F&#10;tmtbPMlmwIUX5Pcb6IzqbmJHUwcaTRs3LPz59ardTu3ISvKGW4cJSJ21btxIZWWAiJkAgIkBtmys&#10;MUUDhx33q5vyLvm2M54BMoRnYKyznps585g/3T9szrxIPDdqwcaADAhM8AxntD4ZZAG2YDAb6xlj&#10;c8oqjvrpVZX/9V9kIOyRIYbp6K+RKKm24QF7+e4gNuBUu3QYY60H49l4r6Ejjv/Pa0feepOU9CYG&#10;mMEIDDEDaV02w2DyPDfnyOP+94/9ps3wvKg16jFbYtoV6gOIOUwB6nyDiAEGrIcI2HqeLRo25oTr&#10;r/dO+wqMgWVnLTjD3rCGQCAB+s47xvbqrYYYFlnMCRtSz6uYcpgwZ2NihwMlQ85GBlz906kXXmRz&#10;i6whBluADNGuuUKn/dwOLgVADFiwBYy1Xk7upG+eOeKXvwgiMWM9hgWMqLK0Ll031zq7/WDCEVPK&#10;FAl7wGeXiaAMBRFLhkdAiBw0cB0FgRDUqKZCQWnGBtjUn1TQv7zy/HOZpWMYU1WFhByoVbe2vdeu&#10;WwENd12nD1NYomOynNv2c8VggMP93LojmAnGGBuJlo2bdMKN/9P/F9cn83MVHsGklQKqrDApMdNT&#10;a8qt2x7EqghVIByRWbLs3Qfvc8mWUN0oQbXjZxmW2VgeNG2mnTvXGTaAWFKECV2GwH5Rr7EnnQgv&#10;wsy7Nk94q4oSCTm/5fW7b7dLl3Y/hNeNSuAegUTRyRoVg0hR4VE//XHklBMFmsECDZjo0JnH3XJr&#10;0cgRKXx/n104CLggd9rF55b9+1XCQkQ+hxHhNIPuoXfv8M94wcFnfm363Xck+pY5iBJyHEualDcQ&#10;EcQBwcGTjv3NTUUjhwaW0VrttldDArUWUnnl5Uf//Fo398gwdCrp0UQmDaBKxIT+h89gwEGzBB9F&#10;SJXKRgxxZWXZZb+oQIVM/MyvTL3oXI7GWSXDvk3nBe6GRgE2Pums00uvuFSUEjbosECfQdLu/npE&#10;D+QcC3sHnXhMU05u0EVQJ1uQWT+TKQwRgEhBwbRvXzD2dze7PE/4wM19hy8XIll60+/rP1nZWoqE&#10;dJNnc3IOOu/rpCZhCGqMwmdVdgLte97Xi4cOaRX6nY4Gs0NAWr34/S033mpFXPeJHQ4wFQQbw56N&#10;9ul75DVXNlUNjFBaF0D6V33pVz8vHD6cjemppxswwYvm5M268OKCb50PjlgVxWdbw8uOTGzA3KOn&#10;33ZrUFBCMEkOsdcuDxV8Y4PSPrN//av8YcMZNqohhLxPWzqAEqlnojmVgw7/j3/zS8s8yXTQlURB&#10;zNxUkF8xdgyYVUWzi+gCBOJ4ad/CecdkG6dScgXF07/33UhhKYED7oQudF9GCvlMhq0XL5p+8YUt&#10;E8bGA3IQ+v/h6oHta9n0HTm66PTTLczn/4WZGcwmFht7+lmj/+d3bKNZBhj256WqyiIFGza9fd+9&#10;kmxpJqegLotRmJmNOWjWHEyexMoRhxASj5OR/KKJ809nG/ch7DqM2ik5QoJFG+vfvPl3vKNOQZ50&#10;+82yVgB7P2ea7sFo05bsCoeOGv6jHyR599wLEJGz3sRrry0YN4HJ8T4NQjtjo+SIPCoonPGj7yfG&#10;jzeq8tky5VgyDAXMsKPmDr3uGseGkKFMQkVp+H/+e9nBB6MVU3S8rwrAqjoQQAZaNu6QIf96WQBk&#10;yIJxrFYIQnkzpxdVVhLIarYxjDA+QWwHfGlONsUyUA7Axed+re+IcSAIyGjX7kYr44OQCEmY0app&#10;vApYUQdVULyscuz3v6sdwvuZd3u3iqgzaFF8ZpZy9z0AlUh8zOmnJmG6bS8jg5Xd0++q7c8RGatj&#10;Tp9ffOWV2ccU958XpoBVVsjmm2/f+O57VgLSTPLWFhYNv+AcUqsQVjVKSTLxs0/vO3q0EgwJdTRQ&#10;RJWdkvrLnn+x4YFHU2Xw3Z/gHpspDYJAnIokVURFVAJxvjiRwKlIeiIGEEEZNjbh+OOTAwakxgQS&#10;JjCUPWNtwQXnjz7xxKgxDNvJtVdSpcCRqga+C4LA9/0W19wYNNS75mb1A985XzSQQMhpRw1sAIDZ&#10;GGtNUWX/yVf9JIiEGGL39rxTckq+OieSenlREVVxqqKkLkzB166QHYAAa6zxolPmf63gnDMSu2VJ&#10;G1BgAbAaeKecNOmU0ywbNhyGUwzBoIOKCwLxnTg/4XZu375udd2qFTvXr/ObG4IgSDinoq7jPADG&#10;IwYBYPa8CafNd6NHEqdNkzAEAAFz1THHmljcsAEb7hiD8cX5vu9rEEjQEY8mKMTIgDEjg/wCtSyG&#10;NH1GhjIF7I064cvwIgA8IsB2SofwSZ2vyUTzlg8Xvv+Xh1699fbXb7t98eOP1S79KNmS8J2f7DgG&#10;C2KGJTBgDR80e25i+GACvDBOIyClVjXS+Q7IKYkjSabHW8O4EamIdP0lTlUkrFIX/TyqALZKVZOn&#10;eYcdxmADS2wyQGrZwSxohRslvWcmjnznJJBARVO3UxGlVJK0plM2CmZYz/NmXnQhH30UrMd7h/U4&#10;EglX0KXbA+luhUCZhYWVRQMSCiS2Y/s7d9yOlkQQOs5psRAeefSxwdABAUiZCJyIe1PPOIsjcWNg&#10;YDuF5C0LEwVbtr933Q1eopmcqmr3HYC9I4Pr2qoyzdu3bXn/XWanagkkopFYNL+8LL+in43maPod&#10;xAApxUv7DPja6Zv/41oNA+YI//AbS8oOv/g8ikbQtbJ1TAI1Akaiaf3bby976fnq19/2t1RHexX3&#10;mjplyGHTqqYdZnvlsFrpIv+sNSULMuKIwxfPP1Pvu2cvUqnCKq6geqtil6xBxHJOLtsosw0fQQjl&#10;eZo5jOdPv/R7TzzxjKupRrswXsDwhIhEbGz6JRcgP0/DKGI62JqDoGb7B3/966r7/igLl2jS9/Pi&#10;uRPHH3TO10ccM0/ze7OA0laTunjv8qEXXbju0svT0gkQCcjBVhw8gdKsqgbJ9Ys/rpo4oROoF+ZL&#10;qJiiqgG5M6c3P/tsVMjntKXRDuRXVVaMHC42bVTaCpwkF/7vXQuvviZev80jqFJA+lpx7+E/+t5h&#10;515o8gvSG2saLSmuPHP+5v/4b5+DQJ36Lc5Y0xUaGaZLqokwOJWY07X/L6pJqMBx+yz5NngeSuzX&#10;KxyryuePmhVCDojk5Y849xsfLXhZ4SLSDfR/n+CrQNyWGsCFVC4KshFPcvI9ayGsrUkO6QBSYYqV&#10;9Jry4399/dVXqDFg0u4OOiAHCVQFBO5WaE2VEo0J1qioFW1njmvTA4+uPfNrA4+YAzLp9owAOWXl&#10;A7994aYrfijqoMg99eTy8ePTnS8SDsgtfujPkbfe2xcboscUAFhbajY9d9IpeYlmEk0h6aAgP7/g&#10;mOOmfvfbfSdN5kgkjTcMkIqNVM6atcH8nALHbdsNNODCC0tGjGbuGo5kMQoTiCY3bXzxxhtqf3db&#10;bktzlCgCtUI7Xnzu5QjHTjz1uKuuyh0xnDnBHO3SMLBsJK9gyje/9fKDf464RHcRP2cJDQ13HH9c&#10;bNOmXT+PRnL7Dyw58ojhR8+pGD9JI3GPIOxMGmjVs7bXyFEjLr107VXXdIILjbIYRE/7yoCp04it&#10;Y7Jd0kKJqEjjhnVPX/YD98RfPaEkYFVjTY307AsfPffyqm+cc+x/XmOLSyNp5tOwEWDEEXOWF+RH&#10;t9WmgYxApP6QQb0HDk1nZQU1tWvfemvQhPHU0VoPsSWPrcRzy449Zs3f/wFSVkZXxYAgMkplMw7z&#10;inpxenPOidv68ZLFP/pJXtM2VoQi1VMqqt689oc/9uJFh5x7jolE0yHIxNGKadM2MRlH9X994vH1&#10;m5jQNd2CkiMad9l3qqYeZtMTX6gL3rnzjxtffA6tKcgp+dR+zPU7PeeShiKOPm/BB4AAEuZhs+cs&#10;Hjw0tmqVaCDY61yDrI1I1eTWmjuOODLesNNrtTNMLJo3ZGjvo48YPvvIktFjI8YjgK3pEieFMURU&#10;OWVy0Vln1d96u1GSbta1qLhXfntLwxuvB0TopvxPblgfE1FV1zGRxLY0vPXb31YdMoHzeqc7L5YY&#10;zGOPmre6zw15WzY1eJEpZ3+d4jnp93ywbeXHy355Xdwl9oXWq8cUACkUnCNCJJ62eWuI72hKPPjA&#10;cwtePeK+u6oOm0VpahlCno4+A4YGuXm2vh6qYTZZS0HB6NNOFjbpPQ9HxLqj7tl/u6r5nj/FwQmw&#10;USWlZiYmLkioPvbYE5u3nvSHW3IGDku3AEKGVfsdPN770lx66snuQn5QiHJuU1Nky2Ztj6+tX7/1&#10;9dc2/uKXJZecP/vyy1FR6bV+ostlNdaMPPXUlTf9JrJl8y6hLOQIQmbcV0+nSA5AVkg6Fpi3leIE&#10;jU3PXHW1efxpKAnBE1KoEIEcqwZ33flyeemRP75SbbzrEUAZVNi/f+6RM4OHH0tnlROhz7FHR0tK&#10;0s3Jjo3rq19/Tc/7BluP2lcjEwRqVUA0YPK0VfAc+Ua6TmBWIlGKjRymXuaNKnVrP4kmdpBGlIRb&#10;owGONO5o6a9vGHfcvEj/qnRwDZRKqga1RL3cZpE1axvXrGGlLq0/JUoYxsXfshlzbQKgZXtt058f&#10;joQkWO1iTu3dXqsqQoLPXRzAKRlxASRWVtrvonNqfvgzocCqBvs3PJZKac+v3xGp3tqe8SD4dN3G&#10;555fl39D+RXfnnXJ97yCAtKupXNYDsKWx579zVfuuidoSTB1b35B1FxXXf/wQ0izBzIhAcYIg5ya&#10;jlizI/CTTy/52z/HnTqfyKQx6IlVCgYNqjj37LqfXxc9/pjKqVMzTVai+a1bfx/ZVO14n4gdey5a&#10;wqGkEgicqksheJJUn53kbVi/4KbfBC2NQZCCxTt+FCBY5sK+ZVTZnxlKYJDCFJxyUunQ4ZZthnBL&#10;4IL3/vJA/b33GOdLkGQJsUNlURLnVNhP6usvv/qr/6GWlnThKIAclHPio844WQwzt9YXZOX9SOjG&#10;OAVEufUmUQ0cB36kuXHbTTc/ddkVyS1bnSCt7ACUpGhgVelZ8znF4MMK8kFKkhw5dNCkg9mEkQuY&#10;TsVupESBOvr46aeDP93vXEJTaLMLEU1Vtc7B+ZtvvLl2+XJS1dSPldrdRgAlE49VHDEjbSmAioNW&#10;zZoFdCo0c45ElVR0y5q19Qteatm+XTpiHExkCQQDNqVDBunI4aTiZyog1rzCEkPQ9NhxQGAyHhnH&#10;qnACFZCwKMgR53zyafXKZeq7dnfQdsOpqBYW5aF3X3GOnWOnJNoulCOiFN6qZFSBaEeuqd08OYAU&#10;VlmJ2n9PB8Q4cOoEemClvwt1siNyTn1NpR9bJhjjsWc9b/RR85oKoqQI2hX+EoL9AgBRiqFJSSES&#10;3iRCLmBx3o7aLVf/7G8/uybR2KCpuqqOocRdbkC0/+gx3ryjQxb4bg3CsAUsO7BQxz2w5zsIfPED&#10;2S3XB+qc+Iuuv35n9SZRderCiopOERKQIY/HnHxKQ0GvSeeeE4nHOolnR6oSJJwT5z59+80dt94j&#10;UJZ92kC2hxdwd72g7FiItOEfz+/csLlg0BBNgz+rCqzJKy8Lln6kqYgRDz1unkZs+sMGOCQ3b1p2&#10;3W+iKV6qLvNDEA+0+q57N5wxf+CM2dpVjjiIjMIn03/ylIW5+dGd9S6krczC70UW/KZRoZZHH3t7&#10;zPiZP/weRXO7/h4lAYuxQ7901Ju/vsWKLyBWYiWfacDJJ3q9CjNg2RDjGrd9fNvtVrreFAE4Iuq1&#10;NK145eXSUaPI2Fbvpb1aRNhGpnTYQZ+mD9u4/KJ+o0fstpKcKnBSqXnvPW/jlrpVqytK+qa1GQrz&#10;Bxx37OaFH2U4pQCs9fZkfKB8zNg3ho3IX7bEUViCramSa1KCe/eXN6547EnsrvOJwuY40twU3V6X&#10;rbuXfre3/93/hbZrECLhsEQKICDFFbHL/i4eOqz4q2fU33IrgQ54TqhRarzljqXjx44555sgtkgb&#10;DOCcyJBTT1rx+OOfB+cqxUSwcNFHj/91yvnns0TIiELbGxEgJSCpXDp6TOkl366cfqhjr5ORZ5SS&#10;DBPAr6959/qbrN+iuq8WhO3ZV1XdPdarUAgkp35n87ZthYPTHg2ElcLRiKYImKm5ML/fpEnKGWp8&#10;yZEsf21BzqpP/PQOW8BkhCItjUuefmrg1Bni2bB6FLvJGjYoHDg0Nntm8ORTCEvCemgHBSKeyNob&#10;b6w95bjS0ePTTAJICWz7jZ/YXFlRtGGDUxdyYAbgfjNnkBfJhF4SrV/2UfLVlyPptBRCYmu/7vkX&#10;6MzTabfqc6SKFQnOFeQWCth07V4idvjMvP5V3NkLARE5EW5q2fj8i+yCrcuX9p1yCKfbZuz1O/zw&#10;9b+4wYhLx+urhESihVSRPrcvCo5WDfjSnbe8fNV/Bi+9EPUDFQkMvFRJm9Lfnq175tku9wegIHXU&#10;8wi3fu51gCqUyKkkt2+LRuMmHid0NmbYxseeetpLt98ZD5JKSGnVAzdk0cS71103eO68eN8K8pDG&#10;HoBYW3XwpMU5uZGdOw78PDN5gsC5ZdfdcNDcOTlVwywxdSxZDqlV42wp6h35g+9HcvMM0HkPQT01&#10;KokPnnoieOZZ4oAJ+7gYdn+/fJgz7ijMbRJVNV1azLqLqhxKrORAedOn5Jf2azVM0j3AX/vUMwEH&#10;nvNcV6mwSDFcQkBbHn685YorvZJeXX6fIzWk8CL95h655ulnIgGUHbp35DNHidjbuWPpsy+UjhzX&#10;ZcWbKBikEkRKiku+dIS76x5oSARPXFDQZ9gwFda0eQQQ0k1vfhAV1a6EqRKxugDEMDueePLuQw4l&#10;QEm59VS3Ku+QRkKjycC4NBS1jKpjjraReOehKAkpQNs3bnYfL/VIN7/x+vgz5lOk621mlctGjfT7&#10;FNst1Rk8m/qd9XsOHxpUTpp66r33rX7z1WV/fbz+0Se8uhqFI2IokuysSyfhTcDqCQTSA03j/o9d&#10;KY6UoL6ptm51//ETHNtOOcgg7n/IpJx5R7onn/08uDUsmrfy0zWvLhj1lfkZ3gpEvSqqvAljacEr&#10;3Vfce9c+VDP8LmngkYl+uvb9ex6Y+eMfs4nIbo8VKJMKOJKXr13W9iipUv26dR//13WWfOPYhcHS&#10;fdi1PRUD0FS4Cx2zOUBMpGwj4ERJcW6fMoYERJ1bWoSJt+JU/cT2bUpwrAruM2OGicQ4pPVKc7XU&#10;bd/24kuqJBSkMSFDIlBhJ3b1J1tXLichpc7NOFI0JWAyKB0xgtX4UFFkt+c5Cx2gTOLErXvsEWlu&#10;DJzvOsOYZJgAYmutFy0/+JAWbtNgBqPHFfStsOljEiKKwK9981VNT7Kf4vsPnJf0Y6tWxVaujK9c&#10;FV25Mhb+uWpVdOXK6MoV0ZXLIytX6NrV6eRhwtjy0ZMUrSByBwdQILplzZJo484ktPa5F4OGpgzQ&#10;TX6fspJj50l6RkyjpmHRIklmSLsnwDCYrRcrKR559LwTfnvzl995bdJfHyq+4ofJsRMSNgIyYg0Y&#10;YojYEEgYLiSZUMdOXCrbPK2CaXdTW4O7zIaAfi6LvHZbATUk8Zi38qUFSRWI60wgyMrx2Iivfl05&#10;lWAF0sAPDtSAIRJIsOaJJ52fyCDDoWpy4n1mzeyUKh2uW4Yj7dTXIBkYzzdeks2eb2uVjdqYMzaD&#10;b85OnPPJudU3/7b64yWkADoHAZg4lAGeQcTw7qLHOXV+y1v33hNZtZqERIVEdd9yyHrMA+D2GW8d&#10;CKNZ2EFt8fz5BRVlomR2C6C1lnaaoLG5eeOmPDCJU6I+Q4fu0Zlu2FJDW2uMoJURQTOaD7J9w4b+&#10;B5My0udxoKi8ImEQc9qjfjxI1So1LPxw+6YNhYOHZn6xXgMHpQxyVVEtnTKZrZd5NNLcvPW993OZ&#10;ybn9eAKJaPCQvsMHhxOODutIRhGwbPlwERFFHFo+XVe7Zm1FcZ+03+WZyrlzlt99H6VJZbAkO155&#10;LVFTEy3vn83YkuxZpbyKAUMq+w066gT88IdbV69Y89Y7q/7yiH31LU62JNh5RKwSgITI7KXRr/83&#10;QP49r6UqkReLfvL4EzPO+iqK+3Z+M4ZqdMhh094dNji2dPnnYdBGdctrb1B9A8W6zpJUqKoKUDJs&#10;SHUnAp49LZoQT/zamXTqiSCTjXhUdSAhcO2yj98765t77PKWu33nW3/4w4nX/pLiHjG6tYsCppq3&#10;3t/wq5tz9tJN2a8QkBIhRRTbHo2PAgkyLdOnHPedC5wX6bK+JqwGVl+2b9rgbdqk4lgBYworyhSs&#10;ENW03F4NNdUc+EzIhhAcSts//ZTIMWVq2FZQXOJKevHmrekbhXVfQSoLnFGJNzZt27i2aPCw1uBr&#10;18h0r4pyRxQN+x0RFQyuUljOQHDG1LhtG2/eur9hDCX0PuFYW1hIIcFwh4MHKGkyUb3gNSgZhXX+&#10;1uXLyidMQJeJvELK3H/8hA9zc2P127v2Nsh5Gzase++dIcdVZLNdPXKSYh31DCn1KupbMqV84pQp&#10;Z39ty5IlS556ovrOe2lTLSEQ+DHHjuQLBvvshioQccRyXfW6994ZMvdY7RgdM6JEHC8rG3ruN9f+&#10;6EqQqpLv+wdO/oNVvQ2bG2qqY6Wl6fw1hiqQU1GuSJGXZnlF2Os7aowQsWSXAhjKYlGxNgtGFqgE&#10;dbff/ukp86tmTO2W+FVVaah/45bfxRp2OFLuIQXQUxAQwsSL5li8OSfenJvXnJvflJvXXFzcMOWQ&#10;fr/4ry/f/YeioaO4DfnRzi5SQI7IbV293PN9ARQIGNE+vRXQVLCq62lp2bHNhEWA2HPElklbtmx0&#10;tIe6xkh+oSkqIuqxKs2QhFkBIWKVpu11om2nL40gK8jhWIQIQoYI+f3K0jaCao0wtDQ2RZpa9ne5&#10;jgNVzTiUyZBSpz58YSC1aWtt/Rtvs5IDrOqGV19PK2NBpCipHBSbOjn9xuKIukX33EeNDdkdR+aw&#10;OQcKuM8AACAASURBVBBBAChYAcDkFJRPnnrkT64+8cWX+t/4s6aqSlb28cWW/m2S3piYsUufegaB&#10;37E1kiqrYycwI44+1i8oSLW2dgesds2BiDTqgsZttenOe4p9npDfq1iBLuC5DPsHQiHvNKu2ViNn&#10;uENiQgdkJysUqrFE8r1bfqsNzd1F2Zf//YXGhx+CkpEes/J6jgqCUFBWMf/tt9k5ap2dSMTLLenL&#10;0SgMZ6LbDTtRBP6KfywgFaPERC6/IBbLhQrI65RZq7vmRJq3bxcKm1RwFtKBgi3VnAo1a9oQesRG&#10;yyvk4+U9ZR0qkVKKW1dJk7U7dU9MJTnxXM3J14YWpUCII7lFjAwfUQCys0nEt7JfoGdlMkQ+Gz+/&#10;oHLkGPKYgE7VsGE78bqVK3NqdzgSFiGg5u9/83f8G/cqsWBpz94fzgUT4vH+xx+z5vnnrISrYiC7&#10;mA8BFoh77Kn3T35k0vyzSKGeASFdLJzRxnFNYSOBVj4zQ0RkbMGQwdMvuGTM3ONev+22ut/fxonm&#10;kFrdqHNKXyx9oEpgSyxwsHbr/Q9su/g7BcOHtku7A8gYImbqc9BBxWec0XjH7UyS9N2BGrJx5MBE&#10;0ryzKcMJUgKUbG6+M2xFhJTbqlORCb/DrtwcZNvUPcXTzwoN8xczmqJWIE2PPbLi7K8OP/oEJTWG&#10;KX2Om6gyOV8psXnTwl/fEA0CCWNQPaQCeqwQjJ3aWE6vQYPyhwwpGjyseNCwkoHD8isGIhZTIONS&#10;hbUfqF+7pu7PD+7qQB2NRD2PmTPPf1P9TqvKmi1TSdO2OgoCygy+gWMFBbTPKVbprpadDay6h8bY&#10;zGJMCKkpUSQa3eNZDnx/P8qvkNRcNG/WzMLKilRgvjMxH7G6dUsWe20dzgD9dO3m1Z+wqGI3+A8C&#10;Esfcf/IhTDYwYYf7ThPjSBFQsOQHV298/TWfhZR53yJfzkQLhg078mdXj7/rrkR5PxYIRL9o0r/D&#10;2iJSVBTbtm3lgpeoKxQbIFgz5pQTgrAXkLoDN9TUgIL0MFSqZI1hIh553v4ekmbpXKQsNRcRjgb6&#10;7g03+ts2M8RllFwg5wAVXfHG6+btdwJSpFoD9ZDc7rFZsAzLDLYwakgMkSEYYuY9CHGiQAR+4oPH&#10;HovUVnfcdpDUUU87R04E2g1JnWxoDNOVMswhQF4kuv/2i/P9PVaoW2NMa54+SGOR6B5eUvczmK0h&#10;k78pP+pojcaZje7+RBVNJLYseFVbW/tAxPr+1g8XqROl3dgKgTAfoHzEqOSw4UQQpd0KxRUKT4S3&#10;rv/nt87f8MoL4jcH+3YALIRIEc8Zc8oJsx+4u2H4kMgBE2ifD0+ASKxl1Y/vvkt21KeziionT9aZ&#10;U0Qhzh3YFCfN4L63k51hcdtn5k1lp8FUSHx1tOCVRc/+U1oDoOm/1ggxkxk6bUpw0LCoEHSfU3/2&#10;hwIwShwuCisTQnaHbGLcYZ7+pncWrv3lDaabRN5tFawhd2B2/x/Z9czQ/ZfIF4nn6J5q+JwfkO8z&#10;tXWj3HPaiWK/OgAggs88YNIkwKATs03rtbOutv6lV5wJm26FHi+tf/5lB2Ul11kFgIgNkc0vKP/y&#10;8RHhgJXa8aCGZGoKZVVPEP9k9YLTvr7wzrtkx/Z9WRqQAYwlIybSb+rM2b+/samkWPB/P6tnrycE&#10;FM/NIQLefX/Ne+9TVyYtiDi/YORX5wsBckAVpu4BoQl/z0rkOwr261CxF4MXFk858LxeVWUqMEoB&#10;p9UAIGUSBnLK+o380RVJmIBdD/as4p6cilb5mo3g98n3NUiIOF8a13368k9/HK+rhTi0yV3niyN2&#10;cBrs3uu17Wl5RXkgEmQbFS8sKyNAVVtbTne5RkFLfa32aIso4VRVBIFi+fmEcBBpH9HifEq0EBTE&#10;Skj4zZLJUgCIjCWkomQ9f0lY6jFiSN/Bg5EiLukM6ThFzYqPc2u2iXNhQV/I4V778ovJ6k2irNyh&#10;31prq2jmiDdw1mzfwMhuXexDPh1VFRVH8erqDy+97M/fOn/Niy/4jfW+OHEp5nhH6lJhCJWwtCQt&#10;whe2jGQmgDFwxpFDrrpSjaEv2JXag6FdSh6BogEWP/qgn2gKRFQDv1OQn+2I2XMTJX3dzoS0WjD6&#10;WY9ZDcQxRSJeehmrUOeUEokW9lNhbc1KOJOvFGhrVw91mW9Vp+ogjsJ6TSWzp8ewEtSo4eLzvjl4&#10;6izPsxQ2Kk+7V9mQYQPD3vijj8ecWYyerMU+UK1zlJVYLJPUb1j15OVXeK+8LuA2biwl0pbmRLIl&#10;7I7I6cVeJK+AAJMd/KFEtrCQ2XDmivakn6zd3vOJ3kpKJCBbUNB6stI+ItHY6Dc3hW0RlChIBpQx&#10;vwcEG40pwvhdzysBKAXMZcccbYoL0nuBsmHhR06TCghM2222bt26YgWxWLJdjk2J+o4YkiwqCXjP&#10;B7UgCLzHnlhw3ImPX3TR6r8/27y9VgRKgCrU+ZQkdRBkadELg5gmnHZGy4TxX1D8J5SPIKj67Nc9&#10;8PD2FauUiLQzBQuTye3fr/yMr7Q07jygDgCIkJNXkH6vImSt8HfuCKGZLM8DiEDOCIAQIjaZbyWj&#10;8IQtEUM4GxIoARwHiV4lh3zrXO4mzmx7FYz/3r8IW5977IDbA7SIEEcBNVa/+far//pv3iuvEYkL&#10;yZ3aEI+m5uYdO/IHhAVymi5fPtKr2IG9sOVmFpUA3Lc0EPHIqGg6tsugoSm5tSauJOixmU5VyQHC&#10;yOldQqm6yvQKoLaOAyGBkIKoqaGJVIXUoGsBKqqxwkIXi6Ep6EGIsO3ylJJA/xkzNT1Mp4GTWE7f&#10;q34MmDDtInWooE3NCVXhNJ8FUX55v6K5c5P332sUftqqYHGgAKIQTkjzAw+88cBfeNLEgfPPGjjj&#10;kN7Dh3m5hcxwYAJAwlnYN0YE5Gxp6chvnLP6vfdJhL6QVzQ/N0FMogU7dy7/+7PThg0lL867GTAa&#10;iQ8/8biNS5aR6IEihxOGepFoUWFG14aZtL6uDt3MlhEXqJ8gBotx2bUsFQg5FT+ZFQoNtkDFFZf1&#10;GTW2u/EJZm/ErFlLv3pGy30PkOuZUozPWgEoEVQ0cA2frFr45wdW3fSbnPp6IiOkVkjaJYAYosba&#10;WlUlZqF03TfQq0+pD/Kggj0EEEJ4pKCir/GskBKnFe4N9Tu1bnvrh3rGxw0VgJC6eE5haW9RBTJ4&#10;IdpQXR0lYiIHMuDGLTUspJnaIVFufp4UF2lTw/5YOJ8oKCzoO2okkUkbjjDmsPPPYxVhRrtKC1HV&#10;sFwyQyTDRvode/Tq++8NmNIBY0rKCogJVZ6AIhq4d95Z//47K9nq+IkD5h1dMX1S+UGjcyoqjLFk&#10;ssgMBjtio1o55dBlxkYk+UUU/62pszHhBAfL//CHiV890yvtZzsslwqLDUzZxLEr3l98AEcqIJT1&#10;KSjttQdxKbTz03XcdjyyPqf//MX1Wx59lDSrCjIQlESVTUuTF4ZGtOthhz8OWPwRoyfOn5/N5tzN&#10;VwPi0UkXXfDio09Eg+09Ipl6TAE45wRA4KRjMyUhBimDQarJ5vrarTVLl676xwtb7r7H1tTkiIBI&#10;UvMTtO+DaJzUV29kDdl904rKwr5l2qd3sHlzhukwxIHRqOMGRsnAfqQqUNYOGQJhHYGqgtCwuSan&#10;qUkZhkR6KOOKyTioZ8Bjxxb1G8gAdp98oYDVCoSCLSuXigYIK6BVGzetE0g6Rl4QGUMo6JU3aoRu&#10;WJ9Oa6WKItk4aHvQrH3w2BC1WI05VUUQ8mUogcgZyjl8VnFFlaRXnLa1bYvpPP9ZHDxjB44duySe&#10;4yWa23CgsJzHb2t/FkKE6lohi9AtUPElSo7eemPL229sYCNFRfnzjhp4zLzBh0zL7T+AIgZqrE1X&#10;NxDyEAWlgwZRZT9dtxYBKQRfMF44JVKor46U7LLlyxe8Me6UEwjcTkTAEMMiJ69X2agRfGBi5hA1&#10;1gWxmTNsfmHaF1EiJRGtW7wM3XSHDRuIxj78KDTXuu2ddKVukNJbYXDUG/ujH+QOqBBwe/XqqxpS&#10;R2o0pCFWInDHFpIKMKL9J0zsfcF5O2/8dfgwkOyLw9+THcGat25a9vxzBgFLpO3VVH1J+g3bdjTW&#10;1Ox8792mhYvsjh0gZ32/ndzpYqJZqXbxEjnVWfIy5Hl6JYV506clH30sEzkXwEpJOIoVFPUfrGR2&#10;L9zjVoQOIjWrVjqIlR5MtyWFgDSikZKTjudoJA0+KEZJFIELtrz0qhW41i4c2955l4KkenGkP8Bs&#10;uPf06XV/f0HSmtAIjEbEGaWgHfy1K0YGElUoAiBgNdJ+Obhy3lyNRng/seBAiwdWxadMkQUvtx9Y&#10;kgkKqEmakLdnV1IUgbSTmFaCaKyuNnjggaUPPvR+Se9+3zx/6nln5w8YlG6rQwmgAGzzcuLDhvif&#10;rmFifJFrApSijpbdf9+4Y47RWGR3t1qMrZow4QBxIaljMcqVX5rjrDVpjCEmUpBr2L71pZdi3fcw&#10;2psXPeKyMFHStGZwHDlr7DFHAxbo0JjbIKy5Nj4zgbyQmrbjYQvDgc1eZMo3znrqT3/K2bKFsmNA&#10;+CwUgBhO7Nz5wfnfyU80dixUDtGAVOe7KEKrLZtkFa1+cQH9oEXzIpo+6YtNpOqYYz959HGj6tJm&#10;9SgrOyZv5qFFVYMBUNctv1VEbCAb33gjzDOWnmM/D0VKXSw2afaRMKbL4wMQFIFK07p1iVffjKkG&#10;KfNBGt99r6W6OlpeSeB0Xw/D5ZOnbGUDCdL6IeSIOTFsyJQbbkBr3kvndD9iJfFrqj+44BLT1Bj+&#10;ODBexYQJwmz2k2gEkJtbduy89S8vaP+GEUag5FQEYBXsog1PkdYgPFmttZFeSKQr7DniLbXbfvFf&#10;zz7zxOF3/qF8wgRV6qoTkBKBmcmYvAEDtisJ1OgXWQWQkPjPPLVu0eLyyRMi7VC7UCqyMUUVFQcq&#10;Z9YDN/YpHTZthknvWIZrV7NqBX+y6vPgWvlMSpSrpjnqTf3e91yvIgKjo5UGFYE6aKJ6S7wgPxmJ&#10;WjYK1/41AYAkyl7u8JGDL79885U/8cV5sk89pXtMARglAqLqAqiV9latayu/JmWjpKQBZ6Vgmxd+&#10;uH3thl6jCzL0AwDM4EOnfVRcGK/rAIq1V4tQUmIDrpp/CkcjrIGQ6STbVYlAhtBSu33Ls3/PBYtK&#10;yFKKrFc6PfQXSlUtPOMr5aPGpaUhlZCByt+w6EO7Y5uoGiIlVqip3rJl9Zqq0nLqOnANkApQOWrM&#10;O2WlkfXruhoAhZaFg+l94nFDj5pLxqZyrtDmACiUhAyJX73wQ0kkTZtbPXxon8HDDGE/NQQBKcir&#10;mj5lIxtqVWACVFx2Re5BQ4mYw4RY6pAGDgWSySVXXYWamvBlHSRkUdXUazEWLX75V9efdscfuky6&#10;cKQm1CPMiMUMwYdCmb7AF4ht0n306F/6T5rQ0QKFkDKFpiv207MzXz646tvn51b1ZxJKU2mkUKh+&#10;+u773t7WK/Rsn+aQmSoB651z5sDDZkKM48CI7ZTcDjVE8v6D9/efeHC/Q6eyGu0IfYPUkViCWDv+&#10;tNM+ufvuyJKlbZ7BgYaAQssRwmqUgi7xZWrNsWDJLDdTV25T86eL3ioeOQIZSgtYew0bUXHhRTt+&#10;eT35QejTK7mwL7PsGptrGjJ85OFfYmNTgE9nkiiFqu9k3eJ3o2s/1V1bJ4tAogJKosRETJDWMmNl&#10;NiKsELBaahk0+Kh/uQzxeLrvCaBGVCRY8fgTcK4V7xCCYeFNb79ZecgUQ+nSn5lV45XlAy48d9M1&#10;14LEOHKAatDegiAyztDAI440NkJdRFaUwg85rl61wkpglYShRGXHz4sUFGRTgNk6J5rO0E9vtaF0&#10;xIjkkCpv+YrWnYM+hx86bO6x1tr2qrg9dqh+ctXLL7kHH3JqrfqBhvC9UyLHYGGF2/nP55ura+Ll&#10;FWDq5ExCWamti7wQCACxknyRFYAIsPWuu7Z/69yiocOUOeTaNUxMoP2W/RO2XgaFyPeuMwqoQAEO&#10;mOjQQ6ee8w3yIpS+zpRFmxu3r33wob0oWFMiJgNiYukurWKIarB2LgtmJSX1exUcfsElNi8vjNl1&#10;kisCw04a161bcfMt9UcfVXbIZOuJdJ5rGDIEGDKF/avG/uD7S791YWrf7rVy6nn13XOqk1VWPfxX&#10;NDdkWAkHEqPTvvmNxJgxAvaNJoxjYj80/8JGBSSJCI+/6t9yKysygjRgl1zx5FPczVxAQcroCEKx&#10;T8IqILEijjVpVaH+4CFH3vH74pEjM/g+htRn7Px4xfbHntztV8GqRx53LS2afvQCpzBjzjyzcdgg&#10;EALj0JFkXyhQcpg9Y+Dkqel6UiqBlJwk1i54xQqlEvOVq6ZPJ8uZPSJtdyHNlWEjAhQpKio7/lgO&#10;OWBBBN2++hM1CkdimDh1gxkMMGDAUW/wl49X2CT7nbSOVSWQz2DnBCrUdUq4EgSk4hrXrW9tTfGF&#10;voSIVb26umX/+Hugwi6kVfgM0BJDGoLaIDiCEziBc4AwBWCePG3uDddzvwqoZPAVnOrmt95uefW1&#10;vaiYhbIDHAD1QAbEWd5EzOBIqmlOh8E5JlYuvfT8PqNGZVBaDm7ZP/+e88marffcV79kmc/oirMe&#10;rd+pY445Lpg9O4VdfD4UQJc9gff+CkCNzz67YckiIZf+BRARzhsw4Ijf3pgYMdzCekQCZgUTwRhn&#10;TBArGPgf/z7u5JNgIxmEuEB2rFqx6f4Hu7tv2JFARdSDhTEU3mycYSbbXFiSd9H5xz5yb8Whh7Ex&#10;GYiRnAr85g/++qhXv6PTrBpVefvtLQvfR8bOc1FwyaBhM2+4LigpY7LC7f13smxbyvvPvPpK06so&#10;7QqCVdGyeVPtE0+lXBBwc3FxxdixYA7jJPsNeCCFrTx8VlsFElQ3vfI6+Qk1lC7AQ+ARc+bQ8cda&#10;7VwgEzAUGieTN2FiblFByKHY2TUBgUhUpLGhccVKTRVzfrF7BAAg9SAr7rhTaqolNGz2vwIQIjj1&#10;QTAw8IAIkVUyYA369O175Y+Ou/euPuMnRuApRNPXfmqicdF990ecvxe6PNCAgySDlEWYhJHlrQyf&#10;yGdmQqcUfcu2ZeiwQ8/+hnixDO/esnXLkt/+HqqxnTs+fOwRTbYElMFYZNu7z/RLL2029nMRBN4f&#10;EsGIiTW3vPfnh48fN4lMPF0xWMCWpLli8qHH/uUvb/7mtzX33RtpaDasjqjFY3vwhImXf3/EUccj&#10;Esugm1ihklz0yGN527Z1dzqdUSPkR6JV3znPCwnLAQLl5OXm9u3bd/CwggED1BhWI3CsnB7N0uqP&#10;Pl77m99F2ZCTXWi3gmA8F3z44EP9px3GkUhXlguIrGMxokO/dAzuu+31q39m3nzHUKrO0wFNhxx8&#10;+H9fWzF1BmeywsAkq9/9ILZ+g2OyQgrNn3VYbkUllNJEIEhUWTv2t+kqN01B6ao1Qn+byfQbOfrt&#10;woLItm1h+unOF19u3rzVDMyznZd/1z+8Xn2OvO7f/x4k3DPPchuAC2JFYJTyiiZdcSniUQ0xbHR+&#10;LisMUd2WrbRufQrHhHyRFQDCThhC9NGST15/bcgJ8yJkpGMT8/1xMQnn5h905Q8tWJUVYMO5ubm5&#10;5WV9hg8pKK8g9sAaen9dZQamCufXvfFmw5//YmRvkHwlPuikk5rmzE4xm3VH74kGweYN71/4/Uhz&#10;ffskgiRo9A+viA0YZNL0rAURqVv+3POxxUtIVYjW//625jPOyB9+UAYtTUgOmDl70ckn+w89sNdR&#10;gM+zAlAlR8o7/vfu9fNPKZ88TchGTMo+aacJQ/EYJ0Lvgw469le/2va9725buzLZ2EImUlRWUTq4&#10;yhb2Ira7bxhRAYU8TBJIUPfRyrU3/T7mRLsZBLIEYnjx6JyLv9tqNaeMSxB1zNvpDKKrhm3lFArX&#10;1PzqLb/Lq631O5CsKJELlBDQtrv/uPHrZ5VNnBIGMtoL0/CvhpiY2PLgOUf1Hz12/YcfbP5oacvO&#10;hlhhQZ+hIwZMnhYrKVLLnB5SU+eSDTs+vvvuQMkQwBoYb9Axc00kmiqcRuc5JFK/uenDRx+1rv3S&#10;tD8CCiJHMHk5Y084iWy4Fto+DS6s2rWWCqoGFs39UvPDDxtnCc7W1q5447WJlQMFMGnoeizb4iGj&#10;TvnD7cuff3HN356tfusdbK8HqS0t7X3k7LGnntr34IlAxKT4ITucPSUFBy7gtQvftU0NpBqQoy+0&#10;/KewF7aSeJJYev+DQ4+aSzFJQdD787LsmZKiwy/5DrArSggiMNofm5BjEJ3PsmNygbCr3f769b/W&#10;5iQpHLrd0snz7IAph7RaEd37dCCuZtG7LtnoqXJr22gHosNmjTnxJMtmN3RESShgx2KSdTXLbrlF&#10;JCAlJrU11R8+/vCMy3+oHA1T3To1PBFW1ojk0+SLL3jxqaeiLQ1wYUd2+f9GARCIWBWN9W/fdOvx&#10;vx1r8wopDPF3YQqCiASi0Ujh4KHFgwcF6gAGGyV03Y+QiBWOhRRQpubGN2+83qurCxjs9kadAghP&#10;CHa3UbuyW1s/pQkgEoDILf7rX5ruupdYYs4E1MUgvIamt2/+3bG/G8m2KA0dZwh9kFET6V1RNad0&#10;8JHHgkRJfeIIwYUyPH0mT0C0+rkXgr/9I0IuAAWEJEy/SePSfSAgZ4Wb1qz96DtXROq3tc+96vza&#10;zM39yodPn27Lyk36WDJ7XsUxc1c//GjoF8eElt/xp3FHHYOiPiZD9EYMlZQPP+30g04+mVsSrrmF&#10;SDkW4ZwcZQ/SddYKiKwowWqyac1Dj5kvPPq/+7XjqadqFn7cd/ohRvQzQIFARMbufk6yqsjViLrG&#10;N+68PfjHCzlKe9cYqZ0X2+23ZcLOmm2GJDRthEySnbKdcvl3vJJi+n/tXXmQXVWZ/37fuff1lhDD&#10;LhJghk1FBdmKokTZxBpRpkpnBpFSwbHisA0oMCOOitRsVTNllaLDjMMq68BYJVtCSAIJSROgkyCQ&#10;FQIJ6SSdrdNJL2+795zvN3/cl6S70+/ldfaB99Wr/JGkX5977jnf/v1+yDrThnggBKIQGcK7s2ba&#10;vDccK66foy2758HTrvjm2GOOz2Iv7OiqQSNEE845+7CJV/X++q4IlsJGm/U6wNvdSJiXUH78iTce&#10;f8xbScgaI5pOJAYj58zl4qjZuZxCoxrFIlRgR30o/PF/nhh45GHTENs+fkLGQcqWX/Va+/xbb4tC&#10;0hRc9TlUFh5/YuEzT9KXa5j62CpOUuQcnMI556JmderUQaMqypdkCKG0euXcf/038amBLlBNoo+f&#10;cMhxJ1aZPxCVKACd777T3L/Ziakw+0AMEiBBxZQETb2PVq9et2RRBmok1YFNjz7t9HJTUxCj0IvZ&#10;zNmLpz0HX6x1+R0d2ESJ4+Zo7LimIw7PHXG4O+gQjVucOo1q5HzNQvp+x5z85Oc+5Kn/ESVXLi18&#10;+ikmZX9go2WH4H1SfPuZZ9/9p39s9qkwUPZ1PZ/mBzZs1CyvIFAiRjzmG1ecdP4FgAaRYZlFI0yY&#10;iPktmxf+9m5J05gqmuVJ0bai883JUyQNzModw+lXVYU5U8m1nH3VVYVDD0tUsCtG60BW/0KK5IIq&#10;06U/+Vnn7HYxPzyjMuQHXFaEVlQgA0UQanWemAuawnfOmLnkH34Cai7shKBnj4uJKm3TW2/Nvu7G&#10;5g3dNKTqUHWiTRjCkr//adfrb6hVB2UDleaMKqrZNeC2WR5hVawdsVKp/Ve/id54vYlRIAgJkMP/&#10;7OJo3Phqm+goan5Dx3wISRW67KPU7AOqUU1Akci48q03EExq6Vocdtzx8Wmf9s5AMYhj+a2f/0vf&#10;iuWDZ5ZHrKCYVhqGKdkpqMCvhlp9/Sj3bOr4xa/ipCgNGeGOuM777893rjrA1wmzlbNefO2Gm8YW&#10;0gBLYbY/pjk2rVyVAV5RNIBpa/MZ101EyxhTOpMwrPWTAgtgWDGr3Wa0R3BFFTFTEQNBv/w3dxc2&#10;btKRrisIFfEuQDju5I8ff+P3RXQXOnS1XlVcT1KMtaCbd60IQDLQaJLbvPmVG27smtcRUp/BdQfa&#10;sCG4bfw/Ktv6szBs3MJTxBjEjGbezNJ1czpmX/u3TRu74b2RsntkFxhCV1BN6RsZvKU00qcrOl6a&#10;PvEaXbxIGIQGSz2rsl07Ird6zQs3/XDj24t9knoL5HB3GkClXbLSUTeEmyd7R15oIkYaxYIlgcV8&#10;3yt3//fmO38N7wMTNVLUgD8578IaLjQp1te7etKzCUAa6bOPMWSY6sYA8aBlkxZdk6dJqVwTCFUw&#10;tu1jX71MIIBDEGfMLVs+6ed3FNavDWnZggULshXk3SRT9nDqHLQCP5r9iexOIBp6KAPphfQWgtlA&#10;vv3ee9zkKUJrqPsRDHxIm7p7lkx/Pvi0TlWBqu6cVGigd+MekUYG0hJhShrF+9SXSu9Mm9T+3b9p&#10;2rAhbB0Fwn6Y5fDJsqVmoARREjjiuolHf+Y0jaIYDjqcyBoZ43Kh8OZ996lPLaTOgmTMeSZmjBYv&#10;XDJtUmLpjq3+gEAQIVJVjZvOvOLb6Ukn7EKObo+p630QIDa/vWzy1RM7X3lBLJgEJXcBqQ0SEqUQ&#10;IIx++dQpL337u82rO7dqs30R2IAJBEpn+d4Fjz40+6+ualqwmNwWsbL2DwegZe78Kd+/rmfBIgs0&#10;COhl1K2rJmQAhCI0LQzMvffBVT/6cRT8thV4Mf+Rgw8/5STWbJ/a9P6K8PY7zqSeNZRem9ezZiV2&#10;Eq7i6HPOVOYMQjgP5AKb/vfZ6bf/rNizkYBK4FZq7107wc7Eq6GQ73jgns23/3s2afQB1+VV2Ft2&#10;0rdNzZlfes8DYfOWA0FJUGiiFHWW6dMQertf/u1/zb9yYtO69RHp6PdbtJT6TW8vy55SjcVjjjrr&#10;6u9J9dZPFSGl85WO8vPTR3w9Slt6932ypWcbuHq1XWmeMOGUW2/ehZBH631z+/120IL4g5YuQkPu&#10;tgAACmJJREFUmfUXV87/3b2l/l5PqpV3IW/rDN778qZNr951V/uV34lWvw+/j3wFMyPFM1dOk7Vv&#10;znv2B7cs/utr47WryLTOyrMGMSJI2vxK+6RvXbF86iQp5dMwutF8igQnSrGQeisMrFv7/B23r7n5&#10;h+KHgCHHcB+56KKxHz3a1egasrBm0cLWcqL1Wc+2QnHNordQ090m9YhPfCo5ZgIzbB9FyQVjOX/v&#10;g89ed0PvgtcTgwUGWhAZPWgPaaXErNjVNe2f71h5y48sDBiE8mGkhNzp1E6qQtAtXLLitVctBO5v&#10;kFQKSEkYKGUW+1e3t//+muu7br5V+7bQGFmcYL8xuyW9fcnKzkqU6fSUW3449vjjawz+JMFLIf/6&#10;7x6IfbmKtyfW0fHOzJm1Ge5U1En06Uu/6s89d29FANiZDefOXNfddx6UiKi57s3Lrr1p6vU3ru94&#10;lamOdlxbgkihv/PF55/6zrdX3vrj1oH+nO1k8GvPPRVB8/lC16tzZtx227SLLsk/9BAYIqqJ1slg&#10;5St08hBqy7LlHZd/64Wf3t737hIJnqyXFh4iUZZgz/cve+a5py6/vP/Ou5TDOTKhOOqSCyVuqqWt&#10;LXTOas/VHYwFhjWz5ogPNbaVqs3jDj3ysktVYAiRUS1LhHo++fTTl339zQfuKW/odsF0eKGPO9P9&#10;pJEDfsWUyZO++a3uX9yp9I6idcM/onaeY+/GxTthYGTtdWBX1uPElBqFdNEjj0my38kSqIQL5np7&#10;V06f8cwPbnrpy3/ufv+kUECJGDxSB+6vNEVfb5/r3pIdj+TMsz71tb90cKI1FLesnPd6+ocnqx0n&#10;UFqDLbjnfvb21SxjicJ0/MFn3HhD6kbX2BnVq3QIpqWQxMO62AfltYVJngrZOyEYjRRJsguflouP&#10;PD7zqeearvz66V/7xkdP/URu/MGUCIpKCZ0kIELL6udQM68+KW3ctHLe/EWPPZ4++bRa4kJl2qrG&#10;rVKQ4gRipUJIyhiVVSAIAwPzhS3dmzavXrXhzbfef2ZyaJ8dpWnTIJOkddcdnJmIIGtV9xaFZMMv&#10;f/n0ow9PmPi9k7/y5SNO+KS0NUWuKeMPRoZStNXZM8uA0olgW9au6ux4delDj/ipM6O0nPnRw85Y&#10;0eGYE0/wIYlNBtfSB29CaW1Xz/SZrXVfLbXQPWlK6da/c4cd6kao54MiKoHKo889u+c//lN99vcB&#10;leI1mztXvvP965aecf/JE68+4XPnjZtwXNTckoICUSOgrJD9ZNjW2emkwOjTvtWrVs394+KHHypO&#10;m96SpADBbMa43kDCq2OSD2mpMqA3clasLKFEDboHHWankhSC74fFodo4XggWSg4qCBjUBWkqKPen&#10;SVEreKgYrg+Dt1CO6FJYAKMw5N4FCeKl+OTTq6+fe8RZn3WIBAaOjGhrEiQEEYoOASIxJ6BZUqKI&#10;jlYTIyBJ04GBLT09PZ2ruubNX/OHp7BgYZQmUYXQ0rJ7JBSEqh10cDCkIS2Jd4I9XyEe6FrTlCYU&#10;NedOv/Ga5oPHSJKEkbMnoNAKA3984H5XLlY7fRAxCX7G7OWvvHTshV8MWhXS3ISOPPkLFyy87FI+&#10;NcnEg1pPWQuP1vFgaQSNm1q/9CV1MVml/Vwd+/r6X5gaiUN2AvZmOECgVaIymEZSPvHECZd+5cgz&#10;zxg/YULb+PFtbWPi1lZGMdO0XBgYyA8U127sef+91XPmdD/3fMu6DWAQmlDr4YqgQxw0yWnbxV9k&#10;cwtG0v5VMfrNhFZcvz5dtz7ZtKGlUIpJgVjYMxmnjCqTChNxcPm4pfmszx516YVHfurMg4/6aMv4&#10;cbkxbXGuBSKW+mKhmO/fMrBu/ZZ331vz8subp07N9Wxy3ovAqqA7MHZjLrmo3NIW28gOJEXSvr7y&#10;zBebvXhlPXyKcEpB8wUXa1srHba71IOA/iGSQJt6t5RmzLQwsm00p4qoOPaggz53zpHnf/7Qk04e&#10;97Fjm8cd3NraFOVy4lSE5XK+nM8Xe/v612/sfu/d7pfae2bOyG3pgTEyilkY/awonMafPw/jD9Gh&#10;wHg2JFtqydIlXLqUonuKYzJyitM+g+OOzRnCiMqLENJ3rZK5r5cRBreOaOT04vNd60GOJEbKFtIG&#10;5nbEXetT8cqRYyFA9fRT9dgJsTgBWfFIsWOGBobi/Lns6hI/6N1FEdtaWy+8yKkLtNF440zTYnlD&#10;t+9ah+7N8KXIrALgN8q9RaQ85pgxp54uYBiygN0JDbaf2/KGjZjzspoztaaLvxDGjgGjrecEO/x/&#10;WDkdePGFuJw3EVflUaCIKMmnP9n6pydSt0cTg41o5sWqgmbJ8vfcgkXePEWxRwwARAitNBKCg33K&#10;QUqBUKqJVzpGYS/XYVSQKqWCQR2ZhBwlVRpyaXNTMnaMtrU5F2mScKA/GshH5XIAKYxMgiI2Upg6&#10;jepI/UMBqnchCkLqCN5TVR1CIIMkJkQcxQSh0iCc7ikDsE13OkE2h2sQQhNRGTsGY9qktRkUJokN&#10;5DHQH6dpTKqIR0azRa9SBWkJQKQSDOZVXNCRHF4q6JUaIiLUU0RXuKBBibJjzm/7ziFhGB0piE0o&#10;rFYZAaAiRnqFMDaQKmhtC2PatKWFCqNJoSSFgvYPNJNKUqyskjOAxgoINkbL/AWFEkEYQDfoLhgG&#10;GTMVrxYHcXSBYY+8a8ApxTsz0AXsqKMJMUdSI0pESzlkzzM+olTh/IhTgBTJyBYE1Q+0VqjawIzg&#10;aofzQDA4xkG9mojqIONNOENwFaANHU3JnRncceZ4OlGpALjaKNt8QDiIAZoiRCYj6bHdSsrFQBHm&#10;JBIJIi42Kysp6mwwju2g3wpmiV+lGKuR+EWEmVoW4srWThUMShvZ4PF7QZbLNdR1tuuKAAgB1Rwd&#10;h3k021YBoHIovRJh71aKCHGEBxyhykCLxHlkYwMCgKQg2yJCRE200mIpiqxDTHRHXLAqGssgkUkA&#10;BlvUujLGGXgChahwDILUXZ1R3KmGwFbYHzCbOMl4OLmtgTcIs6ZYAzKC9cyIVgua6bZuoghsKLDD&#10;tuOGyNF7RhgEv11bgVaCVgz5zu3eNMWJBlApqapWIbdBpn9IYUUvEZUMh5mhkgk0Q0YpKqYam4Vs&#10;RgJmAKgREWSUzoo6FQtkxCFjPYPrSAox0Zgoa63a3ajEHJTimFVBq0FtKwiv5iq5z+3vceuJHbJo&#10;YqifJ+IoqcqIjeeEiCIyCWDEkRMtEBGNAwJIrcz7bfeGQGZYUhh1VIStBlug4syREhB0tAk2AGTi&#10;JEc3XI/tVnVyu0Lf6vdlq9Ws02JoZ/kgzz0D16aYVGWuhMCr5Lg9ViVrTsOIpApn9eY06zIAw05J&#10;zeLYvhYMBR/gqBe+75bX+I0HxkNs/3LIrjN/1bPEfc6biP0+zLw7W/qB26b9pRRHk1rclXTXKP9p&#10;70YDda1hv70DNn7jAfcQQ+hk9uoS8cF/+Tuu4P8BnAY/NK9j5wGtNKQhDWlIQz6U0jAADWlIQxrS&#10;MAANaUhDGtKQhgFoSEMa0pCGNAxAQxrSkIY0pGEAGtKQhjSkIR8g+T9l8WcDNsHdwAAAAABJRU5E&#10;rkJggg==&#10;"
-       id="image1"
-       x="0.086311005"
-       y="0.29999173" /></g></svg>
diff --git a/music_assistant/providers/podcast-index/icon_monochrome.svg b/music_assistant/providers/podcast-index/icon_monochrome.svg
deleted file mode 100644 (file)
index 84b762f..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   width="512"
-   height="512"
-   viewBox="0 0 135.46665 135.46665"
-   version="1.1"
-   id="svg1"
-   xml:space="preserve"
-   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
-   sodipodi:docname="icon_monochrome.svg"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
-     id="namedview1"
-     pagecolor="#73ffff"
-     bordercolor="#000000"
-     borderopacity="0.25"
-     inkscape:showpageshadow="2"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="0"
-     inkscape:deskcolor="#d1d1d1"
-     inkscape:document-units="mm"
-     inkscape:zoom="1.4142136"
-     inkscape:cx="256.3262"
-     inkscape:cy="247.13381"
-     inkscape:window-width="1920"
-     inkscape:window-height="1129"
-     inkscape:window-x="-8"
-     inkscape:window-y="-8"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="layer1" /><defs
-     id="defs1" /><g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1"><image
-       width="135.46666"
-       height="135.46666"
-       preserveAspectRatio="none"
-       xlink:href="data:image/png;base64,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&#10;OvT20f8Bc/DKiBseNBIAAAAASUVORK5CYII=&#10;"
-       id="image1"
-       x="0.086311005"
-       y="0.29999173" /></g></svg>
diff --git a/music_assistant/providers/podcast-index/manifest.json b/music_assistant/providers/podcast-index/manifest.json
deleted file mode 100644 (file)
index 3b27a0b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "domain": "podcast-index",
-  "name": "Podcast Index",
-  "description": "Discover and play podcasts using the open Podcast Index.",
-  "documentation": "https://music-assistant.io/music-providers/podcast-index/",
-  "type": "music",
-  "requirements": [],
-  "codeowners": "@ozgav",
-  "multi_instance": false,
-  "stage": "beta"
-}
diff --git a/music_assistant/providers/podcast-index/provider.py b/music_assistant/providers/podcast-index/provider.py
deleted file mode 100644 (file)
index aca7f10..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-"""Podcast Index provider implementation."""
-
-from __future__ import annotations
-
-from collections.abc import AsyncGenerator, Sequence
-from typing import Any, cast
-
-import aiohttp
-from music_assistant_models.enums import ContentType, MediaType, StreamType
-from music_assistant_models.errors import (
-    InvalidDataError,
-    LoginFailed,
-    MediaNotFoundError,
-    ProviderUnavailableError,
-)
-from music_assistant_models.media_items import (
-    AudioFormat,
-    BrowseFolder,
-    MediaItemType,
-    Podcast,
-    PodcastEpisode,
-    SearchResults,
-)
-from music_assistant_models.streamdetails import StreamDetails
-
-from music_assistant.constants import VERBOSE_LOG_LEVEL
-from music_assistant.controllers.cache import use_cache
-from music_assistant.models.music_provider import MusicProvider
-
-from .constants import (
-    BROWSE_CATEGORIES,
-    BROWSE_RECENT,
-    BROWSE_TRENDING,
-    CONF_API_KEY,
-    CONF_API_SECRET,
-    CONF_STORED_PODCASTS,
-)
-from .helpers import make_api_request, parse_episode_from_data, parse_podcast_from_feed
-
-
-class PodcastIndexProvider(MusicProvider):
-    """Podcast Index provider for Music Assistant."""
-
-    api_key: str = ""
-    api_secret: str = ""
-
-    async def handle_async_init(self) -> None:
-        """Handle async initialization of the provider."""
-        self.api_key = str(self.config.get_value(CONF_API_KEY))
-        self.api_secret = str(self.config.get_value(CONF_API_SECRET))
-
-        if not self.api_key or not self.api_secret:
-            raise LoginFailed("API key and secret are required")
-
-        # Test API connection
-        try:
-            await self._api_request("stats/current")
-        except (LoginFailed, ProviderUnavailableError):
-            # Re-raise these specific errors as they have proper context
-            raise
-        except aiohttp.ClientConnectorError as err:
-            raise ProviderUnavailableError(
-                f"Failed to connect to Podcast Index API: {err}"
-            ) from err
-        except aiohttp.ServerTimeoutError as err:
-            raise ProviderUnavailableError(f"Podcast Index API timeout: {err}") from err
-        except Exception as err:
-            raise LoginFailed(f"Failed to connect to API: {err}") from err
-
-    async def search(
-        self, search_query: str, media_types: list[MediaType], limit: int = 10
-    ) -> SearchResults:
-        """
-        Perform search on Podcast Index.
-
-        Searches for podcasts by term. Future enhancement could include
-        category search if needed.
-        """
-        result = SearchResults()
-        if MediaType.PODCAST not in media_types:
-            return result
-
-        response = await self._api_request(
-            "search/byterm", params={"q": search_query, "max": limit}
-        )
-
-        podcasts = []
-        for feed_data in response.get("feeds", []):
-            podcast = parse_podcast_from_feed(
-                feed_data, self.lookup_key, self.domain, self.instance_id
-            )
-            if podcast:
-                podcasts.append(podcast)
-
-        result.podcasts = podcasts
-        return result
-
-    async def browse(self, path: str) -> Sequence[BrowseFolder | Podcast | PodcastEpisode]:
-        """Browse this provider's items."""
-        base = f"{self.instance_id}://"
-
-        if path == base:
-            # Return main browse categories
-            return [
-                BrowseFolder(
-                    item_id=BROWSE_TRENDING,
-                    provider=self.domain,
-                    path=f"{base}{BROWSE_TRENDING}",
-                    name="Trending Podcasts",
-                ),
-                BrowseFolder(
-                    item_id=BROWSE_RECENT,
-                    provider=self.domain,
-                    path=f"{base}{BROWSE_RECENT}",
-                    name="Recent Episodes",
-                ),
-                BrowseFolder(
-                    item_id=BROWSE_CATEGORIES,
-                    provider=self.domain,
-                    path=f"{base}{BROWSE_CATEGORIES}",
-                    name="Categories",
-                ),
-            ]
-
-        # Parse path after base
-        if path.startswith(base):
-            subpath_parts = path[len(base) :].split("/")
-            subpath = subpath_parts[0] if subpath_parts else ""
-
-            if subpath == BROWSE_TRENDING:
-                return await self._browse_trending()
-            elif subpath == BROWSE_RECENT:
-                return await self._browse_recent_episodes()
-            elif subpath == BROWSE_CATEGORIES:
-                if len(subpath_parts) > 1:
-                    # Browse specific category - category name is directly in path
-                    category_name = subpath_parts[1]
-                    return await self._browse_category_podcasts(category_name)
-                else:
-                    # Browse categories
-                    return await self._browse_categories()
-
-        return []
-
-    async def library_add(self, item: MediaItemType) -> bool:
-        """
-        Add podcast to library.
-
-        Retrieves the RSS feed URL for the podcast and adds it to the stored
-        podcasts configuration. Returns True if successfully added, False if
-        the podcast was already in the library or if the feed URL couldn't be found.
-        """
-        # Only handle podcasts - delegate others to base class
-        if not isinstance(item, Podcast):
-            return await super().library_add(item)
-
-        stored_podcasts = cast("list[str]", self.config.get_value(CONF_STORED_PODCASTS))
-
-        # Get the RSS URL from the podcast via API
-        try:
-            feed_url = await self._get_feed_url_for_podcast(item.item_id)
-        except Exception as err:
-            self.logger.warning(
-                "Failed to retrieve feed URL for podcast %s: %s", item.name, err, exc_info=True
-            )
-            return False
-
-        if not feed_url:
-            self.logger.warning(
-                "No feed URL found for podcast %s (ID: %s)", item.name, item.item_id
-            )
-            return False
-
-        if feed_url in stored_podcasts:
-            return False
-
-        self.logger.debug("Adding podcast %s to library", item.name)
-        stored_podcasts.append(feed_url)
-        self.update_config_value(CONF_STORED_PODCASTS, stored_podcasts)
-        return True
-
-    async def library_remove(self, prov_item_id: str, media_type: MediaType) -> bool:
-        """
-        Remove podcast from library.
-
-        Removes the podcast's RSS feed URL from the stored podcasts configuration.
-        Always returns True for idempotent operation. If feed URL retrieval fails,
-        logs a warning but still returns True to maintain the idempotent contract
-        as required by MA convention.
-        """
-        stored_podcasts = cast("list[str]", self.config.get_value(CONF_STORED_PODCASTS))
-
-        # Get the RSS URL for this podcast
-        try:
-            feed_url = await self._get_feed_url_for_podcast(prov_item_id)
-        except Exception as err:
-            self.logger.warning(
-                "Failed to retrieve feed URL for podcast removal %s: %s",
-                prov_item_id,
-                err,
-                exc_info=True,
-            )
-            # Still return True for idempotent operation
-            return True
-
-        if not feed_url or feed_url not in stored_podcasts:
-            return True
-
-        self.logger.debug("Removing podcast %s from library", prov_item_id)
-        stored_podcasts = [x for x in stored_podcasts if x != feed_url]
-        self.update_config_value(CONF_STORED_PODCASTS, stored_podcasts)
-        return True
-
-    @use_cache(3600 * 24 * 14)  # Cache for 14 days
-    async def get_podcast(self, prov_podcast_id: str) -> Podcast:
-        """Get podcast details."""
-        try:
-            # Try by ID first
-            response = await self._api_request("podcasts/byfeedid", params={"id": prov_podcast_id})
-            if response.get("feed"):
-                podcast = parse_podcast_from_feed(
-                    response["feed"], self.lookup_key, self.domain, self.instance_id
-                )
-                if podcast:
-                    return podcast
-        except (ProviderUnavailableError, InvalidDataError):
-            # Re-raise these specific errors
-            raise
-        except Exception as err:
-            self.logger.debug("Unexpected error getting podcast %s: %s", prov_podcast_id, err)
-
-        raise MediaNotFoundError(f"Podcast {prov_podcast_id} not found")
-
-    async def get_podcast_episodes(
-        self, prov_podcast_id: str
-    ) -> AsyncGenerator[PodcastEpisode, None]:
-        """Get episodes for a podcast."""
-        self.logger.debug("Getting episodes for podcast ID: %s", prov_podcast_id)
-
-        # Try to get the podcast name from the current context first
-        podcast_name = None
-        try:
-            podcast = await self.mass.music.podcasts.get_provider_item(
-                prov_podcast_id, self.instance_id
-            )
-            if podcast:
-                podcast_name = podcast.name
-                self.logger.debug("Got podcast name from MA context: %s", podcast_name)
-        except Exception as err:
-            self.logger.debug("Could not get podcast from MA context: %s", err)
-
-        # If we don't have the name, get it from the API
-        if not podcast_name:
-            try:
-                podcast_response = await self._api_request(
-                    "podcasts/byfeedid", params={"id": prov_podcast_id}
-                )
-                if podcast_response.get("feed"):
-                    podcast_name = podcast_response["feed"].get("title")
-                    self.logger.debug("Got podcast name from API fallback: %s", podcast_name)
-            except Exception as err:
-                self.logger.warning("Could not get podcast name from API: %s", err)
-
-        try:
-            response = await self._api_request(
-                "episodes/byfeedid", params={"id": prov_podcast_id, "max": 1000}
-            )
-
-            episodes = response.get("items", [])
-            for idx, episode_data in enumerate(episodes):
-                episode = parse_episode_from_data(
-                    episode_data,
-                    prov_podcast_id,
-                    idx,
-                    self.lookup_key,
-                    self.domain,
-                    self.instance_id,
-                    podcast_name,
-                )
-                if episode:
-                    yield episode
-
-        except (ProviderUnavailableError, InvalidDataError):
-            # Re-raise these specific errors
-            raise
-        except Exception as err:
-            self.logger.warning(
-                "Unexpected error getting episodes for %s: %s", prov_podcast_id, err
-            )
-
-    @use_cache(43200)  # Cache for 12 hours
-    async def get_podcast_episode(self, prov_episode_id: str) -> PodcastEpisode:
-        """
-        Get podcast episode details using direct API lookup.
-
-        Uses the efficient episodes/byid endpoint for direct episode retrieval.
-        """
-        try:
-            podcast_id, episode_id = prov_episode_id.split("|", 1)
-
-            response = await self._api_request("episodes/byid", params={"id": episode_id})
-            episode_data = response.get("episode")
-
-            if episode_data:
-                episode = parse_episode_from_data(
-                    episode_data, podcast_id, 0, self.lookup_key, self.domain, self.instance_id
-                )
-                if episode:
-                    return episode
-
-        except (ProviderUnavailableError, InvalidDataError):
-            # Re-raise these specific errors
-            raise
-        except ValueError as err:
-            # Handle malformed episode ID
-            raise InvalidDataError(f"Invalid episode ID format: {prov_episode_id}") from err
-        except Exception as err:
-            self.logger.warning("Unexpected error getting episode %s: %s", prov_episode_id, err)
-
-        raise MediaNotFoundError(f"Episode {prov_episode_id} not found")
-
-    @use_cache(86400)
-    async def get_stream_details(self, item_id: str, media_type: MediaType) -> StreamDetails:
-        """
-        Get stream details for a podcast episode.
-
-        Uses the Podcast Index episodes/byid endpoint for efficient direct lookup
-        rather than fetching all episodes for a podcast.
-        """
-        if media_type != MediaType.PODCAST_EPISODE:
-            raise MediaNotFoundError("Stream details only available for episodes")
-
-        try:
-            podcast_id, episode_id = item_id.split("|", 1)
-
-            # Use direct episode lookup for efficiency
-            response = await self._api_request("episodes/byid", params={"id": episode_id})
-            episode_data = response.get("episode")
-
-            if episode_data:
-                stream_url = episode_data.get("enclosureUrl")
-                if stream_url:
-                    return StreamDetails(
-                        provider=self.lookup_key,
-                        item_id=item_id,
-                        audio_format=AudioFormat(
-                            content_type=ContentType.try_parse(
-                                episode_data.get("enclosureType") or "audio/mpeg"
-                            ),
-                        ),
-                        media_type=MediaType.PODCAST_EPISODE,
-                        stream_type=StreamType.HTTP,
-                        path=stream_url,
-                        allow_seek=True,
-                    )
-
-        except (ProviderUnavailableError, InvalidDataError):
-            # Re-raise these specific errors
-            raise
-        except ValueError as err:
-            # Handle malformed episode ID
-            raise InvalidDataError(f"Invalid episode ID format: {item_id}") from err
-        except Exception as err:
-            self.logger.warning("Unexpected error getting stream for %s: %s", item_id, err)
-
-        raise MediaNotFoundError(f"Stream not found for {item_id}")
-
-    async def get_item(self, media_type: MediaType, prov_item_id: str) -> Podcast | PodcastEpisode:
-        """Get single MediaItem from provider."""
-        if media_type == MediaType.PODCAST:
-            return await self.get_podcast(prov_item_id)
-        elif media_type == MediaType.PODCAST_EPISODE:
-            return await self.get_podcast_episode(prov_item_id)
-        else:
-            raise MediaNotFoundError(f"Media type {media_type} not supported by this provider")
-
-    async def _fetch_podcasts(
-        self, endpoint: str, params: dict[str, Any] | None = None
-    ) -> list[Podcast]:
-        """Fetch and parse podcasts from API endpoint."""
-        response = await self._api_request(endpoint, params)
-        podcasts = []
-        for feed_data in response.get("feeds", []):
-            podcast = parse_podcast_from_feed(
-                feed_data, self.lookup_key, self.domain, self.instance_id
-            )
-            if podcast:
-                podcasts.append(podcast)
-        return podcasts
-
-    async def _api_request(
-        self, endpoint: str, params: dict[str, Any] | None = None
-    ) -> dict[str, Any]:
-        """Make authenticated request to Podcast Index API."""
-        self.logger.log(
-            VERBOSE_LOG_LEVEL, "Making API request to %s with params: %s", endpoint, params
-        )
-        return await make_api_request(self.mass, self.api_key, self.api_secret, endpoint, params)
-
-    async def _get_feed_url_for_podcast(self, podcast_id: str) -> str | None:
-        """Get RSS feed URL for a podcast ID."""
-        try:
-            response = await self._api_request("podcasts/byfeedid", params={"id": podcast_id})
-            feed_data: dict[str, Any] = response.get("feed", {})
-            return feed_data.get("url")
-        except (ProviderUnavailableError, InvalidDataError):
-            # Re-raise these specific errors
-            raise
-        except Exception as err:
-            self.logger.warning(
-                "Unexpected error getting feed URL for podcast %s: %s",
-                podcast_id,
-                err,
-                exc_info=True,
-            )
-            return None
-
-    @use_cache(7200)  # Cache for 2 hours
-    async def _browse_trending(self) -> list[Podcast]:
-        """Browse trending podcasts."""
-        try:
-            return await self._fetch_podcasts("podcasts/trending", {"max": 50})
-        except (ProviderUnavailableError, InvalidDataError):
-            raise
-        except Exception as err:
-            self.logger.warning(
-                "Unexpected error getting trending podcasts: %s", err, exc_info=True
-            )
-            return []
-
-    @use_cache(14400)  # Cache for 4 hours
-    async def _browse_recent_episodes(self) -> list[PodcastEpisode]:
-        """Browse recent episodes."""
-        try:
-            response = await self._api_request("recent/episodes", params={"max": 50})
-
-            episodes = []
-            for idx, episode_data in enumerate(response.get("items", [])):
-                # Extract podcast ID from episode data
-                podcast_id = str(episode_data.get("feedId", ""))
-                # Pass feedTitle to avoid unnecessary API calls
-                podcast_name = episode_data.get("feedTitle")
-                episode = parse_episode_from_data(
-                    episode_data,
-                    podcast_id,
-                    idx,
-                    self.lookup_key,
-                    self.domain,
-                    self.instance_id,
-                    podcast_name,
-                )
-                if episode:
-                    episodes.append(episode)
-
-            return episodes
-
-        except (ProviderUnavailableError, InvalidDataError):
-            # Re-raise these specific errors
-            raise
-        except Exception as err:
-            self.logger.warning("Unexpected error getting recent episodes: %s", err, exc_info=True)
-            return []
-
-    @use_cache(86400)  # Cache for 24 hours
-    async def _browse_categories(self) -> list[BrowseFolder]:
-        """Browse podcast categories."""
-        try:
-            response = await self._api_request("categories/list")
-
-            categories = []
-            # Categories API returns feeds array with {id, name} objects
-            categories_data = response.get("feeds", [])
-
-            for category in categories_data:
-                cat_name = category.get("name", "Unknown Category")
-
-                categories.append(
-                    BrowseFolder(
-                        item_id=cat_name,  # Use name as ID
-                        provider=self.domain,
-                        path=f"{self.instance_id}://{BROWSE_CATEGORIES}/{cat_name}",
-                        name=cat_name,
-                    )
-                )
-
-            # Sort by name
-            return sorted(categories, key=lambda x: x.name)
-
-        except (ProviderUnavailableError, InvalidDataError):
-            # Re-raise these specific errors
-            raise
-        except Exception as err:
-            self.logger.warning("Unexpected error getting categories: %s", err, exc_info=True)
-            return []
-
-    @use_cache(43200)  # Cache for 12 hours
-    async def _browse_category_podcasts(self, category_name: str) -> list[Podcast]:
-        """Browse podcasts in a specific category using search."""
-        try:
-            # Search for podcasts using the category name directly
-            search_response = await self._api_request(
-                "search/byterm", params={"q": category_name, "max": 50}
-            )
-
-            podcasts = []
-            for feed_data in search_response.get("feeds", []):
-                podcast = parse_podcast_from_feed(
-                    feed_data, self.lookup_key, self.domain, self.instance_id
-                )
-                if podcast:
-                    podcasts.append(podcast)
-
-            return podcasts
-
-        except (ProviderUnavailableError, InvalidDataError):
-            raise
-        except Exception as err:
-            self.logger.warning(
-                "Unexpected error getting category podcasts: %s", err, exc_info=True
-            )
-            return []
diff --git a/music_assistant/providers/podcast_index/__init__.py b/music_assistant/providers/podcast_index/__init__.py
new file mode 100644 (file)
index 0000000..599d482
--- /dev/null
@@ -0,0 +1,71 @@
+"""Podcast Index provider for Music Assistant."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from music_assistant_models.config_entries import ConfigEntry, ConfigValueType
+from music_assistant_models.enums import ConfigEntryType, ProviderFeature
+
+from .constants import CONF_API_KEY, CONF_API_SECRET, CONF_STORED_PODCASTS
+from .provider import PodcastIndexProvider
+
+if TYPE_CHECKING:
+    from music_assistant_models.config_entries import ProviderConfig
+    from music_assistant_models.provider import ProviderManifest
+
+    from music_assistant.mass import MusicAssistant
+    from music_assistant.models import ProviderInstanceType
+
+SUPPORTED_FEATURES = {
+    ProviderFeature.SEARCH,
+    ProviderFeature.BROWSE,
+}
+
+
+async def setup(
+    mass: MusicAssistant, manifest: ProviderManifest, config: ProviderConfig
+) -> ProviderInstanceType:
+    """Initialize provider(instance) with given configuration."""
+    return PodcastIndexProvider(mass, manifest, config, SUPPORTED_FEATURES)
+
+
+async def get_config_entries(
+    mass: MusicAssistant,
+    instance_id: str | None = None,
+    action: str | None = None,
+    values: dict[str, ConfigValueType] | None = None,
+) -> tuple[ConfigEntry, ...]:
+    """
+    Return Config entries to setup this provider.
+
+    instance_id: id of an existing provider instance (None if new instance setup).
+    action: [optional] action key called from config entries UI.
+    values: the (intermediate) raw values for config entries sent with the action.
+    """
+    # ruff: noqa: ARG001
+    return (
+        ConfigEntry(
+            key=CONF_API_KEY,
+            type=ConfigEntryType.STRING,
+            label="API Key",
+            required=True,
+            description="Your Podcast Index API key. Get your free API credentials at https://api.podcastindex.org/",
+        ),
+        ConfigEntry(
+            key=CONF_API_SECRET,
+            type=ConfigEntryType.SECURE_STRING,
+            label="API Secret",
+            required=True,
+            description="Your Podcast Index API secret",
+        ),
+        ConfigEntry(
+            key=CONF_STORED_PODCASTS,
+            type=ConfigEntryType.STRING,
+            multi_value=True,
+            label="Subscribed Podcasts",
+            default_value=[],
+            required=False,
+            hidden=True,
+        ),
+    )
diff --git a/music_assistant/providers/podcast_index/constants.py b/music_assistant/providers/podcast_index/constants.py
new file mode 100644 (file)
index 0000000..46eb24d
--- /dev/null
@@ -0,0 +1,14 @@
+"""Constants for Podcast Index provider."""
+
+# Configuration keys
+CONF_API_KEY = "api_key"
+CONF_API_SECRET = "api_secret"
+CONF_STORED_PODCASTS = "stored_podcasts"
+
+# API settings
+API_BASE_URL = "https://api.podcastindex.org/api/1.0"
+
+# Browse categories
+BROWSE_TRENDING = "trending"
+BROWSE_RECENT = "recent"
+BROWSE_CATEGORIES = "categories"
diff --git a/music_assistant/providers/podcast_index/helpers.py b/music_assistant/providers/podcast_index/helpers.py
new file mode 100644 (file)
index 0000000..858fa8d
--- /dev/null
@@ -0,0 +1,218 @@
+"""Helper functions for Podcast Index provider."""
+
+from __future__ import annotations
+
+import hashlib
+import time
+from datetime import UTC, datetime
+from typing import TYPE_CHECKING, Any
+
+import aiohttp
+from music_assistant_models.enums import ContentType, ImageType, MediaType
+from music_assistant_models.errors import (
+    InvalidDataError,
+    LoginFailed,
+    ProviderUnavailableError,
+)
+from music_assistant_models.media_items import (
+    AudioFormat,
+    ItemMapping,
+    MediaItemImage,
+    Podcast,
+    PodcastEpisode,
+    ProviderMapping,
+    UniqueList,
+)
+
+from .constants import API_BASE_URL
+
+if TYPE_CHECKING:
+    from music_assistant.mass import MusicAssistant
+
+
+async def make_api_request(
+    mass: MusicAssistant,
+    api_key: str,
+    api_secret: str,
+    endpoint: str,
+    params: dict[str, Any] | None = None,
+) -> dict[str, Any]:
+    """
+    Make authenticated request to Podcast Index API.
+
+    Handles authentication using SHA1 hash of API key, secret, and timestamp.
+    Maps HTTP errors appropriately: 401 -> LoginFailed, others -> ProviderUnavailableError.
+    """
+    # Prepare authentication headers
+    auth_date = str(int(time.time()))
+    auth_string = api_key + api_secret + auth_date
+    auth_hash = hashlib.sha1(auth_string.encode()).hexdigest()
+
+    headers = {
+        "X-Auth-Key": api_key,
+        "X-Auth-Date": auth_date,
+        "Authorization": auth_hash,
+    }
+
+    url = f"{API_BASE_URL}/{endpoint}"
+
+    try:
+        async with mass.http_session.get(url, headers=headers, params=params or {}) as response:
+            response.raise_for_status()
+
+            try:
+                data: dict[str, Any] = await response.json()
+            except aiohttp.ContentTypeError as err:
+                raise InvalidDataError("Invalid JSON response from API") from err
+
+            if str(data.get("status")).lower() != "true":
+                raise InvalidDataError(data.get("description") or "API error")
+
+            return data
+
+    except aiohttp.ClientConnectorError as err:
+        raise ProviderUnavailableError(f"Failed to connect to Podcast Index API: {err}") from err
+    except aiohttp.ServerTimeoutError as err:
+        raise ProviderUnavailableError(f"Podcast Index API timeout: {err}") from err
+    except aiohttp.ClientResponseError as err:
+        if err.status == 401:
+            raise LoginFailed(f"Authentication failed: {err.status}") from err
+        raise ProviderUnavailableError(f"API request failed: {err.status}") from err
+
+
+def parse_podcast_from_feed(
+    feed_data: dict[str, Any], lookup_key: str, domain: str, instance_id: str
+) -> Podcast | None:
+    """Parse podcast from API feed data."""
+    feed_url = feed_data.get("url")
+    podcast_id = feed_data.get("id")
+
+    if not feed_url or not podcast_id:
+        return None
+
+    podcast = Podcast(
+        item_id=str(podcast_id),
+        name=feed_data.get("title", "Unknown Podcast"),
+        publisher=feed_data.get("author") or feed_data.get("ownerName", "Unknown"),
+        provider=lookup_key,
+        provider_mappings={
+            ProviderMapping(
+                item_id=str(podcast_id),
+                provider_domain=domain,
+                provider_instance=instance_id,
+                url=feed_url,
+            )
+        },
+    )
+
+    # Add metadata
+    podcast.metadata.description = feed_data.get("description", "")
+    podcast.metadata.explicit = bool(feed_data.get("explicit", False))
+
+    # Set episode count only if provided
+    episode_count = feed_data.get("episodeCount")
+    if episode_count is not None:
+        podcast.total_episodes = int(episode_count) or 0
+
+    # Add image - prefer 'image' field, fallback to 'artwork'
+    image_url = feed_data.get("image") or feed_data.get("artwork")
+    if image_url:
+        podcast.metadata.add_image(
+            MediaItemImage(
+                type=ImageType.THUMB,
+                path=image_url,
+                provider=lookup_key,
+                remotely_accessible=True,
+            )
+        )
+
+    # Add categories as genres - categories is a dict {id: name}
+    categories = feed_data.get("categories", {})
+    if categories and isinstance(categories, dict):
+        podcast.metadata.genres = set(categories.values())
+
+    # Add language
+    language = feed_data.get("language", "")
+    if language:
+        podcast.metadata.languages = UniqueList([language])
+
+    return podcast
+
+
+def parse_episode_from_data(
+    episode_data: dict[str, Any],
+    podcast_id: str,
+    episode_idx: int,
+    lookup_key: str,
+    domain: str,
+    instance_id: str,
+    podcast_name: str | None = None,
+) -> PodcastEpisode | None:
+    """Parse episode from API episode data."""
+    episode_api_id = episode_data.get("id")
+    if not episode_api_id:
+        return None
+
+    episode_id = f"{podcast_id}|{episode_api_id}"
+
+    position = episode_data.get("episode")
+    if position is None:
+        position = episode_idx + 1
+
+    if podcast_name is None:
+        podcast_name = episode_data.get("feedTitle") or "Unknown Podcast"
+
+    raw_duration = episode_data.get("duration")
+    try:
+        duration = int(raw_duration) if raw_duration is not None else 0
+    except (ValueError, TypeError):
+        duration = 0
+
+    episode = PodcastEpisode(
+        item_id=episode_id,
+        provider=lookup_key,
+        name=episode_data.get("title", "Unknown Episode"),
+        duration=duration,
+        position=position,
+        podcast=ItemMapping(
+            item_id=podcast_id,
+            provider=lookup_key,
+            name=podcast_name,
+            media_type=MediaType.PODCAST,
+        ),
+        provider_mappings={
+            ProviderMapping(
+                item_id=episode_id,
+                provider_domain=domain,
+                provider_instance=instance_id,
+                available=True,
+                audio_format=AudioFormat(
+                    content_type=ContentType.try_parse(
+                        episode_data.get("enclosureType") or "audio/mpeg"
+                    ),
+                ),
+                url=episode_data.get("enclosureUrl"),
+            )
+        },
+    )
+
+    # Add metadata
+    episode.metadata.description = episode_data.get("description", "")
+    episode.metadata.explicit = bool(episode_data.get("explicit", 0))
+
+    date_published = episode_data.get("datePublished")
+    if date_published:
+        episode.metadata.release_date = datetime.fromtimestamp(date_published, tz=UTC)
+
+    image_url = episode_data.get("image") or episode_data.get("feedImage")
+    if image_url:
+        episode.metadata.add_image(
+            MediaItemImage(
+                type=ImageType.THUMB,
+                path=image_url,
+                provider=lookup_key,
+                remotely_accessible=True,
+            )
+        )
+
+    return episode
diff --git a/music_assistant/providers/podcast_index/icon.svg b/music_assistant/providers/podcast_index/icon.svg
new file mode 100644 (file)
index 0000000..52c2eba
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="512"
+   height="512"
+   viewBox="0 0 135.46665 135.46665"
+   version="1.1"
+   id="svg1"
+   xml:space="preserve"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   sodipodi:docname="icon.svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
+     id="namedview1"
+     pagecolor="#ffffff"
+     bordercolor="#000000"
+     borderopacity="0.25"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1"
+     inkscape:document-units="mm"
+     inkscape:zoom="1.4142136"
+     inkscape:cx="256.3262"
+     inkscape:cy="247.13381"
+     inkscape:window-width="1920"
+     inkscape:window-height="1129"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1" /><defs
+     id="defs1" /><g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"><image
+       width="135.46666"
+       height="135.46666"
+       preserveAspectRatio="none"
+       xlink:href="data:image/png;base64,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&#10;rkJggg==&#10;"
+       id="image1"
+       x="0.086311005"
+       y="0.29999173" /></g></svg>
diff --git a/music_assistant/providers/podcast_index/icon_monochrome.svg b/music_assistant/providers/podcast_index/icon_monochrome.svg
new file mode 100644 (file)
index 0000000..84b762f
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="512"
+   height="512"
+   viewBox="0 0 135.46665 135.46665"
+   version="1.1"
+   id="svg1"
+   xml:space="preserve"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   sodipodi:docname="icon_monochrome.svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
+     id="namedview1"
+     pagecolor="#73ffff"
+     bordercolor="#000000"
+     borderopacity="0.25"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1"
+     inkscape:document-units="mm"
+     inkscape:zoom="1.4142136"
+     inkscape:cx="256.3262"
+     inkscape:cy="247.13381"
+     inkscape:window-width="1920"
+     inkscape:window-height="1129"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1" /><defs
+     id="defs1" /><g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"><image
+       width="135.46666"
+       height="135.46666"
+       preserveAspectRatio="none"
+       xlink:href="data:image/png;base64,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&#10;OvT20f8Bc/DKiBseNBIAAAAASUVORK5CYII=&#10;"
+       id="image1"
+       x="0.086311005"
+       y="0.29999173" /></g></svg>
diff --git a/music_assistant/providers/podcast_index/manifest.json b/music_assistant/providers/podcast_index/manifest.json
new file mode 100644 (file)
index 0000000..e4a75dc
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "domain": "podcast_index",
+  "name": "Podcast Index",
+  "description": "Discover and play podcasts using the open Podcast Index.",
+  "documentation": "https://music-assistant.io/music-providers/podcast_index/",
+  "type": "music",
+  "requirements": [],
+  "codeowners": "@ozgav",
+  "multi_instance": false,
+  "stage": "beta"
+}
diff --git a/music_assistant/providers/podcast_index/provider.py b/music_assistant/providers/podcast_index/provider.py
new file mode 100644 (file)
index 0000000..aca7f10
--- /dev/null
@@ -0,0 +1,521 @@
+"""Podcast Index provider implementation."""
+
+from __future__ import annotations
+
+from collections.abc import AsyncGenerator, Sequence
+from typing import Any, cast
+
+import aiohttp
+from music_assistant_models.enums import ContentType, MediaType, StreamType
+from music_assistant_models.errors import (
+    InvalidDataError,
+    LoginFailed,
+    MediaNotFoundError,
+    ProviderUnavailableError,
+)
+from music_assistant_models.media_items import (
+    AudioFormat,
+    BrowseFolder,
+    MediaItemType,
+    Podcast,
+    PodcastEpisode,
+    SearchResults,
+)
+from music_assistant_models.streamdetails import StreamDetails
+
+from music_assistant.constants import VERBOSE_LOG_LEVEL
+from music_assistant.controllers.cache import use_cache
+from music_assistant.models.music_provider import MusicProvider
+
+from .constants import (
+    BROWSE_CATEGORIES,
+    BROWSE_RECENT,
+    BROWSE_TRENDING,
+    CONF_API_KEY,
+    CONF_API_SECRET,
+    CONF_STORED_PODCASTS,
+)
+from .helpers import make_api_request, parse_episode_from_data, parse_podcast_from_feed
+
+
+class PodcastIndexProvider(MusicProvider):
+    """Podcast Index provider for Music Assistant."""
+
+    api_key: str = ""
+    api_secret: str = ""
+
+    async def handle_async_init(self) -> None:
+        """Handle async initialization of the provider."""
+        self.api_key = str(self.config.get_value(CONF_API_KEY))
+        self.api_secret = str(self.config.get_value(CONF_API_SECRET))
+
+        if not self.api_key or not self.api_secret:
+            raise LoginFailed("API key and secret are required")
+
+        # Test API connection
+        try:
+            await self._api_request("stats/current")
+        except (LoginFailed, ProviderUnavailableError):
+            # Re-raise these specific errors as they have proper context
+            raise
+        except aiohttp.ClientConnectorError as err:
+            raise ProviderUnavailableError(
+                f"Failed to connect to Podcast Index API: {err}"
+            ) from err
+        except aiohttp.ServerTimeoutError as err:
+            raise ProviderUnavailableError(f"Podcast Index API timeout: {err}") from err
+        except Exception as err:
+            raise LoginFailed(f"Failed to connect to API: {err}") from err
+
+    async def search(
+        self, search_query: str, media_types: list[MediaType], limit: int = 10
+    ) -> SearchResults:
+        """
+        Perform search on Podcast Index.
+
+        Searches for podcasts by term. Future enhancement could include
+        category search if needed.
+        """
+        result = SearchResults()
+        if MediaType.PODCAST not in media_types:
+            return result
+
+        response = await self._api_request(
+            "search/byterm", params={"q": search_query, "max": limit}
+        )
+
+        podcasts = []
+        for feed_data in response.get("feeds", []):
+            podcast = parse_podcast_from_feed(
+                feed_data, self.lookup_key, self.domain, self.instance_id
+            )
+            if podcast:
+                podcasts.append(podcast)
+
+        result.podcasts = podcasts
+        return result
+
+    async def browse(self, path: str) -> Sequence[BrowseFolder | Podcast | PodcastEpisode]:
+        """Browse this provider's items."""
+        base = f"{self.instance_id}://"
+
+        if path == base:
+            # Return main browse categories
+            return [
+                BrowseFolder(
+                    item_id=BROWSE_TRENDING,
+                    provider=self.domain,
+                    path=f"{base}{BROWSE_TRENDING}",
+                    name="Trending Podcasts",
+                ),
+                BrowseFolder(
+                    item_id=BROWSE_RECENT,
+                    provider=self.domain,
+                    path=f"{base}{BROWSE_RECENT}",
+                    name="Recent Episodes",
+                ),
+                BrowseFolder(
+                    item_id=BROWSE_CATEGORIES,
+                    provider=self.domain,
+                    path=f"{base}{BROWSE_CATEGORIES}",
+                    name="Categories",
+                ),
+            ]
+
+        # Parse path after base
+        if path.startswith(base):
+            subpath_parts = path[len(base) :].split("/")
+            subpath = subpath_parts[0] if subpath_parts else ""
+
+            if subpath == BROWSE_TRENDING:
+                return await self._browse_trending()
+            elif subpath == BROWSE_RECENT:
+                return await self._browse_recent_episodes()
+            elif subpath == BROWSE_CATEGORIES:
+                if len(subpath_parts) > 1:
+                    # Browse specific category - category name is directly in path
+                    category_name = subpath_parts[1]
+                    return await self._browse_category_podcasts(category_name)
+                else:
+                    # Browse categories
+                    return await self._browse_categories()
+
+        return []
+
+    async def library_add(self, item: MediaItemType) -> bool:
+        """
+        Add podcast to library.
+
+        Retrieves the RSS feed URL for the podcast and adds it to the stored
+        podcasts configuration. Returns True if successfully added, False if
+        the podcast was already in the library or if the feed URL couldn't be found.
+        """
+        # Only handle podcasts - delegate others to base class
+        if not isinstance(item, Podcast):
+            return await super().library_add(item)
+
+        stored_podcasts = cast("list[str]", self.config.get_value(CONF_STORED_PODCASTS))
+
+        # Get the RSS URL from the podcast via API
+        try:
+            feed_url = await self._get_feed_url_for_podcast(item.item_id)
+        except Exception as err:
+            self.logger.warning(
+                "Failed to retrieve feed URL for podcast %s: %s", item.name, err, exc_info=True
+            )
+            return False
+
+        if not feed_url:
+            self.logger.warning(
+                "No feed URL found for podcast %s (ID: %s)", item.name, item.item_id
+            )
+            return False
+
+        if feed_url in stored_podcasts:
+            return False
+
+        self.logger.debug("Adding podcast %s to library", item.name)
+        stored_podcasts.append(feed_url)
+        self.update_config_value(CONF_STORED_PODCASTS, stored_podcasts)
+        return True
+
+    async def library_remove(self, prov_item_id: str, media_type: MediaType) -> bool:
+        """
+        Remove podcast from library.
+
+        Removes the podcast's RSS feed URL from the stored podcasts configuration.
+        Always returns True for idempotent operation. If feed URL retrieval fails,
+        logs a warning but still returns True to maintain the idempotent contract
+        as required by MA convention.
+        """
+        stored_podcasts = cast("list[str]", self.config.get_value(CONF_STORED_PODCASTS))
+
+        # Get the RSS URL for this podcast
+        try:
+            feed_url = await self._get_feed_url_for_podcast(prov_item_id)
+        except Exception as err:
+            self.logger.warning(
+                "Failed to retrieve feed URL for podcast removal %s: %s",
+                prov_item_id,
+                err,
+                exc_info=True,
+            )
+            # Still return True for idempotent operation
+            return True
+
+        if not feed_url or feed_url not in stored_podcasts:
+            return True
+
+        self.logger.debug("Removing podcast %s from library", prov_item_id)
+        stored_podcasts = [x for x in stored_podcasts if x != feed_url]
+        self.update_config_value(CONF_STORED_PODCASTS, stored_podcasts)
+        return True
+
+    @use_cache(3600 * 24 * 14)  # Cache for 14 days
+    async def get_podcast(self, prov_podcast_id: str) -> Podcast:
+        """Get podcast details."""
+        try:
+            # Try by ID first
+            response = await self._api_request("podcasts/byfeedid", params={"id": prov_podcast_id})
+            if response.get("feed"):
+                podcast = parse_podcast_from_feed(
+                    response["feed"], self.lookup_key, self.domain, self.instance_id
+                )
+                if podcast:
+                    return podcast
+        except (ProviderUnavailableError, InvalidDataError):
+            # Re-raise these specific errors
+            raise
+        except Exception as err:
+            self.logger.debug("Unexpected error getting podcast %s: %s", prov_podcast_id, err)
+
+        raise MediaNotFoundError(f"Podcast {prov_podcast_id} not found")
+
+    async def get_podcast_episodes(
+        self, prov_podcast_id: str
+    ) -> AsyncGenerator[PodcastEpisode, None]:
+        """Get episodes for a podcast."""
+        self.logger.debug("Getting episodes for podcast ID: %s", prov_podcast_id)
+
+        # Try to get the podcast name from the current context first
+        podcast_name = None
+        try:
+            podcast = await self.mass.music.podcasts.get_provider_item(
+                prov_podcast_id, self.instance_id
+            )
+            if podcast:
+                podcast_name = podcast.name
+                self.logger.debug("Got podcast name from MA context: %s", podcast_name)
+        except Exception as err:
+            self.logger.debug("Could not get podcast from MA context: %s", err)
+
+        # If we don't have the name, get it from the API
+        if not podcast_name:
+            try:
+                podcast_response = await self._api_request(
+                    "podcasts/byfeedid", params={"id": prov_podcast_id}
+                )
+                if podcast_response.get("feed"):
+                    podcast_name = podcast_response["feed"].get("title")
+                    self.logger.debug("Got podcast name from API fallback: %s", podcast_name)
+            except Exception as err:
+                self.logger.warning("Could not get podcast name from API: %s", err)
+
+        try:
+            response = await self._api_request(
+                "episodes/byfeedid", params={"id": prov_podcast_id, "max": 1000}
+            )
+
+            episodes = response.get("items", [])
+            for idx, episode_data in enumerate(episodes):
+                episode = parse_episode_from_data(
+                    episode_data,
+                    prov_podcast_id,
+                    idx,
+                    self.lookup_key,
+                    self.domain,
+                    self.instance_id,
+                    podcast_name,
+                )
+                if episode:
+                    yield episode
+
+        except (ProviderUnavailableError, InvalidDataError):
+            # Re-raise these specific errors
+            raise
+        except Exception as err:
+            self.logger.warning(
+                "Unexpected error getting episodes for %s: %s", prov_podcast_id, err
+            )
+
+    @use_cache(43200)  # Cache for 12 hours
+    async def get_podcast_episode(self, prov_episode_id: str) -> PodcastEpisode:
+        """
+        Get podcast episode details using direct API lookup.
+
+        Uses the efficient episodes/byid endpoint for direct episode retrieval.
+        """
+        try:
+            podcast_id, episode_id = prov_episode_id.split("|", 1)
+
+            response = await self._api_request("episodes/byid", params={"id": episode_id})
+            episode_data = response.get("episode")
+
+            if episode_data:
+                episode = parse_episode_from_data(
+                    episode_data, podcast_id, 0, self.lookup_key, self.domain, self.instance_id
+                )
+                if episode:
+                    return episode
+
+        except (ProviderUnavailableError, InvalidDataError):
+            # Re-raise these specific errors
+            raise
+        except ValueError as err:
+            # Handle malformed episode ID
+            raise InvalidDataError(f"Invalid episode ID format: {prov_episode_id}") from err
+        except Exception as err:
+            self.logger.warning("Unexpected error getting episode %s: %s", prov_episode_id, err)
+
+        raise MediaNotFoundError(f"Episode {prov_episode_id} not found")
+
+    @use_cache(86400)
+    async def get_stream_details(self, item_id: str, media_type: MediaType) -> StreamDetails:
+        """
+        Get stream details for a podcast episode.
+
+        Uses the Podcast Index episodes/byid endpoint for efficient direct lookup
+        rather than fetching all episodes for a podcast.
+        """
+        if media_type != MediaType.PODCAST_EPISODE:
+            raise MediaNotFoundError("Stream details only available for episodes")
+
+        try:
+            podcast_id, episode_id = item_id.split("|", 1)
+
+            # Use direct episode lookup for efficiency
+            response = await self._api_request("episodes/byid", params={"id": episode_id})
+            episode_data = response.get("episode")
+
+            if episode_data:
+                stream_url = episode_data.get("enclosureUrl")
+                if stream_url:
+                    return StreamDetails(
+                        provider=self.lookup_key,
+                        item_id=item_id,
+                        audio_format=AudioFormat(
+                            content_type=ContentType.try_parse(
+                                episode_data.get("enclosureType") or "audio/mpeg"
+                            ),
+                        ),
+                        media_type=MediaType.PODCAST_EPISODE,
+                        stream_type=StreamType.HTTP,
+                        path=stream_url,
+                        allow_seek=True,
+                    )
+
+        except (ProviderUnavailableError, InvalidDataError):
+            # Re-raise these specific errors
+            raise
+        except ValueError as err:
+            # Handle malformed episode ID
+            raise InvalidDataError(f"Invalid episode ID format: {item_id}") from err
+        except Exception as err:
+            self.logger.warning("Unexpected error getting stream for %s: %s", item_id, err)
+
+        raise MediaNotFoundError(f"Stream not found for {item_id}")
+
+    async def get_item(self, media_type: MediaType, prov_item_id: str) -> Podcast | PodcastEpisode:
+        """Get single MediaItem from provider."""
+        if media_type == MediaType.PODCAST:
+            return await self.get_podcast(prov_item_id)
+        elif media_type == MediaType.PODCAST_EPISODE:
+            return await self.get_podcast_episode(prov_item_id)
+        else:
+            raise MediaNotFoundError(f"Media type {media_type} not supported by this provider")
+
+    async def _fetch_podcasts(
+        self, endpoint: str, params: dict[str, Any] | None = None
+    ) -> list[Podcast]:
+        """Fetch and parse podcasts from API endpoint."""
+        response = await self._api_request(endpoint, params)
+        podcasts = []
+        for feed_data in response.get("feeds", []):
+            podcast = parse_podcast_from_feed(
+                feed_data, self.lookup_key, self.domain, self.instance_id
+            )
+            if podcast:
+                podcasts.append(podcast)
+        return podcasts
+
+    async def _api_request(
+        self, endpoint: str, params: dict[str, Any] | None = None
+    ) -> dict[str, Any]:
+        """Make authenticated request to Podcast Index API."""
+        self.logger.log(
+            VERBOSE_LOG_LEVEL, "Making API request to %s with params: %s", endpoint, params
+        )
+        return await make_api_request(self.mass, self.api_key, self.api_secret, endpoint, params)
+
+    async def _get_feed_url_for_podcast(self, podcast_id: str) -> str | None:
+        """Get RSS feed URL for a podcast ID."""
+        try:
+            response = await self._api_request("podcasts/byfeedid", params={"id": podcast_id})
+            feed_data: dict[str, Any] = response.get("feed", {})
+            return feed_data.get("url")
+        except (ProviderUnavailableError, InvalidDataError):
+            # Re-raise these specific errors
+            raise
+        except Exception as err:
+            self.logger.warning(
+                "Unexpected error getting feed URL for podcast %s: %s",
+                podcast_id,
+                err,
+                exc_info=True,
+            )
+            return None
+
+    @use_cache(7200)  # Cache for 2 hours
+    async def _browse_trending(self) -> list[Podcast]:
+        """Browse trending podcasts."""
+        try:
+            return await self._fetch_podcasts("podcasts/trending", {"max": 50})
+        except (ProviderUnavailableError, InvalidDataError):
+            raise
+        except Exception as err:
+            self.logger.warning(
+                "Unexpected error getting trending podcasts: %s", err, exc_info=True
+            )
+            return []
+
+    @use_cache(14400)  # Cache for 4 hours
+    async def _browse_recent_episodes(self) -> list[PodcastEpisode]:
+        """Browse recent episodes."""
+        try:
+            response = await self._api_request("recent/episodes", params={"max": 50})
+
+            episodes = []
+            for idx, episode_data in enumerate(response.get("items", [])):
+                # Extract podcast ID from episode data
+                podcast_id = str(episode_data.get("feedId", ""))
+                # Pass feedTitle to avoid unnecessary API calls
+                podcast_name = episode_data.get("feedTitle")
+                episode = parse_episode_from_data(
+                    episode_data,
+                    podcast_id,
+                    idx,
+                    self.lookup_key,
+                    self.domain,
+                    self.instance_id,
+                    podcast_name,
+                )
+                if episode:
+                    episodes.append(episode)
+
+            return episodes
+
+        except (ProviderUnavailableError, InvalidDataError):
+            # Re-raise these specific errors
+            raise
+        except Exception as err:
+            self.logger.warning("Unexpected error getting recent episodes: %s", err, exc_info=True)
+            return []
+
+    @use_cache(86400)  # Cache for 24 hours
+    async def _browse_categories(self) -> list[BrowseFolder]:
+        """Browse podcast categories."""
+        try:
+            response = await self._api_request("categories/list")
+
+            categories = []
+            # Categories API returns feeds array with {id, name} objects
+            categories_data = response.get("feeds", [])
+
+            for category in categories_data:
+                cat_name = category.get("name", "Unknown Category")
+
+                categories.append(
+                    BrowseFolder(
+                        item_id=cat_name,  # Use name as ID
+                        provider=self.domain,
+                        path=f"{self.instance_id}://{BROWSE_CATEGORIES}/{cat_name}",
+                        name=cat_name,
+                    )
+                )
+
+            # Sort by name
+            return sorted(categories, key=lambda x: x.name)
+
+        except (ProviderUnavailableError, InvalidDataError):
+            # Re-raise these specific errors
+            raise
+        except Exception as err:
+            self.logger.warning("Unexpected error getting categories: %s", err, exc_info=True)
+            return []
+
+    @use_cache(43200)  # Cache for 12 hours
+    async def _browse_category_podcasts(self, category_name: str) -> list[Podcast]:
+        """Browse podcasts in a specific category using search."""
+        try:
+            # Search for podcasts using the category name directly
+            search_response = await self._api_request(
+                "search/byterm", params={"q": category_name, "max": 50}
+            )
+
+            podcasts = []
+            for feed_data in search_response.get("feeds", []):
+                podcast = parse_podcast_from_feed(
+                    feed_data, self.lookup_key, self.domain, self.instance_id
+                )
+                if podcast:
+                    podcasts.append(podcast)
+
+            return podcasts
+
+        except (ProviderUnavailableError, InvalidDataError):
+            raise
+        except Exception as err:
+            self.logger.warning(
+                "Unexpected error getting category podcasts: %s", err, exc_info=True
+            )
+            return []
index dea3168993ed4b20fbd5a2e2f435bb032f5a1ed6..d1367acbc3c5ad9a611a2106f11c2f8b0464b261 100644 (file)
@@ -58,8 +58,6 @@ class ResonateProvider(PlayerProvider):
         """Return the features supported by this Provider."""
         return {
             ProviderFeature.SYNC_PLAYERS,
-            ProviderFeature.CREATE_GROUP_PLAYER,
-            ProviderFeature.REMOVE_GROUP_PLAYER,
         }
 
     async def loaded_in_mass(self) -> None:
index 9deef506bc847e014cc7fad190d7fc1f4f1ac3c4..51095efbd646840ff308b4814a8106577a514862 100644 (file)
@@ -36,9 +36,6 @@ from music_assistant.providers.snapcast.provider import SnapCastProvider
 SUPPORTED_FEATURES = {
     ProviderFeature.SYNC_PLAYERS,
     ProviderFeature.REMOVE_PLAYER,
-    # support sync groups by reporting create/remove player group support
-    ProviderFeature.CREATE_GROUP_PLAYER,
-    ProviderFeature.REMOVE_GROUP_PLAYER,
 }
 
 
index 796ac880b32309849dc4f0f613bb52b8476827e2..cf5d720eaa0d1af495c609c4ed84fbae5c97104f 100644 (file)
@@ -25,9 +25,6 @@ if TYPE_CHECKING:
 
 SUPPORTED_FEATURES = {
     ProviderFeature.SYNC_PLAYERS,
-    # support sync groups by reporting create/remove player group support
-    ProviderFeature.CREATE_GROUP_PLAYER,
-    ProviderFeature.REMOVE_GROUP_PLAYER,
 }
 
 
index 9dcc7fe0a9bbfc3ae7a109b4632161482620d1f2..a847062d8ec92ed105d9f2f951fbfbd1f5ba3e6e 100644 (file)
@@ -11,6 +11,7 @@ from __future__ import annotations
 
 import asyncio
 import time
+from copy import deepcopy
 from typing import TYPE_CHECKING
 
 from aiohttp import ClientConnectorError
@@ -300,7 +301,6 @@ class SonosPlayer(Player):
             await airplay_player.stop()
         else:
             await self.client.player.group.stop()
-        self._attr_playback_state = PlaybackState.IDLE
         self.update_state()
 
     async def pause(self) -> None:
@@ -309,11 +309,6 @@ class SonosPlayer(Player):
 
         Will only be called if the player reports PlayerFeature.PAUSE is supported.
         """
-
-        def _update_state() -> None:
-            self._attr_playback_state = PlaybackState.PAUSED
-            self.update_state()
-
         if self.client.player.is_passive:
             self.logger.debug("Ignore STOP command: Player is synced to another player.")
             return
@@ -321,7 +316,6 @@ class SonosPlayer(Player):
             # linked airplay player is active, redirect the command
             self.logger.debug("Redirecting PAUSE command to linked airplay player.")
             await airplay_player.pause()
-            _update_state()
             return
         active_source = self._attr_active_source
         if self.mass.player_queues.get(active_source):
@@ -332,14 +326,11 @@ class SonosPlayer(Player):
             # TODO: revisit this later once we implemented support for range requests
             # as I have the feeling the pause issue is related to seek support (=range requests)
             await self.stop()
-            _update_state()
             return
         if not self.client.player.group.playback_actions.can_pause:
             await self.stop()
-            _update_state()
             return
         await self.client.player.group.pause()
-        _update_state()
 
     async def next_track(self) -> None:
         """
@@ -384,11 +375,7 @@ class SonosPlayer(Player):
 
         :param media: Details of the item that needs to be played on the player.
         """
-
-        def _update_state() -> None:
-            self._attr_current_media = media
-            self._attr_playback_state = PlaybackState.PLAYING
-            self.update_state()
+        self._attr_current_media = deepcopy(media)
 
         if self.client.player.is_passive:
             # this should be already handled by the player manager, but just in case...
@@ -403,17 +390,15 @@ class SonosPlayer(Player):
             # airplay mode is enabled, redirect the command
             self.logger.debug("Redirecting PLAY_MEDIA command to linked airplay player.")
             await self._play_media_airplay(airplay_player, media)
-            _update_state()
             return
 
         if media.media_type in (
             MediaType.PLUGIN_SOURCE,
             MediaType.FLOW_STREAM,
-        ) or media.source_id.startswith(UGP_PREFIX):
+        ) or (media.source_id and media.source_id.startswith(UGP_PREFIX)):
             # flow stream or plugin source playback
             # always use the legacy (UPNP) playback method for this
             await self._play_media_legacy(media)
-            _update_state()
             return
 
         if media.source_id and media.queue_item_id:
@@ -428,7 +413,6 @@ class SonosPlayer(Player):
                 queue_version=str(int(mass_queue.items_last_updated)),
             )
             self.mass.call_later(5, self.sync_play_modes, media.source_id)
-            _update_state()
             return
 
         # All other playback types
@@ -439,7 +423,6 @@ class SonosPlayer(Player):
         await self.client.player.group.play_stream_url(
             media.uri, {"name": media.title, "type": "track"}
         )
-        _update_state()
 
     async def select_source(self, source: str) -> None:
         """
@@ -492,22 +475,26 @@ class SonosPlayer(Player):
         :param player_ids_to_add: List of player_id's to add to the group.
         :param player_ids_to_remove: List of player_id's to remove from the group.
         """
+        player_ids_to_add = player_ids_to_add or []
+        player_ids_to_remove = player_ids_to_remove or []
         if airplay_player := self.get_linked_airplay_player(False):
             # if airplay mode is enabled, we could possibly receive child player id's that are
             # not Sonos players, but AirPlay players. We redirect those.
-            airplay_child_ids = [x for x in player_ids_to_add or [] if x.startswith("ap")]
-            player_ids_to_add = [x for x in player_ids_to_add or [] if x not in airplay_child_ids]
-            if airplay_child_ids:
-                if (
-                    airplay_player.active_source != self._attr_active_source
-                    and airplay_player.playback_state == PlaybackState.PLAYING
-                ):
-                    # edge case player is not playing a MA queue - fail this request
-                    raise PlayerCommandFailed("Player is not playing a Music Assistant queue.")
-                await self.mass.players.cmd_group_many(airplay_player.player_id, airplay_child_ids)
-        if player_ids_to_add:
+            airplay_player_ids_to_add = [x for x in player_ids_to_add if x.startswith("ap")]
+            player_ids_to_add = [x for x in player_ids_to_add if x not in airplay_player_ids_to_add]
+            airplay_player_ids_to_remove = [x for x in player_ids_to_remove if x.startswith("ap")]
+            player_ids_to_remove = [
+                x for x in player_ids_to_remove if x not in airplay_player_ids_to_remove
+            ]
+            if airplay_player_ids_to_add or airplay_player_ids_to_remove:
+                await self.mass.players.cmd_set_members(
+                    airplay_player.player_id,
+                    player_ids_to_add=airplay_player_ids_to_add,
+                    player_ids_to_remove=airplay_player_ids_to_remove,
+                )
+        if player_ids_to_add or player_ids_to_remove:
             await self.client.player.group.modify_group_members(
-                player_ids_to_add=player_ids_to_add, player_ids_to_remove=[]
+                player_ids_to_add=player_ids_to_add, player_ids_to_remove=player_ids_to_remove
             )
 
     async def ungroup(self) -> None:
@@ -551,8 +538,15 @@ class SonosPlayer(Player):
 
     def on_player_event(self, event: SonosEvent | None) -> None:
         """Handle incoming event from player."""
-        self.update_attributes()
-        self.update_state()
+        try:
+            self.update_attributes()
+        except Exception as err:
+            self.logger.exception("Failed to update player attributes: %s", err)
+            return
+        try:
+            self.update_state()
+        except Exception as err:
+            self.logger.exception("Failed to update player state: %s", err)
 
     def update_attributes(self) -> None:  # noqa: PLR0915
         """Update the player attributes."""
@@ -600,7 +594,7 @@ class SonosPlayer(Player):
             self._attr_group_members.clear()
 
         # map playback state
-        self._playback_state = PLAYBACK_STATE_MAP[active_group.playback_state]
+        self._attr_playback_state = PLAYBACK_STATE_MAP[active_group.playback_state]
         self._attr_elapsed_time = active_group.position
 
         # figure out the active source based on the container
@@ -637,9 +631,7 @@ class SonosPlayer(Player):
             if SOURCE_SPOTIFY not in [x.id for x in self._attr_source_list]:
                 self._attr_source_list.append(PLAYER_SOURCE_MAP[SOURCE_SPOTIFY])
         elif active_service == MusicService.MUSIC_ASSISTANT:
-            if self.client.player.is_coordinator:
-                self._attr_active_source = self._player_id
-            elif object_id := container.get("id", {}).get("objectId"):
+            if object_id := container.get("id", {}).get("objectId"):
                 self._attr_active_source = object_id.split(":")[-1]
             else:
                 self._attr_active_source = None
index 42ef940423e453ce149c52319e4894c567e5f272..a84d4b4751317a5ef300c34a8310ce77d35dbee5 100644 (file)
@@ -27,9 +27,6 @@ if TYPE_CHECKING:
 
 SUPPORTED_FEATURES = {
     ProviderFeature.SYNC_PLAYERS,
-    # support sync groups by reporting create/remove player group support
-    ProviderFeature.CREATE_GROUP_PLAYER,
-    ProviderFeature.REMOVE_GROUP_PLAYER,
 }
 
 
index 0da037989e91d268296ada60579cf81117e3498e..cb17862f4867e59dee8e9cfa1188219b8f0a0c83 100644 (file)
@@ -26,9 +26,6 @@ if TYPE_CHECKING:
 
 SUPPORTED_FEATURES = {
     ProviderFeature.SYNC_PLAYERS,
-    # support sync groups by reporting create/remove player group support
-    ProviderFeature.CREATE_GROUP_PLAYER,
-    ProviderFeature.REMOVE_GROUP_PLAYER,
 }
 
 
index 42c748d1ab64f5bc8827497e61bff0baab553ba9..396cdf74796b9e217dd89fd885c36b66e4617382 100644 (file)
@@ -3,6 +3,7 @@
 from __future__ import annotations
 
 import asyncio
+from copy import deepcopy
 from time import time
 from typing import TYPE_CHECKING, cast
 
@@ -262,7 +263,7 @@ class UniversalGroupPlayer(GroupPlayer):
         base_url = f"{self.mass.streams.base_url}/ugp/{self.player_id}.flac"
 
         # set the state optimistically
-        self._attr_current_media = media
+        self._attr_current_media = deepcopy(media)
         self._attr_elapsed_time = 0
         self._attr_elapsed_time_last_updated = time() - 1
         self._attr_playback_state = PlaybackState.PLAYING
index 31e518bd55277a7d70dcd8d5588820ad22b591ef..5ee94d77c639245ff64cae190f80162fca0f37e3 100644 (file)
@@ -63,7 +63,6 @@ test = [
   "ruff==0.12.12",
 ]
 
-
 [project.scripts]
 mass = "music_assistant.__main__:main"
 
@@ -130,7 +129,16 @@ enable_error_code = [
   "truthy-iterable",
 ]
 exclude = [
-  '^music_assistant/controllers/.*$',
+  '^music_assistant/controllers/__init__.py$',
+  '^music_assistant/controllers/cache.py$',
+  '^music_assistant/controllers/config.py$',
+  '^music_assistant/controllers/media/.*$',
+  '^music_assistant/controllers/metadata.py$',
+  '^music_assistant/controllers/music.py$',
+  '^music_assistant/controllers/player_queues.py$',
+  '^music_assistant/controllers/players/player_controller.py',
+  '^music_assistant/controllers/streams.py$',
+  '^music_assistant/controllers/webserver.py',
   '^music_assistant/helpers/app_vars.py',
   '^music_assistant/models/player_provider.py',
   '^music_assistant/providers/apple_music/.*$',