beetbox-beets-00724b7/0000775000175000017500000000000015253035401014053 5ustar pieterpieterbeetbox-beets-00724b7/test/0000775000175000017500000000000015253035401015032 5ustar pieterpieterbeetbox-beets-00724b7/test/test_files.py0000664000175000017500000003665415253035401017563 0ustar pieterpieter"""Test file manipulation functionality of Item.""" import os import shutil import stat import unittest from pathlib import Path import beets.library from beets import util from beets.test import _common from beets.test._common import item from beets.test.helper import NEEDS_REFLINK, BeetsTestCase from beets.util import MoveOperation, syspath class MoveTest(BeetsTestCase): def setUp(self): super().setUp() # make a temporary file self.temp_music_file_name = Path("temp.mp3") self.path = self.temp_path / self.temp_music_file_name shutil.copy(self.resource_path, self.path) # add it to a temporary library self.i = beets.library.Item.from_path(self.path) self.lib.add(self.i) # set up the destination self.lib.path_formats = [ ("default", str(Path("$artist") / "$album" / "$title")) ] self.i.artist = "one" self.i.album = "two" self.i.title = "three" self.dest = self.lib_path / "one" / "two" / "three.mp3" self.otherdir = self.temp_path / "testotherdir" def test_move_arrives(self): self.i.move() assert self.dest.exists() def test_move_to_custom_dir(self): self.i.move(basedir=os.fsencode(self.otherdir)) assert (self.otherdir / "one" / "two" / "three.mp3").exists() def test_move_departs(self): self.i.move() assert not self.path.exists() def test_move_in_lib_prunes_empty_dir(self): self.i.move() old_path = self.i.filepath assert old_path.exists() self.i.artist = "newArtist" self.i.move() assert not old_path.exists() assert not old_path.parent.exists() def test_copy_arrives(self): self.i.move(operation=MoveOperation.COPY) assert self.dest.exists() def test_copy_does_not_depart(self): self.i.move(operation=MoveOperation.COPY) assert self.path.exists() def test_reflink_arrives(self): self.i.move(operation=MoveOperation.REFLINK_AUTO) assert self.dest.exists() def test_reflink_does_not_depart(self): self.i.move(operation=MoveOperation.REFLINK_AUTO) assert self.path.exists() @NEEDS_REFLINK def test_force_reflink_arrives(self): self.i.move(operation=MoveOperation.REFLINK) assert self.dest.exists() @NEEDS_REFLINK def test_force_reflink_does_not_depart(self): self.i.move(operation=MoveOperation.REFLINK) assert self.path.exists() def test_move_changes_path(self): self.i.move() assert self.i.path == util.normpath(self.dest) def test_copy_already_at_destination(self): self.i.move() old_path = self.i.path self.i.move(operation=MoveOperation.COPY) assert self.i.path == old_path def test_move_already_at_destination(self): self.i.move() old_path = self.i.path self.i.move() assert self.i.path == old_path def test_move_file_with_colon(self): self.i.artist = "C:DOS" self.i.move() assert "C_DOS" in self.i.path.decode() def test_move_file_with_multiple_colons(self): # print(beets.config["replace"]) self.i.artist = "COM:DOS" self.i.move() assert "COM_DOS" in self.i.path.decode() def test_move_file_with_colon_alt_separator(self): old = beets.config["drive_sep_replace"] beets.config["drive_sep_replace"] = "0" self.i.artist = "C:DOS" self.i.move() assert "C0DOS" in self.i.path.decode() beets.config["drive_sep_replace"] = old def test_read_only_file_copied_writable(self): # Make the source file read-only. self.path.chmod(0o444) try: self.i.move(operation=MoveOperation.COPY) assert os.access(self.i.filepath, os.W_OK) finally: # Make everything writable so it can be cleaned up. self.path.chmod(0o777) self.i.filepath.chmod(0o777) def test_move_avoids_collision_with_existing_file(self): # Make a conflicting file at the destination. dest = Path(os.fsdecode(self.i.destination())) util.mkdirall(dest) dest.touch() self.i.move() assert self.i.filepath != dest assert self.i.filepath.parent == dest.parent @unittest.skipUnless(_common.HAVE_SYMLINK, "need symlinks") def test_link_arrives(self): self.i.move(operation=MoveOperation.LINK) assert self.dest.exists() assert self.dest.is_symlink() assert self.dest.resolve() == self.path.resolve() @unittest.skipUnless(_common.HAVE_SYMLINK, "need symlinks") def test_link_does_not_depart(self): self.i.move(operation=MoveOperation.LINK) assert self.path.exists() @unittest.skipUnless(_common.HAVE_SYMLINK, "need symlinks") def test_link_changes_path(self): self.i.move(operation=MoveOperation.LINK) assert self.i.path == util.normpath(self.dest) @unittest.skipUnless(_common.HAVE_HARDLINK, "need hardlinks") def test_hardlink_arrives(self): self.i.move(operation=MoveOperation.HARDLINK) assert self.dest.exists() s1 = self.path.stat() s2 = self.dest.stat() assert (s1[stat.ST_INO], s1[stat.ST_DEV]) == ( s2[stat.ST_INO], s2[stat.ST_DEV], ) @unittest.skipUnless(_common.HAVE_HARDLINK, "need hardlinks") def test_hardlink_does_not_depart(self): self.i.move(operation=MoveOperation.HARDLINK) assert self.path.exists() @unittest.skipUnless(_common.HAVE_HARDLINK, "need hardlinks") def test_hardlink_changes_path(self): self.i.move(operation=MoveOperation.HARDLINK) assert self.i.path == util.normpath(self.dest) @unittest.skipUnless(_common.HAVE_HARDLINK, "need hardlinks") def test_hardlink_from_symlink(self): link_path = self.temp_path / "temp_link.mp3" link_path.symlink_to(self.temp_music_file_name) self.i.path = link_path self.i.move(operation=MoveOperation.HARDLINK) s1 = self.path.stat() s2 = self.dest.stat() assert (s1[stat.ST_INO], s1[stat.ST_DEV]) == ( s2[stat.ST_INO], s2[stat.ST_DEV], ) class AlbumFileTest(BeetsTestCase): def setUp(self): super().setUp() # Make library and item. self.lib.path_formats = [ ("default", str(Path("$albumartist") / "$album" / "$title")) ] self.i = item(self.lib) # Make a file for the item. self.i.path = self.i.destination() util.mkdirall(self.i.filepath) self.i.filepath.touch() # Make an album. self.ai = self.lib.add_album((self.i,)) # Alternate destination dir. self.otherdir = os.fsencode(self.temp_path / "testotherdir") def test_albuminfo_move_changes_paths(self): self.ai.album = "newAlbumName" self.ai.move() self.ai.store() self.i.load() assert b"newAlbumName" in self.i.path def test_albuminfo_move_moves_file(self): oldpath = self.i.filepath self.ai.album = "newAlbumName" self.ai.move() self.ai.store() self.i.load() assert not oldpath.exists() assert self.i.filepath.exists() def test_albuminfo_move_copies_file(self): oldpath = self.i.filepath self.ai.album = "newAlbumName" self.ai.move(operation=MoveOperation.COPY) self.ai.store() self.i.load() assert oldpath.exists() assert self.i.filepath.exists() @NEEDS_REFLINK def test_albuminfo_move_reflinks_file(self): oldpath = self.i.filepath self.ai.album = "newAlbumName" self.ai.move(operation=MoveOperation.REFLINK) self.ai.store() self.i.load() assert oldpath.exists() assert self.i.filepath.exists() def test_albuminfo_move_to_custom_dir(self): self.ai.move(basedir=self.otherdir) self.i.load() self.ai.store() assert b"testotherdir" in self.i.path class ArtFileTest(BeetsTestCase): def setUp(self): super().setUp() # Make library and item. self.i = item(self.lib) self.i.path = self.i.destination() # Make a music file. util.mkdirall(self.i.filepath) self.i.filepath.touch() # Make an album. self.ai = self.lib.add_album((self.i,)) # Make an art file too. art_bytes = self.lib.get_album(self.i).art_destination("something.jpg") self.art = Path(os.fsdecode(art_bytes)) self.art.touch() self.ai.artpath = art_bytes self.ai.store() # Alternate destination dir. self.otherdir = os.fsencode(self.temp_path / "testotherdir") def test_art_deleted_when_items_deleted(self): assert self.art.exists() self.ai.remove(True) assert not self.art.exists() def test_art_moves_with_album(self): assert self.art.exists() oldpath = self.i.path self.ai.album = "newAlbum" self.ai.move() self.i.load() assert self.i.path != oldpath assert not self.art.exists() newart = self.lib.get_album(self.i).art_destination(self.art) assert Path(os.fsdecode(newart)).exists() def test_art_moves_with_album_to_custom_dir(self): # Move the album to another directory. self.ai.move(basedir=self.otherdir) self.ai.store() self.i.load() # Art should be in new directory. assert not self.art.exists() newart = self.lib.get_album(self.i).art_filepath assert newart.exists() assert "testotherdir" in str(newart) def test_setart_copies_image(self): util.remove(self.art) newart = self.lib_path / "newart.jpg" newart.touch() i2 = item() i2.path = self.i.path i2.artist = "someArtist" ai = self.lib.add_album((i2,)) i2.move(operation=MoveOperation.COPY) assert ai.artpath is None ai.set_art(newart) assert ai.art_filepath.exists() def test_setart_to_existing_art_works(self): util.remove(self.art) # Original art. newart = self.lib_path / "newart.jpg" newart.touch() i2 = item() i2.path = self.i.path i2.artist = "someArtist" ai = self.lib.add_album((i2,)) i2.move(operation=MoveOperation.COPY) ai.set_art(newart) # Set the art again. ai.set_art(ai.artpath) assert ai.art_filepath.exists() def test_setart_to_existing_but_unset_art_works(self): newart = self.lib_path / "newart.jpg" newart.touch() i2 = item() i2.path = self.i.path i2.artist = "someArtist" ai = self.lib.add_album((i2,)) i2.move(operation=MoveOperation.COPY) # Copy the art to the destination. artdest = ai.art_destination(newart) shutil.copy(newart, syspath(artdest)) # Set the art again. ai.set_art(artdest) assert ai.art_filepath.exists() def test_setart_to_conflicting_file_replaces_it(self): newart = self.lib_path / "newart.jpg" newart.touch() i2 = item() i2.path = self.i.path i2.artist = "someArtist" ai = self.lib.add_album((i2,)) i2.move(operation=MoveOperation.COPY) # Make a file at the destination. artdest = Path(os.fsdecode(ai.art_destination(newart))) artdest.touch() # Set the art - should replace the existing file, not create a suffixed # duplicate like cover.2.jpg. ai.set_art(newart) assert artdest == ai.art_filepath def test_setart_replaces_old_art_at_different_path(self): newart = self.lib_path / "newart.png" newart.touch() i2 = item() i2.path = self.i.path i2.artist = "someArtist" ai = self.lib.add_album((i2,)) i2.move(operation=MoveOperation.COPY) # Set initial art. ai.set_art(newart) old_artpath = ai.art_filepath assert old_artpath.exists() # Set new art with a different extension. another_art = self.lib_path / "another.jpg" another_art.touch() ai.set_art(another_art) # Old art should be removed. assert not old_artpath.exists() assert ai.art_filepath.exists() def test_setart_sets_permissions(self): util.remove(self.art) newart = self.lib_path / "newart.jpg" newart.touch() newart.chmod(0o400) # read-only try: i2 = item() i2.path = self.i.path i2.artist = "someArtist" ai = self.lib.add_album((i2,)) i2.move(operation=MoveOperation.COPY) ai.set_art(newart) mode = stat.S_IMODE(ai.art_filepath.stat().st_mode) assert mode & stat.S_IRGRP assert os.access(ai.art_filepath, os.W_OK) finally: # Make everything writable so it can be cleaned up. newart.chmod(0o777) ai.art_filepath.chmod(0o777) def test_move_last_file_moves_albumart(self): oldartpath = self.lib.albums()[0].art_filepath assert oldartpath.exists() self.ai.album = "different_album" self.ai.store() self.ai.items()[0].move() artpath = self.lib.albums()[0].art_filepath assert "different_album" in str(artpath) assert artpath.exists() assert not oldartpath.exists() def test_move_not_last_file_does_not_move_albumart(self): i2 = item() i2.albumid = self.ai.id self.lib.add(i2) oldartpath = self.lib.albums()[0].art_filepath assert oldartpath.exists() self.i.album = "different_album" self.i.album_id = None # detach from album self.i.move() artpath = self.lib.albums()[0].art_filepath assert "different_album" not in str(artpath) assert artpath == oldartpath assert oldartpath.exists() class RemoveTest(BeetsTestCase): def setUp(self): super().setUp() # Make library and item. self.i = item(self.lib) self.i.path = self.i.destination() # Make a music file. util.mkdirall(self.i.filepath) self.i.filepath.touch() # Make an album with the item. self.ai = self.lib.add_album((self.i,)) def test_removing_last_item_prunes_empty_dir(self): assert self.i.filepath.parent.exists() self.i.remove(True) assert not self.i.filepath.parent.exists() def test_removing_last_item_preserves_nonempty_dir(self): (self.i.filepath.parent / "dummy.txt").touch() self.i.remove(True) assert self.i.filepath.parent.exists() def test_removing_last_item_prunes_dir_with_blacklisted_file(self): (self.i.filepath.parent / ".DS_Store").touch() self.i.remove(True) assert not self.i.filepath.parent.exists() def test_removing_without_delete_leaves_file(self): self.i.remove(False) assert self.i.filepath.parent.exists() def test_removing_last_item_preserves_library_dir(self): self.i.remove(True) assert self.lib_path.exists() def test_removing_last_item_in_album_with_albumart_prunes_dir(self): artfile = self.temp_path / "testart.jpg" artfile.touch() self.ai.set_art(artfile) self.ai.store() self.i.remove(True) assert not self.i.filepath.parent.exists() beetbox-beets-00724b7/test/autotag/0000775000175000017500000000000015253035401016476 5ustar pieterpieterbeetbox-beets-00724b7/test/autotag/test_hooks.py0000664000175000017500000004017215253035401021236 0ustar pieterpieter"""Tests for autotagging functionality.""" import operator from contextlib import nullcontext as does_not_warn from functools import cached_property import pytest from beets.autotag import ( AlbumInfo, AlbumMatch, Distance, TrackInfo, TrackMatch, correct_list_fields, ) from beets.library import Item from beets.test.helper import BeetsTestCase from beets.util import AttrDict str_field_deprecation = pytest.warns( DeprecationWarning, match="The 'genre' field is deprecated" ) _p = pytest.param @pytest.mark.parametrize( "str_value, list_value, expected_warning, expected_list_value", [ _p( "", None, str_field_deprecation, None, id="empty str value should become None, warning raised", ), _p( "value", None, str_field_deprecation, ["value"], id="str value only, warning raised", ), _p( "value; another value", None, str_field_deprecation, ["value", "another value"], id="str value only and split, warning raised", ), _p( "value", ["list value"], str_field_deprecation, ["list value"], id="list value wins, warning raised", ), _p(None, None, does_not_warn(), None, id="no str value, no warning"), ], ) class TestLegacyStringField: def test_init_info( self, str_value, list_value, expected_warning, expected_list_value ): with expected_warning: actual_list_value = TrackInfo._get_list_from_string_value( "genre", "genres", str_value, list_value ) assert actual_list_value == expected_list_value def test_set_str_value( self, str_value, list_value, expected_warning, expected_list_value ): info = TrackInfo(genres=list_value) with expected_warning: info["genre"] = str_value assert info["genres"] == expected_list_value class ApplyTest(BeetsTestCase): def _apply( self, per_disc_numbering=False, artist_credit=False, original_date=False, from_scratch=False, ): info = self.info mapping = dict(zip(self.items, info.tracks)) self.config["per_disc_numbering"] = per_disc_numbering self.config["artist_credit"] = artist_credit self.config["original_date"] = original_date self.config["import"]["from_scratch"] = from_scratch amatch = AlbumMatch(Distance(), self.info, mapping) amatch.apply_metadata() return amatch def setUp(self): super().setUp() self.items = [Item(), Item()] self.info = AlbumInfo( tracks=[ TrackInfo( title="title", track_id="dfa939ec-118c-4d0f-84a0-60f3d1e6522c", medium=1, medium_index=1, medium_total=1, index=1, artist="trackArtist", artist_credit="trackArtistCredit", artists_credit=["trackArtistCredit"], artist_sort="sortLast, sortFirst and sortLast2, sortFirst2", artists_sort=[ "sortLast, sortFirst", "sortLast2, sortFirst2", ], arranger="trackArranger1, trackArranger2", composer="trackComposer1, trackComposer2", genres=["Rock"], lyricist="trackLyricist1, trackLyricist2", remixer="trackRemixer1, trackRemixer2", ), TrackInfo( title="title2", track_id="40130ed1-a27c-42fd-a328-1ebefb6caef4", medium=2, medium_index=1, index=2, medium_total=1, arrangers=["trackArranger1", "trackArranger2"], composers=["trackComposer1", "trackComposer2"], lyricists=["trackLyricist1", "trackLyricist2"], remixers=["trackRemixer1", "trackRemixer2"], ), ], artist="albumArtist", artists=["albumArtist", "albumArtist2"], album="album", album_id="7edb51cb-77d6-4416-a23c-3a8c2994a2c7", artist_id="a6623d39-2d8e-4f70-8242-0a9553b91e50", artists_ids=None, artist_credit="albumArtistCredit", artists_credit=["albumArtistCredit1", "albumArtistCredit2"], artist_sort=None, artists_sort=["albumArtistSort", "albumArtistSort2"], albumtype="album", va=True, mediums=2, data_source="MusicBrainz", year=2013, month=12, day=18, genre="Rock; Pop", ) common_expected = { "album": "album", "albumartist_credit": "albumArtistCredit", "albumartist": "albumArtist", "albumartists": ["albumArtist", "albumArtist2"], "albumartists_credit": [ "albumArtistCredit", "albumArtistCredit1", "albumArtistCredit2", ], "albumartist_sort": "albumArtistSort", "albumartists_sort": ["albumArtistSort", "albumArtistSort2"], "albumtype": "album", "albumtypes": ["album"], "comp": True, "disctotal": 2, "mb_albumartistid": "a6623d39-2d8e-4f70-8242-0a9553b91e50", "mb_albumartistids": ["a6623d39-2d8e-4f70-8242-0a9553b91e50"], "mb_albumid": "7edb51cb-77d6-4416-a23c-3a8c2994a2c7", "mb_artistid": "a6623d39-2d8e-4f70-8242-0a9553b91e50", "mb_artistids": ["a6623d39-2d8e-4f70-8242-0a9553b91e50"], "arrangers": ["trackArranger1", "trackArranger2"], "composers": ["trackComposer1", "trackComposer2"], "remixers": ["trackRemixer1", "trackRemixer2"], "lyricists": ["trackLyricist1", "trackLyricist2"], "tracktotal": 2, "year": 2013, "month": 12, "day": 18, } self.expected_tracks = [ { **common_expected, "artist": "trackArtist", "artists": ["trackArtist"], "artist_credit": "trackArtistCredit", "artist_sort": "sortLast, sortFirst and sortLast2, sortFirst2", "artists_credit": ["trackArtistCredit"], "artists_sort": [ "sortLast, sortFirst", "sortLast2, sortFirst2", ], "disc": 1, "genres": ["Rock"], "mb_trackid": "dfa939ec-118c-4d0f-84a0-60f3d1e6522c", "title": "title", "track": 1, }, { **common_expected, "artist": "albumArtist", "artists": ["albumArtist", "albumArtist2"], "artist_credit": "albumArtistCredit", "artist_sort": "albumArtistSort", "artists_credit": [ "albumArtistCredit", "albumArtistCredit1", "albumArtistCredit2", ], "artists_sort": ["albumArtistSort", "albumArtistSort2"], "disc": 2, "genres": ["Rock", "Pop"], "mb_trackid": "40130ed1-a27c-42fd-a328-1ebefb6caef4", "title": "title2", "track": 2, }, ] def test_autotag_items(self): self._apply() keys = self.expected_tracks[0].keys() get_values = operator.itemgetter(*keys) applied_data = [ dict(zip(keys, get_values(dict(i)))) for i in self.items ] assert applied_data == self.expected_tracks def test_per_disc_numbering(self): self._apply(per_disc_numbering=True) assert self.items[0].track == 1 assert self.items[1].track == 1 assert self.items[0].tracktotal == 1 assert self.items[1].tracktotal == 1 def test_artist_credit_prefers_artist_over_albumartist_credit(self): self.info.tracks[0].update(artist="oldArtist", artist_credit=None) self._apply(artist_credit=True) assert self.items[0].artist == "oldArtist" def test_artist_credit_falls_back_to_albumartist(self): self.info.artist_credit = None self._apply(artist_credit=True) assert self.items[1].artist == "albumArtist" def test_date_only_zeroes_month_and_day(self): self.items = [Item(year=1, month=2, day=3)] self.info.update(year=2013, month=None, day=None) self._apply() assert self.items[0].year == 2013 assert self.items[0].month == 0 assert self.items[0].day == 0 def test_missing_date_applies_nothing(self): self.items = [Item(year=1, month=2, day=3)] self.info.update(year=None, month=None, day=None) self._apply() assert self.items[0].year == 1 assert self.items[0].month == 2 assert self.items[0].day == 3 def test_original_date_overrides_album_metadata(self): self.info.update( year=2013, month=12, day=18, original_year=1999, original_month=4, original_day=7, ) match = self._apply(original_date=True) album = self.lib.add_album(self.items) match.apply_album_metadata(album) assert album.year == 1999 assert album.month == 4 assert album.day == 7 class TestFromScratch: @pytest.fixture(autouse=True) def config(self, config): config["import"]["from_scratch"] = True @pytest.fixture def album_info(self): return AlbumInfo( tracks=[TrackInfo(title="title", artist="track artist", index=1)] ) @pytest.fixture def item(self): return Item(artist="old artist", comments="stale comment") def test_album_match_clears_stale_metadata(self, album_info, item): match = AlbumMatch(Distance(), album_info, {item: album_info.tracks[0]}) match.apply_metadata() assert item.artist == "track artist" assert item.comments == "" def test_singleton_match_clears_stale_metadata(self, item): match = TrackMatch(Distance(), TrackInfo(artist="track artist"), item) match.apply_metadata() assert item.artist == "track artist" assert item.comments == "" @pytest.mark.parametrize( "overwrite_fields,expected_item_artist", [ pytest.param(["artist"], "", id="overwrite artist"), pytest.param([], "artist", id="do not overwrite artist"), ], ) class TestOverwriteNull: @pytest.fixture(autouse=True) def config(self, config, overwrite_fields): config["overwrite_null"]["album"] = overwrite_fields config["overwrite_null"]["track"] = overwrite_fields config["import"]["from_scratch"] = False @pytest.fixture def item(self): return Item(artist="artist") @pytest.fixture def track_info(self): return TrackInfo(artist=None) def test_album(self, item, track_info, expected_item_artist): match = AlbumMatch( Distance(), AlbumInfo([track_info]), {item: track_info} ) match.apply_metadata() assert item.artist == expected_item_artist def test_singleton(self, item, track_info, expected_item_artist): match = TrackMatch(Distance(), track_info, item) match.apply_metadata() assert item.artist == expected_item_artist @pytest.mark.parametrize( "single_field,list_field", [ ("albumtype", "albumtypes"), ("artist", "artists"), ("artist_credit", "artists_credit"), ("artist_id", "artists_ids"), ("artist_sort", "artists_sort"), ], ) @pytest.mark.parametrize( "single_value,list_value,expected_values", [ (None, [], (None, [])), (None, ["1"], ("1", ["1"])), (None, ["1", "2"], ("1", ["1", "2"])), ("1", [], ("1", ["1"])), ("1", ["1"], ("1", ["1"])), ("1", ["1", "2"], ("1", ["1", "2"])), ("1", ["2", "1"], ("1", ["1", "2"])), ("1", ["2"], ("1", ["1", "2"])), ("1 ft 2", ["1", "1 ft 2"], ("1 ft 2", ["1 ft 2", "1"])), ("1 FT 2", ["1", "1 ft 2"], ("1 FT 2", ["1", "1 ft 2"])), ("a", ["b", "A"], ("a", ["b", "A"])), ("1 ft 2", ["2", "1"], ("1 ft 2", ["2", "1"])), ( "a, b and c, d", ["a, b", "c, d"], ("a, b and c, d", ["a, b", "c, d"]), ), ], ) def test_correct_list_fields( single_field, list_field, single_value, list_value, expected_values ): """Verify that singular and plural field variants are kept consistent. Checks that when both a single-value field and its list counterpart are present, the function reconciles them: ensuring the single value appears in the list and the list drives the canonical single value when needed. """ input_data = {single_field: single_value, list_field: list_value} data = correct_list_fields(input_data) assert (data[single_field], data[list_field]) == expected_values class TestAttrDictCachedPropertyMasking: """Regression tests for #6558. When a ``cached_property`` on an :class:`AttrDict` subclass raises ``AttributeError`` during its own computation, Python's default attribute lookup falls back to ``__getattr__`` with the property's name and the real missing field gets masked behind a misleading "object has no attribute 'raw_data'". We intercept cached_property lookups in ``__getattribute__``: when ``super().__getattribute__`` raises ``AttributeError`` and the attribute resolves to a ``cached_property``, the error is re-raised as ``RuntimeError`` that keeps the original traceback so it still points at the real failing line inside the property body. ``raise ... from None`` suppresses the chained-exception block in CLI tracebacks. """ def test_inner_error_surfaces_with_original_message(self): class Sample(AttrDict[object]): @cached_property def derived(self): return self.missing_field obj = Sample() with pytest.raises(RuntimeError, match="missing_field"): obj.derived def test_cause_chain_is_suppressed(self): class Sample(AttrDict[object]): @cached_property def derived(self): return self.missing_field obj = Sample() with pytest.raises(RuntimeError) as excinfo: obj.derived # ``raise ... from None`` suppresses the chained traceback block. assert excinfo.value.__cause__ is None assert excinfo.value.__suppress_context__ is True def test_traceback_points_at_property_body(self): class Sample(AttrDict[object]): @cached_property def derived(self): return self.missing_field obj = Sample() with pytest.raises(RuntimeError) as excinfo: obj.derived # The wrapper reuses the original AttributeError traceback, so the # RuntimeError itself points back at the line that actually failed. tb = excinfo.value.__traceback__ frames = [] while tb is not None: frames.append(tb.tb_frame.f_code.co_name) tb = tb.tb_next assert "derived" in frames def test_cached_property_success_returns_value(self): class Sample(AttrDict[object]): @cached_property def doubled(self): return self["n"] * 2 obj = Sample({"n": 21}) assert obj.doubled == 42 def test_plain_missing_attr_still_raises_attributeerror(self): obj = AttrDict[str]() with pytest.raises(AttributeError, match="nope"): obj.nope def test_existing_dict_key_returns_value(self): obj = AttrDict[str]({"title": "ok"}) assert obj.title == "ok" beetbox-beets-00724b7/test/autotag/__init__.py0000664000175000017500000000000015253035401020575 0ustar pieterpieterbeetbox-beets-00724b7/test/autotag/test_match.py0000664000175000017500000001472715253035401021216 0ustar pieterpieterfrom typing import ClassVar import pytest from beets import metadata_plugins from beets.autotag import ( AlbumInfo, Source, TrackInfo, assign_items, tag_album, tag_item, ) from beets.library import Item class TestAssignment: A = "one" B = "two" C = "three" @pytest.fixture(autouse=True) def config(self, config): config["match"]["track_length_grace"] = 10 config["match"]["track_length_max"] = 30 @pytest.mark.parametrize( # 'expected' is a tuple of expected (mapping, extra_items, extra_tracks) "item_titles, track_titles, expected", [ # items ordering gets corrected ([A, C, B], [A, B, C], ({A: A, B: B, C: C}, [], [])), # unmatched tracks are returned as 'extra_tracks' # the first track is unmatched ([B, C], [A, B, C], ({B: B, C: C}, [], [A])), # the middle track is unmatched ([A, C], [A, B, C], ({A: A, C: C}, [], [B])), # the last track is unmatched ([A, B], [A, B, C], ({A: A, B: B}, [], [C])), # unmatched items are returned as 'extra_items' ([A, C, B], [A, C], ({A: A, C: C}, [B], [])), ], ) def test_assign_tracks(self, item_titles, track_titles, expected): expected_mapping, expected_extra_items, expected_extra_tracks = expected items = [Item(title=title) for title in item_titles] tracks = [TrackInfo(title=title) for title in track_titles] item_info_pairs, extra_items, extra_tracks = assign_items(items, tracks) assert ( {i.title: t.title for i, t in item_info_pairs}, [i.title for i in extra_items], [t.title for t in extra_tracks], ) == (expected_mapping, expected_extra_items, expected_extra_tracks) def test_order_works_when_track_names_are_entirely_wrong(self): # A real-world test case contributed by a user. def item(i, length): return Item( artist="ben harper", album="burn to shine", title=f"ben harper - Burn to Shine {i}", track=i, length=length, ) items = [] items.append(item(1, 241.37243007106997)) items.append(item(2, 342.27781704375036)) items.append(item(3, 245.95070222338137)) items.append(item(4, 472.87662515485437)) items.append(item(5, 279.1759535763187)) items.append(item(6, 270.33333768012)) items.append(item(7, 247.83435613222923)) items.append(item(8, 216.54504531525072)) items.append(item(9, 225.72775379800484)) items.append(item(10, 317.7643606963552)) items.append(item(11, 243.57001238834192)) items.append(item(12, 186.45916150485752)) def info(index, title, length): return TrackInfo(title=title, length=length, index=index) trackinfo = [] trackinfo.append(info(1, "Alone", 238.893)) trackinfo.append(info(2, "The Woman in You", 341.44)) trackinfo.append(info(3, "Less", 245.59999999999999)) trackinfo.append(info(4, "Two Hands of a Prayer", 470.49299999999999)) trackinfo.append(info(5, "Please Bleed", 277.86599999999999)) trackinfo.append(info(6, "Suzie Blue", 269.30599999999998)) trackinfo.append(info(7, "Steal My Kisses", 245.36000000000001)) trackinfo.append(info(8, "Burn to Shine", 214.90600000000001)) trackinfo.append(info(9, "Show Me a Little Shame", 224.0929999999999)) trackinfo.append(info(10, "Forgiven", 317.19999999999999)) trackinfo.append(info(11, "Beloved One", 243.733)) trackinfo.append(info(12, "In the Lord's Arms", 186.13300000000001)) expected = list(zip(items, trackinfo)), [], [] assert assign_items(items, trackinfo) == expected class TestTagMultipleDataSources: @pytest.fixture def shared_track_id(self): return "track-12345" @pytest.fixture def shared_album_id(self): return "album-12345" @pytest.fixture(autouse=True) def _setup_plugins(self, monkeypatch, shared_album_id, shared_track_id): class StubPlugin: data_source: ClassVar[str] data_source_mismatch_penalty = 0 @property def track(self): return TrackInfo( artist="Artist", title="Title", track_id=shared_track_id, data_source=self.data_source, ) @property def album(self): return AlbumInfo( [self.track], artist="Albumartist", album="Album", album_id=shared_album_id, data_source=self.data_source, ) def albums_for_ids(self, *_): yield self.album def tracks_for_ids(self, *_): yield self.track def candidates(self, *_, **__): yield self.album def item_candidates(self, *_, **__): yield self.track class DeezerPlugin(StubPlugin): data_source = "Deezer" class DiscogsPlugin(StubPlugin): data_source = "Discogs" monkeypatch.setattr( metadata_plugins, "find_metadata_source_plugins", lambda: [DeezerPlugin(), DiscogsPlugin()], ) def check_proposal(self, proposal): sources = [ candidate.info.data_source for candidate in proposal.candidates ] assert len(sources) == 2 assert set(sources) == {"Discogs", "Deezer"} def test_search_album_ids(self, shared_album_id): source = Source.from_items([Item()]) proposal = tag_album(source, search_ids=[shared_album_id]) self.check_proposal(proposal) def test_search_album_current_id(self, shared_album_id): source = Source.from_items([Item(mb_albumid=shared_album_id)]) proposal = tag_album(source) self.check_proposal(proposal) def test_search_track_ids(self, shared_track_id): source = Source.from_item(Item()) proposal = tag_item(source, search_ids=[shared_track_id]) self.check_proposal(proposal) def test_search_track_current_id(self, shared_track_id): source = Source.from_item(Item(mb_trackid=shared_track_id)) proposal = tag_item(source) self.check_proposal(proposal) beetbox-beets-00724b7/test/autotag/test_distance.py0000664000175000017500000003076015253035401021707 0ustar pieterpieterimport re import pytest from beets.autotag import ( AlbumInfo, Distance, Source, TrackInfo, distance, string_dist, track_distance, ) from beets.library import Item from beets.metadata_plugins import MetadataSourcePlugin, get_penalty from beets.plugins import BeetsPlugin _p = pytest.param class TestDistance: @pytest.fixture(autouse=True) def setup_config(self, config): config["match"]["distance_weights"]["data_source"] = 2.0 config["match"]["distance_weights"]["album"] = 4.0 config["match"]["distance_weights"]["medium"] = 2.0 @pytest.fixture def dist(self): return Distance() def test_add(self, dist): dist.add("add", 1.0) assert dist._penalties == {"add": [1.0]} @pytest.mark.parametrize( "key, args_with_expected", [ ( "equality", [ (("ghi", ["abc", "def", "ghi"]), [0.0]), (("xyz", ["abc", "def", "ghi"]), [0.0, 1.0]), (("abc", re.compile(r"ABC", re.I)), [0.0, 1.0, 0.0]), ], ), ("expr", [((True,), [1.0]), ((False,), [1.0, 0.0])]), ( "number", [ ((1, 1), [0.0]), ((1, 2), [0.0, 1.0]), ((2, 1), [0.0, 1.0, 1.0]), ((-1, 2), [0.0, 1.0, 1.0, 1.0, 1.0, 1.0]), ], ), ( "priority", [ (("abc", "abc"), [0.0]), (("def", ["abc", "def"]), [0.0, 0.5]), (("gh", ["ab", "cd", "ef", re.compile("GH", re.I)]), [0.0, 0.5, 0.75]), # noqa: E501 (("xyz", ["abc", "def"]), [0.0, 0.5, 0.75, 1.0]), ], ), ( "ratio", [ ((25, 100), [0.25]), ((10, 5), [0.25, 1.0]), ((-5, 5), [0.25, 1.0, 0.0]), ((5, 0), [0.25, 1.0, 0.0, 0.0]), ], ), ( "string", [ (("abc", "bcd"), [2 / 3]), (("abc", None), [2 / 3, 1]), ((None, None), [2 / 3, 1, 0]), ], ), ], ) # fmt: skip def test_add_methods(self, dist, key, args_with_expected): method = getattr(dist, f"add_{key}") for arg_set, expected in args_with_expected: method(key, *arg_set) assert dist._penalties[key] == expected def test_distance(self, dist): dist.add("album", 0.5) dist.add("media", 0.25) dist.add("media", 0.75) assert dist.distance == 0.5 assert dist.max_distance == 6.0 assert dist.raw_distance == 3.0 assert dist["album"] == 1 / 3 assert dist["media"] == 1 / 6 def test_operators(self, dist): dist.add("data_source", 0.0) dist.add("album", 0.5) dist.add("medium", 0.25) dist.add("medium", 0.75) assert len(dist) == 2 assert list(dist) == [("album", 0.2), ("medium", 0.2)] assert dist == 0.4 assert dist < 1.0 assert dist > 0.0 assert dist - 0.4 == 0.0 assert 0.4 - dist == 0.0 assert float(dist) == 0.4 def test_penalties_sort(self, dist): dist.add("album", 0.1875) dist.add("medium", 0.75) assert dist.items() == [("medium", 0.25), ("album", 0.125)] # Sort by key if distance is equal. dist = Distance() dist.add("album", 0.375) dist.add("medium", 0.75) assert dist.items() == [("album", 0.25), ("medium", 0.25)] def test_generic_penalty_keys_excludes_zero_penalties(self, dist): dist.add("album", 0.5) dist.add("label", 0.0) dist.add("medium", 0.25) assert dist.generic_penalty_keys == ["album", "medium"] def test_update(self, dist): dist1 = dist dist1.add("album", 0.5) dist1.add("media", 1.0) dist2 = Distance() dist2.add("album", 0.75) dist2.add("album", 0.25) dist2.add("media", 0.05) dist1.update(dist2) assert dist1._penalties == { "album": [0.5, 0.75, 0.25], "media": [1.0, 0.05], } class TestTrackDistance: @pytest.fixture(scope="class") def info(self): return TrackInfo(title="title", artist="artist") @pytest.mark.parametrize( "title, artist, expected_penalty", [ _p("title", "artist", False, id="identical"), _p("title", "Various Artists", False, id="tolerate-va"), _p("title", "different artist", True, id="different-artist"), _p("different title", "artist", True, id="different-title"), ], ) def test_track_distance(self, info, title, artist, expected_penalty): item = Item(artist=artist, title=title) dist = track_distance(item, info, incl_artist=True) assert bool(dist) == expected_penalty, dist._penalties class TestAlbumDistance: @pytest.fixture(scope="class") def items(self): return [ Item( title=title, track=track, artist="artist", album="album", length=1, ) for title, track in [("one", 1), ("two", 2), ("three", 3)] ] @pytest.fixture def get_dist(self, items): def inner(info: AlbumInfo): return distance( Source.from_items(items).data, info, list(zip(items, info.tracks)), len(items) - len(info.tracks), ) return inner @pytest.fixture def info(self, items): return AlbumInfo( artist="artist", album="album", tracks=[ TrackInfo( title=i.title, artist=i.artist, index=i.track, length=i.length, ) for i in items ], va=False, ) def test_identical_albums(self, get_dist, info): assert get_dist(info) == 0 def test_incomplete_album(self, get_dist, info): info.tracks.pop(2) assert 0 < float(get_dist(info)) < 0.2 def test_overly_complete_album(self, get_dist, info): info.tracks.append( Item(index=4, title="four", artist="artist", length=1) ) assert 0 < float(get_dist(info)) < 0.2 @pytest.mark.parametrize("va", [True, False]) def test_albumartist(self, get_dist, info, va): info.artist = "another artist" info.va = va assert bool(get_dist(info)) is not va def test_comp_no_track_artists(self, get_dist, info): # Some VA releases don't have track artists (incomplete metadata). info.artist = "another artist" info.va = True for track in info.tracks: track.artist = None assert get_dist(info) == 0 def test_comp_track_artists_do_not_match(self, get_dist, info): info.va = True info.tracks[0].artist = "another artist" assert get_dist(info) != 0 def test_tracks_out_of_order(self, get_dist, info): tracks = info.tracks tracks[1].title, tracks[2].title = tracks[2].title, tracks[1].title assert 0 < float(get_dist(info)) < 0.2 def test_two_medium_release(self, get_dist, info): info.tracks[0].medium_index = 1 info.tracks[1].medium_index = 2 info.tracks[2].medium_index = 1 assert get_dist(info) == 0 class TestStringDistance: @pytest.mark.parametrize( "string1, string2", [ ("Some String", "Some String"), ("Some String", "Some.String!"), ("Some String", "sOME sTring"), ("My Song (EP)", "My Song"), ("The Song Title", "Song Title, The"), ("A Song Title", "Song Title, A"), ("An Album Title", "Album Title, An"), ("", ""), ("Untitled", "[Untitled]"), ("And", "&"), ("\xe9\xe1\xf1", "ean"), ], ) def test_matching_distance(self, string1, string2): assert string_dist(string1, string2) == 0.0 def test_different_distance(self): assert string_dist("Some String", "Totally Different") != 0.0 @pytest.mark.parametrize( "string1, string2", [ ("Draft Beer", "Draft Whiskey"), ("Left Field", "Left Symphony"), ("Gift Ideas", "Gift Cards"), ("Craft Beer", "Craft Wine"), ], ) def test_featuring_pattern_does_not_match_mid_word(self, string1, string2): # The "featuring"/"feat"/"ft" pattern must not match "ft" embedded # inside an ordinary word (draft, left, gift, craft, ...) -- doing so # would treat everything after "ft" as a low-weight suffix and make # genuinely different strings look almost identical instead of # correctly registering as a large distance. assert string_dist(string1, string2) > 0.3 @pytest.mark.parametrize( "string1, string2, reference", [ ("XXX Band Name", "The Band Name", "Band Name"), ("One .Two.", "One (Two)", "One"), ("One .Two.", "One [Two]", "One"), ("My Song blah Someone", "My Song feat Someone", "My Song"), ], ) def test_relative_weights(self, string1, string2, reference): assert string_dist(string2, reference) < string_dist(string1, reference) def test_solo_pattern(self): # Just make sure these don't crash. string_dist("The ", "") string_dist("(EP)", "(EP)") string_dist(", An", "") class TestDataSourceDistance: MATCH = 0.0 MISMATCH = 0.125 @pytest.fixture(autouse=True) def setup(self, monkeypatch, penalty, weight, multiple_data_sources): monkeypatch.setitem(Distance._weights, "data_source", weight) get_penalty.cache_clear() class TestMetadataSourcePlugin(MetadataSourcePlugin): def album_for_id(self, *args, **kwargs): ... def track_for_id(self, *args, **kwargs): ... def candidates(self, *args, **kwargs): ... def item_candidates(self, *args, **kwargs): ... # We use BeetsPlugin here to check if our compatibility layer # for pre 2.4.0 MetadataPlugins is working as expected # TODO: Replace BeetsPlugin with TestMetadataSourcePlugin in v3.0.0 with pytest.deprecated_call(): class OriginalPlugin(BeetsPlugin): data_source = "Original" class OtherPlugin(TestMetadataSourcePlugin): @property def data_source_mismatch_penalty(self): return penalty monkeypatch.setattr( "beets.metadata_plugins.find_metadata_source_plugins", lambda: ( [OriginalPlugin(), OtherPlugin()] if multiple_data_sources else [OtherPlugin()] ), ) @pytest.mark.parametrize( "item,info,penalty,weight,multiple_data_sources,expected_distance", [ _p("Original", "Original", 0.5, 1.0, True, MATCH, id="match"), _p("Original", "Other", 0.5, 1.0, True, MISMATCH, id="mismatch"), _p("Other", "Original", 0.5, 1.0, True, MISMATCH, id="mismatch"), _p("Original", "unknown", 0.5, 1.0, True, MISMATCH, id="mismatch-unknown"), _p("Original", None, 0.5, 1.0, True, MISMATCH, id="mismatch-no-info"), _p(None, "Other", 0.5, 1.0, True, MISMATCH, id="mismatch-no-original-multiple-sources"), # noqa: E501 _p(None, "Other", 0.5, 1.0, False, MATCH, id="match-no-original-but-single-source"), # noqa: E501 _p("unknown", "unknown", 0.5, 1.0, True, MATCH, id="match-unknown"), _p("Original", "Other", 1.0, 1.0, True, 0.25, id="mismatch-max-penalty"), _p("Original", "Other", 0.5, 5.0, True, 0.3125, id="mismatch-high-weight"), _p("Original", "Other", 0.0, 1.0, True, MATCH, id="match-no-penalty"), _p("Original", "Other", 0.5, 0.0, True, MATCH, id="match-no-weight"), ], ) # fmt: skip def test_distance(self, item, info, expected_distance): item = Item(data_source=item) info = TrackInfo(data_source=info, title="") dist = track_distance(item, info) assert dist.distance == expected_distance beetbox-beets-00724b7/test/library/0000775000175000017500000000000015253035401016476 5ustar pieterpieterbeetbox-beets-00724b7/test/library/test_migrations.py0000664000175000017500000003253015253035401022266 0ustar pieterpieterimport os import textwrap from pathlib import Path from typing import ClassVar import pytest from beets.dbcore import types from beets.library import Album, Item, migrations from beets.test.helper import TestHelper from beets.util import cached_classproperty, path_as_posix Migration = tuple[ type[migrations.Migration], tuple[type[Item] | type[Album], ...] ] class MigrationTestHelper(TestHelper): """Provide a shared harness for exercising one library migration at a time. The helper builds a library that starts in a pre-migration state, then re-enables the migration under test so each subclass can verify the data transformation in isolation. """ migration: ClassVar[Migration] @classmethod def setup_previous_state(cls, monkeypatch: pytest.MonkeyPatch) -> None: """Shape the library into the legacy state expected by the migration. Subclasses override this hook to create older schema or metadata layouts before the test library is initialized. """ @pytest.fixture(autouse=True) def setup(self, monkeypatch): """Initialize the test library around the migration under test. The fixture first prevents automatic migrations so legacy test data can be created safely, then restores the target migration and tears down the temporary library after each test. """ # do not apply migrations upon library initialization monkeypatch.setattr("beets.library.library.Library._migrations", ()) self.setup_previous_state(monkeypatch) self.setup_beets() # and now configure the migrations to be tested monkeypatch.setattr( "beets.library.library.Library._migrations", (self.migration,) ) try: yield finally: self.teardown_beets() class TestMultiGenreFieldMigration(MigrationTestHelper): """Verify legacy single-value genres are promoted to multi-value fields.""" migration = (migrations.MultiGenreFieldMigration, (Item, Album)) @classmethod def setup_previous_state(cls, monkeypatch: pytest.MonkeyPatch) -> None: """Expose the legacy genre columns required to exercise the migration.""" # add genre field to both models to make sure this column is created monkeypatch.setattr( "beets.library.models.Item._fields", {**Item._fields, "genre": types.STRING}, ) monkeypatch.setattr( "beets.library.models.Album._fields", {**Album._fields, "genre": types.STRING}, ) monkeypatch.setattr( "beets.library.models.Album.item_keys", {*Album.item_keys, "genre"} ) def test_migrate(self): """Ensure genre data is split once and preserved when already populated.""" self.config["lastgenre"]["separator"] = " - " expected_item_genres = [] for genre, initial_genres, expected_genres in [ # already existing value is not overwritten ("Item Rock", ("Ignored",), ("Ignored",)), ("", (), ()), ("Rock", (), ("Rock",)), # multiple genres are split on one of default separators ("Item Rock; Alternative", (), ("Item Rock", "Alternative")), # multiple genres are split the first (lastgenre) separator ONLY ("Item - Rock, Alternative", (), ("Item", "Rock, Alternative")), ]: self.add_item(genre=genre, genres=initial_genres) expected_item_genres.append(expected_genres) unmigrated_album = self.add_album( genre="Album Rock / Alternative", genres=[] ) expected_item_genres.append(("Album Rock", "Alternative")) self.lib._migrate() actual_item_genres = [tuple(i.genres) for i in self.lib.items()] assert actual_item_genres == expected_item_genres unmigrated_album.load() assert unmigrated_album.genres == ["Album Rock", "Alternative"] # remove cached initial db tables data del self.lib.db_tables assert self.lib.migration_exists("multi_genre_field", "items") assert self.lib.migration_exists("multi_genre_field", "albums") class MultiArtistFieldMigrationTestMixin(MigrationTestHelper): """Share coverage for migrations that split artist-like text into lists.""" str_field: ClassVar[str] list_field: ClassVar[str] migration_cls: ClassVar[type[migrations.MultiValueFieldMigration]] @cached_classproperty def migration(cls) -> Migration: """Bind each concrete test class to its corresponding migration.""" return (cls.migration_cls, (Item,)) @classmethod def setup_previous_state(cls, monkeypatch: pytest.MonkeyPatch) -> None: """Expose the legacy scalar field expected by the migration.""" # add legacy str field to make sure this column is created monkeypatch.setattr( "beets.library.models.Item._fields", {**Item._fields, cls.str_field: types.STRING}, ) def test_migrate(self): """Ensure existing list values win and legacy text splits consistently.""" expected_list_values = [] for str_value, initial_list_value, expected_list_value in [ # already existing value is not overwritten ("Artist", ("Ignored",), ("Ignored",)), ("", (), ()), ("Artist", (), ("Artist",)), # multiple values are split on one of separators ("Artist; Another Artist", (), ("Artist", "Another Artist")), # multiple values are split by the existing separator ONLY ("Artist, Another; Artist", (), ("Artist, Another", "Artist")), ]: data = { self.str_field: str_value, self.list_field: initial_list_value, } self.add_item(**data) expected_list_values.append(expected_list_value) self.lib._migrate() actual_list_values = [ tuple(i[self.list_field]) for i in self.lib.items() ] assert actual_list_values == expected_list_values # remove cached initial db tables data del self.lib.db_tables assert self.lib.migration_exists( f"multi_{self.str_field}_field", "items" ) class TestMultiRemixerFieldMigration(MultiArtistFieldMigrationTestMixin): str_field = "remixer" list_field = "remixers" migration_cls = migrations.MultiRemixerFieldMigration class TestMultiLyricistFieldMigration(MultiArtistFieldMigrationTestMixin): str_field = "lyricist" list_field = "lyricists" migration_cls = migrations.MultiLyricistFieldMigration class TestMultiComposerFieldMigration(MultiArtistFieldMigrationTestMixin): str_field = "composer" list_field = "composers" migration_cls = migrations.MultiComposerFieldMigration class TestMultiArrangerFieldMigration(MultiArtistFieldMigrationTestMixin): str_field = "arranger" list_field = "arrangers" migration_cls = migrations.MultiArrangerFieldMigration class TestLyricsMetadataInFlexFieldsMigration(MigrationTestHelper): """Verify embedded lyrics metadata moves into dedicated flexible fields.""" migration = (migrations.LyricsMetadataInFlexFieldsMigration, (Item,)) def test_migrate(self, is_importable): """Ensure extracted metadata is preserved without mutating plain lyrics.""" lyrics_item = self.add_item( lyrics=textwrap.dedent(""" [00:00.00] Some synced lyrics / Quelques paroles synchronisées [00:00.50] [00:01.00] Some more synced lyrics / Quelques paroles plus synchronisées Source: https://lrclib.net/api/1/""") ) instrumental_lyrics_item = self.add_item(lyrics="[Instrumental]") self.lib._migrate() lyrics_item.load() assert lyrics_item.lyrics == textwrap.dedent( """ [00:00.00] Some synced lyrics / Quelques paroles synchronisées [00:00.50] [00:01.00] Some more synced lyrics / Quelques paroles plus synchronisées""" ) assert lyrics_item.lyrics_backend == "lrclib" assert lyrics_item.lyrics_url == "https://lrclib.net/api/1/" if is_importable("langdetect"): assert lyrics_item.lyrics_language == "EN" assert lyrics_item.lyrics_translation_language == "FR" else: with pytest.raises(AttributeError): instrumental_lyrics_item.lyrics_language with pytest.raises(AttributeError): instrumental_lyrics_item.lyrics_translation_language with pytest.raises(AttributeError): instrumental_lyrics_item.lyrics_backend with pytest.raises(AttributeError): instrumental_lyrics_item.lyrics_url with pytest.raises(AttributeError): instrumental_lyrics_item.lyrics_language with pytest.raises(AttributeError): instrumental_lyrics_item.lyrics_translation_language # remove cached initial db tables data del self.lib.db_tables assert self.lib.migration_exists( "lyrics_metadata_in_flex_fields", "items" ) class TestRemoveInheritedArtpathMigration(MigrationTestHelper): """Verify inherited artpath flex attributes are removed from items.""" migration = (migrations.RemoveInheritedArtpathMigration, (Item,)) def test_migrate(self): """Ensure the inherited artpath flex attribute is removed from items.""" item = self.add_item(artpath="/abs/path/to/cover.jpg") self.lib._migrate() item.load() with pytest.raises(AttributeError): item.artpath # remove cached initial db tables data del self.lib.db_tables assert self.lib.migration_exists("remove_inherited_artpath", "items") class TestRelativePathMigration(MigrationTestHelper): """Verify stored item paths are rewritten to library-relative values.""" migration = (migrations.RelativePathMigration, (Item,)) def test_migrate(self): """Ensure stored paths become relative while the public API stays stable.""" relative_path = str(Path("foo") / "bar" / "baz.mp3") abs_string_path = str(self.lib_path / relative_path) abs_bytes_path = os.fsencode(abs_string_path) # need to insert the path directly into the database to bypass the path setter self.lib._connection().executemany( "INSERT INTO items (id, path) VALUES (?, ?)", ( (1, abs_bytes_path), # add a string path to ensure the migration handles it (2, abs_string_path), ), ) old_stored_path = ( self.lib._connection() .execute("select path from items where id=?", (1,)) .fetchone()[0] ) assert old_stored_path == abs_bytes_path self.lib._migrate() item = self.lib.get_item(1) assert item # and now we have a relative path stored_path = ( self.lib._connection() .execute("select path from items where id=?", (item.id,)) .fetchone()[0] ) assert stored_path == path_as_posix(os.fsencode(relative_path)) # and the item.path property still returns an absolute path assert item.path == abs_bytes_path # also check the string path was migrated correctly str_item = self.lib.get_item(2) assert str_item assert str_item.path == abs_bytes_path class TestMigrationBackup(MigrationTestHelper): """Tests for the backup-before-migration feature.""" migration = (migrations.LyricsMetadataInFlexFieldsMigration, (Item,)) db_on_disk = True @classmethod def setup_previous_state(cls, monkeypatch): monkeypatch.setattr( "beets.library.models.Item._fields", {**Item._fields, "lyrics": types.STRING}, ) @pytest.mark.parametrize( "config_value, expected_count", [(True, 1), (False, 0)] ) def test_backup_config(self, config_value, expected_count): self.config["create_backup_before_migrations"] = config_value self.add_item(lyrics="some lyrics") db_path = self.lib.path self.lib._migrate() backups = [ f for f in db_path.parent.iterdir() if os.fsdecode(f).endswith(".bak") ] assert len(backups) == expected_count class TestInstrumentalLyricsInFlexFieldMigration(MigrationTestHelper): """Verify legacy instrumental markers move out of canonical lyrics.""" migration = (migrations.InstrumentalLyricsInFlexFieldMigration, (Item,)) def test_migrate(self): """Ensure exact instrumental markers become metadata, not lyric text.""" instrumental_item = self.add_item(lyrics="[Instrumental]") regular_item = self.add_item(lyrics="Regular lyrics") self.lib._migrate() instrumental_item.load() regular_item.load() assert instrumental_item.lyrics == "" assert instrumental_item.lyrics_instrumental == "1" assert regular_item.lyrics == "Regular lyrics" with pytest.raises(AttributeError, match="lyrics_instrumental"): regular_item.lyrics_instrumental # remove cached initial db tables data del self.lib.db_tables assert self.lib.migration_exists( "instrumental_lyrics_in_flex_field", "items" ) beetbox-beets-00724b7/test/library/__init__.py0000664000175000017500000000000015253035401020575 0ustar pieterpieterbeetbox-beets-00724b7/test/test_util.py0000664000175000017500000004277015253035401017432 0ustar pieterpieter"""Tests for base utils from the beets.util package.""" import os import platform import re import subprocess import sys import unittest from pathlib import Path from unittest.mock import Mock, patch import pytest from beets import util from beets.library import Item from beets.test import _common from beets.test.helper import NEEDS_REFLINK, BeetsTestCase _p = pytest.param class UtilTest(unittest.TestCase): def test_open_anything(self): with _common.system_mock("Windows"): assert util.open_anything() == 'cmd /c start ""' with _common.system_mock("Darwin"): assert util.open_anything() == "open" with _common.system_mock("Tagada"): assert util.open_anything() == "xdg-open" @patch("os.execlp") @patch("beets.util.open_anything") def test_interactive_open(self, mock_open, mock_execlp): mock_open.return_value = "tagada" util.interactive_open(["foo"], util.open_anything()) mock_execlp.assert_called_once_with("tagada", "tagada", "foo") mock_execlp.reset_mock() util.interactive_open(["foo"], "bar") mock_execlp.assert_called_once_with("bar", "bar", "foo") def test_sanitize_unix_replaces_leading_dot(self): with _common.platform_posix(): p = util.sanitize_path("one/.two/three") assert "." not in p def test_sanitize_windows_replaces_trailing_dot(self): with _common.platform_windows(): p = util.sanitize_path("one/two./three") assert "." not in p def test_sanitize_windows_replaces_illegal_chars(self): with _common.platform_windows(): p = util.sanitize_path(':*?"<>|') assert ":" not in p assert "*" not in p assert "?" not in p assert '"' not in p assert "<" not in p assert ">" not in p assert "|" not in p def test_sanitize_windows_replaces_trailing_space(self): with _common.platform_windows(): p = util.sanitize_path("one/two /three") assert " " not in p def test_sanitize_path_works_on_empty_string(self): with _common.platform_posix(): p = util.sanitize_path("") assert p == "" def test_sanitize_with_custom_replace_overrides_built_in_sub(self): with _common.platform_posix(): p = util.sanitize_path("a/.?/b", [(re.compile(r"foo"), "bar")]) assert p == "a/.?/b" def test_sanitize_with_custom_replace_adds_replacements(self): with _common.platform_posix(): p = util.sanitize_path("foo/bar", [(re.compile(r"foo"), "bar")]) assert p == "bar/bar" @unittest.skip("unimplemented: #359") def test_sanitize_empty_component(self): with _common.platform_posix(): p = util.sanitize_path("foo//bar", [(re.compile(r"^$"), "_")]) assert p == "foo/_/bar" @patch("beets.util.subprocess.Popen") def test_command_output(self, mock_popen): def popen_fail(*args, **kwargs): m = Mock(returncode=1) m.communicate.return_value = "foo", "bar" return m mock_popen.side_effect = popen_fail with pytest.raises(subprocess.CalledProcessError) as exc_info: util.command_output(["taga", "\xc3\xa9"]) assert exc_info.value.returncode == 1 assert exc_info.value.cmd == "taga \xc3\xa9" def test_case_sensitive_default(self): path = util.bytestring_path(util.normpath("/this/path/does/not/exist")) assert util.case_sensitive(path) == (platform.system() != "Windows") @unittest.skipIf(sys.platform == "win32", "fs is not case sensitive") def test_case_sensitive_detects_sensitive(self): # FIXME: Add tests for more code paths of case_sensitive() # when the filesystem on the test runner is not case sensitive pass @unittest.skipIf(sys.platform != "win32", "fs is case sensitive") def test_case_sensitive_detects_insensitive(self): # FIXME: Add tests for more code paths of case_sensitive() # when the filesystem on the test runner is case sensitive pass class PathConversionTest(unittest.TestCase): def test_syspath_windows_format(self): with _common.platform_windows(): path = Path("a") / "b" / "c" outpath = util.syspath(path) assert isinstance(outpath, str) assert outpath.startswith("\\\\?\\") def test_syspath_windows_format_unc_path(self): # The \\?\ prefix on Windows behaves differently with UNC # (network share) paths. path = "\\\\server\\share\\file.mp3" with _common.platform_windows(): outpath = util.syspath(path) assert isinstance(outpath, str) assert outpath == "\\\\?\\UNC\\server\\share\\file.mp3" def test_syspath_posix_unchanged(self): with _common.platform_posix(): path = str(Path("a") / "b" / "c") outpath = util.syspath(path) assert path == outpath def _windows_bytestring_path(self, path): with _common.platform_windows(): return util.bytestring_path(path) def test_bytestring_path_windows_encodes_utf8(self): path = "caf\xe9" outpath = self._windows_bytestring_path(path) assert path == outpath.decode("utf-8") def test_bytesting_path_windows_removes_magic_prefix(self): path = "\\\\?\\C:\\caf\xe9" outpath = self._windows_bytestring_path(path) assert outpath == "C:\\caf\xe9".encode() class TestPathLegalization: _p = pytest.param @pytest.fixture(autouse=True) def _patch_max_filename_length(self, monkeypatch): monkeypatch.setattr("beets.util.get_max_filename_length", lambda: 5) @pytest.mark.parametrize( "path, expected", [ _p("abcdeX/fgh", "abcde/fgh", id="truncate-parent-dir"), _p("abcde/fXX.ext", "abcde/f.ext", id="truncate-filename"), # note that 🎹 is 4 bytes long: # >>> "🎹".encode("utf-8") # b'\xf0\x9f\x8e\xb9' _p("a🎹/a.ext", "a🎹/a.ext", id="unicode-fit"), _p("ab🎹/a.ext", "ab/a.ext", id="unicode-truncate-fully-one-byte-over-limit"), _p("f.a.e", "f.a.e", id="persist-dot-in-filename"), # see #5771 ], ) # fmt: skip def test_truncate(self, path, expected): path = path.replace("/", os.path.sep) expected = expected.replace("/", os.path.sep) assert util.truncate_path(path) == expected @pytest.mark.parametrize( "replacements, expected_path, expected_truncated", [ # [ repl before truncation, repl after truncation ] _p([ ], "_abcd", False, id="default"), _p([(r"abcdX$", "1ST"), ], ":1ST", False, id="1st_valid"), _p([(r"abcdX$", "TOO_LONG"), ], ":TOO_", False, id="1st_truncated"), _p([(r"abcdX$", "1ST"), (r"1ST$", "2ND") ], ":2ND", False, id="both_valid"), _p([(r"abcdX$", "TOO_LONG"), (r"TOO_$", "2ND") ], ":2ND", False, id="1st_truncated_2nd_valid"), _p([(r"abcdX$", "1ST"), (r"1ST$", "TOO_LONG") ], ":TOO_", False, id="1st_valid_2nd_truncated"), # if the logic truncates the path twice, it ends up applying the default replacements _p([(r"abcdX$", "TOO_LONG"), (r"TOO_$", "TOO_LONG") ], "_TOO_", True, id="both_truncated_default_repl_applied"), ] ) # fmt: skip def test_replacements( self, replacements, expected_path, expected_truncated ): replacements = [(re.compile(pat), repl) for pat, repl in replacements] assert util.legalize_path(":abcdX", replacements, "") == ( expected_path, expected_truncated, ) class TestPlurality: @pytest.mark.parametrize( "objs, expected_obj, expected_freq", [ pytest.param([1, 1, 1, 1], 1, 4, id="consensus"), pytest.param([1, 1, 2, 1], 1, 3, id="near consensus"), pytest.param([1, 1, 2, 2, 3], 1, 2, id="conflict-first-wins"), ], ) def test_plurality(self, objs, expected_obj, expected_freq): assert (expected_obj, expected_freq) == util.plurality(objs) def test_empty_sequence_raises_error(self): with pytest.raises(ValueError, match="must be non-empty"): util.plurality([]) def test_get_most_common_tags(self): items = [ Item(albumartist="aartist", label="label 1", album="album"), Item(albumartist="aartist", label="label 2", album="album"), Item(albumartist="aartist", label="label 3", album="another album"), ] likelies = util.get_most_common_tags(items) assert likelies["albumartist"] == "aartist" assert likelies["album"] == "album" # albumartist consensus overrides artist assert likelies["artist"] == "aartist" assert likelies["label"] == "label 1" assert likelies["year"] == 0 class HelperTest(unittest.TestCase): def test_ancestry_works_on_file(self): p = "/a/b/c" a = ["/", "/a", "/a/b"] assert util.ancestry(p) == a def test_ancestry_works_on_dir(self): p = "/a/b/c/" a = ["/", "/a", "/a/b", "/a/b/c"] assert util.ancestry(p) == a def test_ancestry_works_on_relative(self): p = "a/b/c" a = ["a", "a/b"] assert util.ancestry(p) == a def test_components_works_on_file(self): p = "/a/b/c" a = ["/", "a", "b", "c"] assert util.components(p) == a def test_components_works_on_dir(self): p = "/a/b/c/" a = ["/", "a", "b", "c"] assert util.components(p) == a def test_components_works_on_relative(self): p = "a/b/c" a = ["a", "b", "c"] assert util.components(p) == a def test_forward_slash(self): p = rb"C:\a\b\c" a = rb"C:/a/b/c" assert util.path_as_posix(p) == a class FilePathTestCase(BeetsTestCase): def setUp(self): super().setUp() self.path = self.temp_path / "testfile" self.path.touch() # Tests that we can "delete" nonexistent files. class SoftRemoveTest(FilePathTestCase): def test_soft_remove_deletes_file(self): util.remove(self.path, True) assert not self.path.exists() def test_soft_remove_silent_on_no_file(self): util.remove(self.path / "XXX", True) class SafeMoveCopyTest(FilePathTestCase): def setUp(self): super().setUp() self.otherpath = self.temp_path / "testfile2" self.otherpath.touch() self.dest = Path(f"{self.path}.dest") def test_successful_move(self): util.move(self.path, self.dest) assert self.dest.exists() assert not self.path.exists() def test_successful_copy(self): util.copy(self.path, self.dest) assert self.dest.exists() assert self.path.exists() @NEEDS_REFLINK def test_successful_reflink(self): util.reflink(str(self.path), str(self.dest)) assert self.dest.exists() assert self.path.exists() def test_unsuccessful_move(self): with pytest.raises(util.FilesystemError): util.move(self.path, self.otherpath) def test_unsuccessful_copy(self): with pytest.raises(util.FilesystemError): util.copy(self.path, self.otherpath) def test_unsuccessful_reflink(self): with pytest.raises(util.FilesystemError, match="target exists"): util.reflink(self.path, self.otherpath) def test_self_move(self): util.move(self.path, self.path) assert self.path.exists() def test_self_copy(self): util.copy(self.path, self.path) assert self.path.exists() class PruneTest(BeetsTestCase): def setUp(self): super().setUp() self.base = self.temp_path / "testdir" self.base.mkdir() self.sub = self.base / "subdir" self.sub.mkdir() def test_prune_existent_directory(self): util.prune_dirs(self.sub, self.base) assert self.base.exists() assert not self.sub.exists() def test_prune_nonexistent_directory(self): util.prune_dirs(self.sub / "another", self.base) assert self.base.exists() assert not self.sub.exists() class WalkTest(BeetsTestCase): def setUp(self): super().setUp() self.base = self.temp_path / "testdir" self.base.mkdir() (self.base / "y").touch() (self.base / "x").touch() base_d = self.base / "d" base_d.mkdir() (base_d / "z").touch() self.str_base = str(self.base) def test_sorted_files(self): res = list(util.sorted_walk(self.str_base)) assert len(res) == 2 assert res[0] == (self.str_base, ["d"], ["x", "y"]) assert res[1] == (str(self.base / "d"), [], ["z"]) def test_ignore_file(self): res = list(util.sorted_walk(self.str_base, ("x",))) assert len(res) == 2 assert res[0] == (self.str_base, ["d"], ["y"]) assert res[1] == (str(self.base / "d"), [], ["z"]) def test_ignore_directory(self): res = list(util.sorted_walk(self.str_base, ("d",))) assert len(res) == 1 assert res[0] == (self.str_base, [], ["x", "y"]) def test_ignore_everything(self): res = list(util.sorted_walk(self.str_base, ("*",))) assert len(res) == 1 assert res[0] == (self.str_base, [], []) class UniquePathTest(BeetsTestCase): def setUp(self): super().setUp() self.base = self.temp_path / "testdir" self.base.mkdir() (self.base / "x.mp3").touch() (self.base / "x.1.mp3").touch() (self.base / "x.2.mp3").touch() (self.base / "y.mp3").touch() def test_new_file_unchanged(self): path = util.unique_path(self.base / "z.mp3") assert path == self.base / "z.mp3" def test_conflicting_file_appends_1(self): path = util.unique_path(self.base / "y.mp3") assert path == str(self.base / "y.1.mp3") def test_conflicting_file_appends_higher_number(self): path = util.unique_path(self.base / "x.mp3") assert path == str(self.base / "x.3.mp3") def test_conflicting_file_with_number_increases_number(self): path = util.unique_path(self.base / "x.1.mp3") assert path == str(self.base / "x.3.mp3") def test_conflicting_file_with_multi_digit_number_increases_number(self): (self.base / "w.10.mp3").touch() path = util.unique_path(self.base / "w.10.mp3") assert path == str(self.base / "w.11.mp3") class MkDirAllTest(BeetsTestCase): def test_mkdirall(self): child = self.temp_path / "foo" / "bar" / "baz" / "quz.mp3" util.mkdirall(child) assert not child.exists() assert child.parent.exists() assert child.parent.is_dir() class TestAsciifyPath: @pytest.fixture(autouse=True) def _setup_config(self, config): config["path_sep_replace"] = "_" @pytest.mark.parametrize( "platform, normalization", [ _p("darwin", "NFD", id="macos"), _p("linux", "NFC", id="other-platform"), ], ) def test_normalizes_unicode_for_platform( self, monkeypatch, platform, normalization ): normalize = Mock(wraps=util.unicodedata.normalize) monkeypatch.setattr("sys.platform", platform) monkeypatch.setattr("beets.util.unicodedata.normalize", normalize) assert util.asciify_path("caf\xe9") == "cafe" normalize.assert_called_once_with(normalization, "caf\xe9") @pytest.mark.parametrize( "path, expected", [ _p("plain", "plain", id="ascii"), _p("\u201c\u00f6\u2014\u00cf\u201d", '"o--I"', id="unicode"), _p( f"caf\xe9{os.sep}na\xefve", f"cafe{os.sep}naive", id="path-components", ), ], ) def test_transliterates_path(self, path, expected): assert util.asciify_path(path) == expected @pytest.mark.parametrize( "replacement, expected", [ _p("_", "abC_ 1_2d", id="default"), _p("-", "abC- 1-2d", id="configured"), ], ) def test_replaces_generated_separators(self, config, replacement, expected): config["path_sep_replace"] = replacement assert util.asciify_path("ab\xa2\xbdd") == expected def test_normalizes_alternate_path_separator(self, monkeypatch): monkeypatch.setattr("beets.util.os.sep", "/") monkeypatch.setattr("beets.util.os.altsep", "\\") assert util.asciify_path("caf\xe9\\na\xefve") == "cafe/naive" class EditorCommandTest(unittest.TestCase): def test_editor_command_from_config(self): """editor config option takes priority over environment variables.""" from beets import config config.set({"editor": "nano"}) with patch.dict(os.environ, {"VISUAL": "vim", "EDITOR": "emacs"}): assert util.editor_command() == "nano" def test_editor_command_falls_back_to_visual(self): """Falls back to $VISUAL when no editor config is set.""" with patch.dict( os.environ, {"VISUAL": "vim", "EDITOR": "emacs"}, clear=True ): assert util.editor_command() == "vim" def test_editor_command_falls_back_to_editor_env(self): """Falls back to $EDITOR when no editor config or $VISUAL is set.""" with patch.dict(os.environ, {"EDITOR": "emacs"}, clear=True): assert util.editor_command() == "emacs" beetbox-beets-00724b7/test/rsrc/0000775000175000017500000000000015253035401016003 5ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/abbey.jpg0000664000175000017500000002747615253035401017607 0ustar pieterpieterÿØÿàJFIFÿÛC ( %"1"%)+... 384,7(-.,ÿÛC  ,$$,,,4,4,,4/,,,,,,,,,,,,,,4,,4,,,,,,,,,,,,,,,,,,,,,,ÿÂáá"ÿÄÿÚÉ=âÒð^qÙûv‹îsÞê»Ï{¾Çª¤À«¦§’Q£•7r½Î{�W}îø E±áÖ¥ºóÎÊ8dÝܶ×Îu~ïX‚ÈÛ�*ßuç%žÉrää.Î{žò»]¨�b¶¾©éB‚\Ô¼�ÔÞ{Е¤º:¹KjB&-—8·ÏŒ,·,ú¯½ïCæñ­è´I€¥Îs¤³6lDî«-ï{<¨ ÒÁ§>X®¨WXaöº· :SC²û�ã!7)ÚÌzQÇSŧÄ1Å–›�â×ïWs¶‘"Ç;Ä+ÞWº“ì†�hn¡I‰_ ÖšWÓŽû‡ßd¥Ç/Y�¨çíÃ…E†3žë\zlÊáÀ6³ìoÙ/yàND9Ñ΋áò—-Ø—–͹‰jé6wàãmEWêðÒG(Šó>÷d° ýÒTÈ´ ¦*©E™*Ò}nRÉŸ+¾´Hm¡ðÞI„pV�AÔüœ Ó‘[×}°zÎq'? DœaDWÙ9`X(‚²”Ⱦõ”lP"¾$ÀdÌÀqÉS”»Ôr8@„ÏXÓSD¹ÊˆôáW*öç ”œ¾@Qž�K9š»%3éoG^·”@´ �œ"ët¨ÅŠ’W¦Y®in B&mþÖ«öID¶ŸÁœëĸ æ¸†`gG%ѪAßÒÒlµbš÷‹ç¬@çŠ^¨îaZvÇ©Ô)”�¶‰®ä+ÙNæ*‹5­•œñ»Jf¡é@]*št&fþñ…nT°Ö‰¼…›â‡_zÃl]j¶É×ú�ÔJ¥�K¦si¬bö}ÁȬt5ŽþÔë�™! Õg=Š˜f‹8¹í}‹Ö“èÜd4ëÓ} !o“ZÛ~¯e¤rñ{â³ÚO‹×d½A¸Jy8èžoW°£Ôj[.ÙôÔ¬L1õŸ³sʽÊkýôæ¾×»—ÖÜå�TCÍ«žjó¢§Ìø<)÷†Ò.éK˜äYÛ5tÕ)Ö*Kcèd{ÿÄÿÚ®¯¢Øl¼ P%�_A˜[,˜vÔp ’ôOvÓ—’}³ –}§Št¡Û g¯Î¬\í¶Yí¥v“²Xs‹L„°K×H%$´Œ™ËÙÒ&±›bö<Ý O^aú9ê&/ÓÝhR±�´— òÒü¯}Ê×J^|¥íDçk˜-m¸ÿÄÿÚ�C”qï.ÄäŠOG\ÒÀ&œ•^½ˆ‚›i¤TÔìØe”GC3ˆV–ç­�ÁÒ”@éŠ,ë#iÃiB–ظ5sv!�EpD�(†’l!i»<�±ÑqYÊÌš™ì±Ý 2äL× ¥(©©‘uÇÿÄ# 0ÿÚí£ãá”YÙ3g*&ÿW}]Ôì*%¯‚!lè×ô�Û×ÝQeÎ:ð�j‘¦0Õ1øŒ»oÉ oLÇ _o®¢�2uòÉ¥`–ê¶#t:�°!þôÏ~ƽq V´!ö¿  ªÔ°Ôª«=<ÚØÕk~,i[Ò6ãi_Ó´kÖš¨+Ûµí\¥^BI[‰~Ôtc£�íù½vÑÍŒ˜÷ÚÍRÌŸ*ƒ3IÙ;3ÀPjôëP( LÛ�«LAÌU™¬¨‰šBŸ»Ê K¦”¥â±ŒªF…þÈæºR¯Ïl®¼¯#_"fêéØrƒ1àL»�èØµµú»ÌóRo*2gý»y¤:±¬±¤‰;z6æLç”&hÁÔʼºféÔÔWÀì™V„!ÂYvW!¶6ºö¬U?Úô)¨§NÝE©Ïbœd8IÓ “@" á\úº7­[5IX Bc ¾^%@ºwñè' »·ý€Ž˜|n a51å<™�­B.N6j³F¶esScV0ñù¦™J›Ô~<\­”ÊF›ÈÑ#Ž�-7$C�Sž�ÿdWÀ¦ýò™º“®.îý]¬ÎÏç2ó:óç¦[úqtÒÆ¨ÿŽBRwÇôk¹É+ùg“ñÍ_Íä4ÊJ+‰'éºØCU–'|‘e.\„¤¦†¥ßÿÄB!1AQ"aq�‘ 2¡±ÁÑð#BRáñbr’$03S¢²c‚ÂCT£ÒÿÚ?Ò;h$™0EA)—Œ5ÞÞžÏ\ ’ I¸ZaÝè?޵ûDkM`€RÅšŒ'>€5-².‰ãŽ#6õ„ë¾·A-yDï Fø#Ùý©ÜS6xPcŽ^<`¬6ªqlË–¿XCj]a—ñlÀ{éæ!íT &sÂÒ¹‚yn¥^? {?ù臜=áÃcµëã¹Êj¨­\�Ð’Ï”P�”�ң֓ü3˜Çt 4½™½,¤ù>‘u™Éüt�?‚ &BqgqNãTÔl…-ì�€Ú}a°&�åê“IzúÆþ�Îct$«ZrÀ÷E˺¢îîfÈ$GRBÁÖúyBН*w‹Fqðâ BЩ•…ÜŸ¾T…üÙH™ð9ï…Z®ã¨ _x ?�vÍGº³.™)�[6ARa3ÀEàÎEÚ‡ÇÂP¢DçGÆqtÞ�pï7�ôÇ®€ÒJO?8i›EØ|kju(³â;Øï€:¶©VÉ‚xc1bÌxq‚vs³|lKDŸÂU«¡µs¼ïZ˜õÇ¢”6öƒx34•ÛHÕïcf¡7ûÃøX~¢pÇ(¼‚%ª†”]Kq#dg7>3jÅÕlkÙ„V…E«_M ù ­A)©§~†ÒDÄ&é`AìYB½z¦Èº]) -êTÎ {ÍøeÙ ð PJyöƲMõ‚Cg»‡HYƒœ^w8‡nÆŒ$æ)xηwQáœæi ¯8kÃ^š ™ ¹'\ ÓRœK žPÄ»7Ëç8ž{!_?öý4ývíè8•r‰±În[·6“i=vPo�޲p#8 È=g A”ùÏœ*Ñ7”›£‰§ýÄcÓAøDü8ãÛôœvÆ7‰¬4™à”–ì‚ó„Ês9Òû DÞEû ^Àí…úxÕÁ¤9}áK{ _(m�>o�8REHÙHÏñ1À@I½J/–ÿ¹_Jt$bò”­eeª}²ºÆ°f Ìóôñ&xü­KŒg¿¡'ûÁÌè—Ÿ†Ý$ JN>šÁjÇïW¹�.üýVdׇ@Ùɘ=aݺ/¡ LçQÙŒ_*K¹)Q½,(ǵ5£7žÈAž?YA¥c�`¤9©ìÒÚOnƒ6”^wsŸÚ¢À“V™J0êšbÏåHq7 d©3}‡-!Ì„VèÜIð‚º›­GÌPÅïÌ>YÕså2;˜@Ö8dõ9F³™Ã´ç šôéëœO(Øð6»_,ó!6cãH5*™å„„o‰#‡Ú}œ„Ý7…L!™@¾bSSí¤(I#8(¹uœÌùEå•—ò€@/‹;™J¼êêìÄÒ5Ž¢ëò�¶0¡yK•FÜ”;°ãŽÙœá½a|€£Î&ä‚��šŽ¬©¯m=Ç@H"èRvÔdÇ6�…{tO8œØnúE/,Š”›Fz§Æp”Z+†i»ÛŒ ”¤†.Á…x¾è÷ uØ/t‘t5êËqh{‹z¦•„à’“x>8ò…‚�îýaFß² JƒÊvà%¾€IK)Å•G ¼;8˜ïðh³Ö•âê¼H=S„öÁ.¤†H“c²ZpÖÊ=¢‹Ðcå¾/,¤ Špqã ¼EÓ,>Ðæœ ˆ9ŒÎè¦qh«º‹¤õLhFð| =`Y¨`¯øKBn, 0MÅTÞ#ëOz[}JÀkjïËÁƒvƵãS+ßçÊ Æ»~bcÅ1íM¥×ìüÛa@=âÁ7‹�âyŠÐÅà•-D¸rœ) M±EšXÈ»bî&*áÃ�Æ nâ�°¸§‹s”öE�'Þ§ù˜e3AÇö�±R@–xE¥õX–‘…n,`•ÝQP‘Ç” ÿöôBÙ(þdÝèÞiû4¬Ðhæò™Ø ;ãö”õìïÊGh�ÝÅ©OZWLÇÚY$Ó™wÈøZœb¡å´äl�ï‰L¾Ý“°ŽÙyCB²ìÕ‹c½Á‚§™ n«ÙQ”^„ÄN/ k›ÎÜyÖ-×Mñó#­ÅP…Í,xLoFâ6Â'«X_úÝ´lã„êËt_¥‰ÃÖpq£aî†ÏžŠ@cí‡H9�  vƒù#ðÞððÐn§w@¨ßÀSiÆ[à€N“ñ³´.d¬ +ž1jŒ­“±‚Çœ!}UOÅãaä`žª@2ür}n„ §lLÓ&ƒgh’’uUM†£”!S[¡¬!IJJ’ÁT}�õtÎ5RŸ•ç¼¾‰eÞØ¬Q€‡Õâp¥›€0ya¤­A"¦$"QvÐ~_xO£¤¢ÎÓ¬™æ$®b?Õ¶ýGCSCÅÒ »õ·ùCŽþ�#`¬{[¡]d¨LâP4^AúÊEĸÜ|!É9ÏJí-S¬©N¦�q�D+"Ç�Ôvè7Áʹ­Ò2ÄùE�ÊQ‹ $\žÌÏ8ã(*’¼6Gìê¢rÕ‹é#”%J÷iJlă}¦0ÆtknÄÂ=²BÂJT[:�Ùq‹/é#ôˆJ}š�̆LÝð—1}U™Æ¿ÙABRP.ŠêÌm”'ÛÝ]Ò•&Wš¸6ÚÂUd¤¥ c]ÅÞ¶ XöiIH´mk¸Ãï-lÊpP¬*ÍWV'Þ3,É´MÕào=²1cò«õ±É_¨èMžªYKìNÿ(RÕyEÎ߀ŠCilá³8þm›"bÒ¸ -+§¾‘xû$|g3–ìô4Ì2 UW]Ø(7HÕ=S˜‹ãÙ¬ë©zŒ·ˆ{oÊ‘çÏá†bõ…˜Ä R�el´d];ŒÃzÂ=½�'®™/~ŒÛ€uæ€6Ô Æ†ºØÚv'vݱuW,Ø‘Ö>àZ -4=™ˆ”&Õ7UÀâ!VJººá·hЫ=[Mdpó‹êØ+-gªŒñW�‡!#0¬ä¼¶Zï´µþÔqÄ–oZªy8J’É {ýg ³A]²™# rœY+VÅ *TAs΂,K9'â,• âovÃÞ&ÒÈMW\ƒ�œ$Дì”� éÀÔžÈÞ.éù¾ —hØ’û„¼"p£²Á&̲�=ð¥X‘ÁƶÅ�Š–m¤–ÿkmÅà*êÛ 8b®ê@²C$ûÓ!øv˜&plÖ�qUØsó€ à¸‰Âm“uUøNFd«ªàp#1£×¡Ù ¾Ÿg5¾¨‹K£Ú]½�×h`Á€À Å9¬õG‰Ø!ÕxÍU$×O²³ŸYZÊð¶é²KRªÛ( «Àw“ìûè÷j/ÀB-Suiq–I–ÈRW}*qBƒ– “E™µ%!^Ñýà4¤›³CÂ�6eR¨ž;#gn„Û&ê¸A…Y*ê¸Ñ¡V‹@uwfNÈMˆù–j¯,†”Ù ­Xa™À6Š+WXödÍ>ÖÔ?U:ÇÀsñè7ìëüLžgÉôñ0âÔmImà�‡VУþ:JK‰Hȼ+E Ž”Ú¦ê¸Žb-?©gúUç ±MÔñ8ŸYi D°&n·¢GPxñÓ(övZÝuë+Àrè-’®RñŠ·Þ7¿¬!öOïý{Qâ¡í,ԌķáÛñߎŸchð™,lúC‡=?j „ÿ,Ÿ˜ù ´{kYõQ¬¯øŽ}Ç¢öíò¤&~0À{#Öq¶�9Çïª öiJ:Ä£ÂX-$šN.[^X~?ct)`¶ÊÌÿÄøt½Òÿ)î‰XD‡åÑ!�[]éÿ�ï6ž¾Ýãñ3º?yGå?â4û¡ù¼ {ë-þq+=çº%ÇÃD£^Ïó§üÇCÿÄ'!1AQaq�¡‘±ðÁÑáñ ÿÚ?0úF¶%'§ k÷¼^ÁEA�¦àÜ_Î,ˆCGVÄuu<ã�‡‘<óë‘`ŸZ¡ÑS§[À°*aïÑñß9 9íÑ7+]µ‡ 5 ”D3$$^ êý1ÿÈÿè2!n‰¢_·9P‰‚Fg¶ ›È )˜ :"¶Ì‰âþûäaƒÖðH@zȱ¸ã×ué’”@²¹h]²B02JÅMÅ q ÛÖÆ(¤>lIèœeØü¨ž»C×4†úÿžþ‘Š›A71|}Ü4ØàÙ…[ðù19YÐdBÁÈšÅ!¦¹ˆ-³ÂærpÿÒ‰ -]Õà¶(²¤ @ ÌUå7*b™$/“}Æ~£#hW œOÓZ¾";ž>øÉ:—üørØ4æçr&°¬D“AHd&zØ3ºÉ "*‹°(“ãÁŽHC0›±~玌Þ.ÑIQŠv3Œ)“Úš‰ì7Ã¥˜Ì&1 ¤²4+˜ÄI¶¦nyO®Q»Ç®F900ÈÀÊêJAh%kÆXĆ� üå@V4¤>F•œPX`¶J‘!º“œU"ÔXÒÈÕß:g§áýaŠ,Qá+çZ¹ÁdBjü¿»Âp#ʦ&9fã%Ò”•#Î’ú;sî„Ñ™AʆL–DÊ¢T›î}8qjlM©ç[CZ�mP Å …@†Y�åĨ6¡$M‰óžx‘QE²L$HWÔýâ½9Ë$"@J»ÔÌ1f#r ˆGŠš/F‚@^Ç®ý2p•"½í6›Ôd‰ Ó©±O_œŽŒhZf8©ŸÑ„ÄYeÏ�àªçÜ{dYzá�Ó$dÛ…>‘yVaA¸g€ï(f%$i×Ürz–tYÐF–9¾±™1™ÜL$lïxfÈ‹„.ån†«!…8%œ1*oü¤©³N22³N/Ó’„DH%tÀd¾ÏŒU–´X±J)¾ûrdÞ)ˆd$�Æ UÄkUY9Aì|_Û#W•›"ßû‰‚FàÒy¨N}pLRF9H £kïƒyè)s:¼3ÐLA¹ª>3Äþý1¬‚n‹1×åŠ@yBéòkÆJ,¾:¾yûüï �ĵÐKýÆ'ëŒW1þâ"(³mú¢ïÐÍ ³g”ŒMÙ?8òÚe�¢¤Úy¿/[ÈÆTWMY©ßQ=d 5!7Ë $UkT¼`|‹ ”Áo)/ÿ0, ×qú02j•âGSW’ÊD;Òy.}WY1:@uVňõïY]Ÿ&ŽŽß~Œ”JÓ~_ûë�0^UIð&)H“Ò?œ�ÍÎÔ1j=qOðX!@ðÕšÞÚóÞÞs‰“z¹Öõï—n‘EvÙÖ¿Þ5ÿ>��È™7ûIÈBÏOÞ|` ÜKª%>ù Cѱõ†þøË *’º,,±+1³ ºMa0ixœ“ìèáJÔ¢«�ÿà¬@…[J� ³ÛJ3DƒÈÊÝNò"£DL‚Hõ`¦\gîíÕä,êÓ¾ÃTU˜ø d�n(Šd½Úzw�BNÈÈ{óR&\0 #‹_däˆeú“ÁÆ �ÍEžâAó—�/Ö_ÆZrYJà#ävT'p"ùã@$¬ “š’˼„ !´ÂBÚw­^)¸’ÕDD™ûd2”<#™`éÀLG °"0LÕÂá$‰IUeЉH“%Äã * b’EÞ"¤H�,£súäâF*å€ÒÜjñQ ™!#†ñyðgVåØ)äÅhÑ©@—£Ç*@Ú£~pg'"‚¹f «yqÜpp·Ô¥Î§%Í�´6µÌ³Ù”l5*j̤^y¯\  –Z•ˆµ5ãNÌQ�…±2Yó—AË=Q|(ˆ¨©"ĽÑûc²DÄ•¤Ípÿ1Ü“v+÷ã7�e“s'-!K„JK“ôŸ0Q’»Ï[F�n/å’!³§$Vʤl@7Ío! ­J(%•'�n÷„á›]²G@y7’ˆP ®ö ݉²Ãk’{juŽ0ÖŠ$ iqš€‚ÌÈ…ï%‡PKVa eÖ>C©H¢ÐÈСV�ஊÁbUX± Öy¿§Œpà ˆX?xÊÙ‘$ì “%Ñ¿YÈ’K¨�•@�ËšOa1òyv€Š ÐL õÀG%l¾Kde=¸™› ½O¾�rÉQD‚@üc½o÷mÃA-„S²Lõ†) $¹µˆGDÑ&N¶ HG ’-|˜Ì=¶HÉ2k¸bÌß8•(Ô �Hõç.y–¦‘$hÈĉ\“Ûw‹Í -?~ã6Áê'ç°®G]âõï ŸL÷|`{Ã2<‘‰b2ÜAáÆÅ…�°‹=�L‘@jÏ‹ÌN UànO¾®„ ê™ðA„¢1)i(Šu£ªÃ{¨XMOŒpb)ë¡?µ©JH@¡ú `®2 ʘÉWЙD|bè 냵ƒi9Ææš•KDZÛÖEÛï„’d§^¸ f€Hj äX¸õd¾- <‹ÔõÁ„x¸O‘|Ä‚÷‹�Ú§²7ïŠZn.W„×µ‚ióósö””ÍìÏùoï´`œý¾“> ì£m ã®e`‹Å´=«ýpf r¸8íËÂþ˜áMq^`ÍÇB^Ó>Í#”?_i&z&U¸Íw‹D6Ä-Y�PGB·m»Þñ T"#Ò2'£xäØ ê’çë½ã)6Îæ2f'dk¿Ýæã�?—0HD "‰Ín|`õ?¸Âe‡t>Azá2>Ø>�é)â¸öÏÐÿLN_sž¢;šûã’v“äJb$V”#š‰ù1(èÜ™�Áá1\äµ´æ>Ð`î®”ùOñ�"{ómàÉ^Tý÷À+Çëüá+î_ãµGÀ�8+ "�G±Ì¸žZ%Ru4~øx­%“‘y|øÁ4ÿ¿9>¯Û ýþ~Ù tüÝúb„ð倌/NòÚ’¸D�õã&?�䢓ÀL{¹×¼„¥„2®ªÜ9ç¸:âR�861Âd ”ŸX²/ðXGkè àç/o•mõÀTþùÇ%¶ö+QýáI9ãOø^3aúøz³ówï–ƒ U}�œ‡î~p§ÛÏçmn™ës�d—Üü|à¥âf=àûàÀÚ»zšŽ#"Õ„¯.ŸÞr2^ÿgº<ÿX3W#î%#í±uÝjÇGÄ>S4§_Üý!„ñVÎl£e—{xs³}u—zb4GB…©ÜÇ󚔓‹e�¢Œˆè{òÁï‡΂¡ž  ÏÙ‚�Á��ß©­k(ho¦ñàOßÌTbHÒOïœó>ßî@?PRsûöãPQYDlwàÄ€f¼±¥�]äV@‘7ûÞ5 -¡Z^¦ç˜ó‰—…¥ Ä)¨ÂŠˆ©€-_ðûàÊS£«æ·ŽÛz?¼ï†¢*³z0û`¡ ’NC¶ úŸ 8­[}±¡zôzଋÀ©ÿlVZà \¥îô à”nä"9Á‰ˆ@tŽá=ñD¤¦ “ÀyÀ@0bi©y{âg*1Ây�™$÷Äz”!(ìo‘1ybjJN¾Nrc©õ›ËÆ�¿ê†ž:ËdÇ÷çïÎ(ºMÏ­6�wÊcE¿2ƒÀP»pAHx î(õó�àÞs"w ôï¬ežÄ×(ÔG“]¤D¯×´á± 4½†|šáÎxÕÁËÄa%_»ý&$付‰>O9"×- a'³NVT® .b|¥ð䨤 Óoóñ‰Gƒù}\¾vß�+@¬�‚ á xä:NOÑ1\ødÚ&‹˜zë'‰Ã�•—ÜГ:Ä:]‹˜oÉ ÜÜþ)¢å!r6ñ%u§FaÚÒyöÄÓ“û¯Œ…–{{Ùú¿ÆB¼ûû`•(á;ü'9\Ùš&=éú?3Ð'ŠM'Ódy¶ßokøaô2CQ@\aycÕ3q©=W$#×“Çæ°;ýûæ!E‚Ñ�_ãçÑ èWÅ ò¸²~“œÈùåA 32­}Èãrd¤È¨0<’¦ŽÜ���‘1¹½Þku$ �zÎ_¿ÐŸ 1Ôž¿`fàB(: Q#7ÌýûâÊzÃÕ\Ê~ç8 ‚&‘$G¨Áú¯Ðdƒ¯ú<]¤ðOMW´y'xT®š:­>ìlÎú�E-dH&+)†SÂ'ÉÙŽ\_¡›$FäW©‰ï¼b bZoï0ϵPððB:F؈b}ò«S�¸D‹BÌD-ùœ ! z ¨òÓƒèxš¡(—qöÚ@,úw†â¢ÇÝ$w.Ô¸ž_Mg'X Óᪿœ�ˆ�1<�±±Òu.98}?OÛ?O«?Q×>øÍ^¯ÖCô™øYk“ù¿9🣧éñ|×ã¿éŸ•�ßÎ~O¤Ý߯ÿÄ.!1A"Q 2ðaq±3BR‘ÁÑñÿÚ?ïÀ¥î2 ¹ Úù›H”�ž½]ø}!CúŽDs$©!7\ézeΠèSy”‹iò\õjÍ’nìõ/ÏïòmóÁ QŽ’šŠ¶K<¤<�ÜÛ¸Kbà«äÛ÷ö¾V¥á‰û˜åkOľ(ãÈÓ}˜ãH¡¢¾V褺1}$òFŽn]õû sB…vWÈÄí Iv¯LY}<™”¬‡Šo�*b#EVŽš'Â"åT„68ɲ8åÆÉM©U ~ã’GÆŽ²”·;èr^ÄåÈäÔö¢© u-£ÈŸ“zòÉNJJ‡¾ÐÕ”´À–ó<ômHþd‰«$G±Å�Ê,\ro7³rF)ܸ?š{בɲä´ùC"½VK«(�"+š:7¯%ÇÜrF’rÝ™½/ ŠâÅÂ.¿R3RtD“ŽH;D$šà›¤E«6¦Kjá—¿úG¹•¨Å$G&ÙY7 OtWúH¥É –ȸÊohÚF7Rà~‰~Dc»Õ!ÃlˆOk¯&�…rQDczd~ !Âàå’U!�úQ%j†štÌy6þ‡Ä‡¿î>È-̪àn¹e·ËºZO½1:tôË V´½1tÆfúD#Çödû!õ"_ÄB< OÿÄ%!1A Q2"�ÁÿÚ?¿B’1¬¬¨±*EK.Ë~Šu²‡Ý�Š<^5gâµÚìÿ,´TžÇʉ&‡&óýŠ!äIi“ndz‡ÆIÖ†ílx„[bKT5cG‹Ñ(¡ªbM‘ЉG±EbìX}ìcNÈÇDbÇEü½–qŒ™%cŽÈ¢â?"–‘B‚jì§z)œxªUÙÅý’�=W xd¼iE1Di‘‚âìL¼[?!¿Ö~?‘µ·g"ÛDGÑ)hŒ…±ô44V<©qÙàðF0{ßü(±ZìKeꊼAY.±ÄâÅÏ$6‘5´Åâ¿eSs’²Pâ»,IÆJ‰E§²(kE±&ÖŽ2%?¢ål”•58Â¥þ¾Åú%‘%%È«$õ³úC~‘v‡HÚg6F2N±JËÙG¬>Ë¡2Q³õËt=‘VècÊëêñZøOÖ<_Öï ¡ôGùcøÿÙbeetbox-beets-00724b7/test/rsrc/t_time.m4a0000664000175000017500000001334615253035401017676 0ustar pieterpieter ftypM4A M4A mp42isom ŠmoovlmvhdÄLé_ÄLï¬D¸@�trak\tkhdÄLé_ÄLï¸@mdia mdhdÄLé_ÄLï¬D¸UÄ"hdlrsounÓminfsmhd$dinfdref url —stblgstsdWmp4a¬D3esds€€€"€€€@xú€€€€€€stts.(stscÌstsz.22""'-+1/+&0''&%)(-,*).)(*%)-4&6.*,$,3/'& stcoÆé •udta �meta"hdlrmdirappl°ˆilst©namdatafull"©ARTdatathe artist$©wrtdatathe composer!©albdatathe album!©gendatathe genre trkndatadiskdata,©day$data1987-03-31T07:00:00Zcpildatapgapdatatmpodata6©too.dataiTunes v7.6.2, QuickTime 7.4.5¢----meancom.apple.iTunesnameiTunNORMjdata 00000000 00000000 00000000 00000000 00000228 00000000 00000008 00000000 00000187 00000000¼----meancom.apple.iTunesnameiTunSMPB„data 00000000 00000840 0000037C 000000000000AC44 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"©lyrdatathe lyrics(aART datathe album artist$©cmtdatathe comments$©grpdatathe grouping×freefree(mdatЃì\«11;Ä<Àøƒ¤4„ `I�fàe—^àï�P0#Ü·›�Áb˜Ä»VOØÙ(*¾J€q8òƒ„q©-@>Ťè[-3þ!‹rtg¼¼(ι¶q]b¥¸úƒÄPEÙ€€ ª°DãÙ‘>JUl3ËA$Ö)i)ƒÀúƒÄA#�€+:3ï`Xa¶™˜ÉùQ;«À±˜ˆèàöƒ¢" „Î Ž× óf{q wZ“Ä 3z¿f#)NÙq'øƒ¢" „kËr½ÙÖ£ g�§ý'”ê )y*¦˜Úö»,°Îµx¡úƒ¢" „r †BXVFìì7nhϦNž|z%ôe0Ue®«Œ œöƒ‚B„_`9åo¢ðJ­Dz0¯)òøáÛ1F8‘ú·åÉ>7t·#‹Uàøƒ¤4#ŒXÛõÞ™¾áàÒ`¸Ž‚Þ×xT†aGˆ~fäHv<ý¶ÁÀúƒÄ`? &ˆ×63Дl:äGàë’ 莵š„ÇÓëåN‚àúƒ¢R#Aש9Ï<³ÔiÇ%Öøê¦—µŠÍÎê®yfžÎôƒ‚T„ `®!�I}uhnV$?‹+ä¡(Z«„Á�¡Üta¥Vi±+±l‰8úƒÄ3#P�0¼ñ•T`’3¹èžÓ#?}¥ÕõÚ»ìÔ‹€úƒ¤Q#Hl`µˆÁ½¥ËK§)Q)E‚ñõ>O²Âô¯SÔ¦úƒÆ"#P ÛdpËŸ¿Û2é­~sÛÈÓï�'Pîì=Í&ü!úƒÄPG<Ž0NÝÍ�Eø™_ƒõ'1…:õ˜‹å\øƒ¢ ˆ,l ƒq¼Ôº<�¬>èðÍ&ïÞ¦J3}•]dQ€€8úƒ¢`F  8I+–¶:aá–;0¥Ç>m>;ßM¾íÛ�Ÿ× ¥/gøƒ¤p>€ÞbSci›”¤L z:~H�5ƒM3©'°A+è&„f ‡Ö(pöƒ‚0!dÀ¢’¯:%¢C°9B³î+]þ3Z†¹ècJr†Â¶�öƒ¤`E€�a,]µ)\BiwÈ,yç@úD¸ù�ü'ħ¥¨Üøƒ¢ ˆÐÀ€0qóà=bžmBÅAwùH°×! šDSª� 8öƒ‚5 !`Â4†§å^ñíª^:$9µÏ…gs`M%…ÊZZtª^U£Y(o€úƒ¢"ˆ¤09œ’#NÑ·#̬zÚW›;t A-1dyß”3¤^ àúƒ¢" "ìFâwì¼ú„,µ¸rŠþ¬js%”ŸÒísÙfžep=¼øƒ¤`G €@ÀãÒ5?à¼`•Ø�ÉÍM²ÈöÆýYB^×;C€øƒ¢`BÈ ÆãiRø—‡iéŽ6ˆ0 9ü¾åÓvë…(ÜÿÿGYJ´…=˜¢oçlÇWøƒ¤3 BÐ3ÜQhLÖÆ$/ê‡b<÷~³µ8ëûÛΚS�­n*jõXeÅ×7’#àôƒ‚"(„@Ø Ad¨*Â`óÙ'ሬÁ®co·>Vûça &µ% øƒ¤`F‚ ¢±äßxã}¸<ëÊüfP[2ÚqXä.Š'Iµpúƒ¢" „¤*ÓØšÖ'êŠÇÉR™z[oÝÓ¬ía‚„¾”XÇS2p'ÀøƒÆ2! éZðÞx²µ¾ùìú$©¿Vn´%j(óVÀöƒ¤`F‚�€öŽ�F†@›c}}ðCÂ2>Û<ÆçO5£!¹QÞ/grD�ðúƒ¤aBàô‡2‰´S(^®Z�dð{¦P�¤Ÿ~‰ÙÛ˜¦‘6 Sºœöƒ¢ „,`¼-1wNÞAÀÍ”XPKh¡wKÛ#0R¬Y±X�-Àøƒ¢`E� "ÅImq¤>w¢È1s5{!ÁXº[¯/æÛ?ÓG�¥xøƒ¢2"%€Xä  aÔž®ŽæÏû©ÆÏç¿÷º�r¯˜LaÀƒì\ªRi"?pƒì\¬ „ô@À\beetbox-beets-00724b7/test/rsrc/empty.ape0000664000175000017500000003215415253035401017635 0ustar pieterpieterMAC –4Ü3Ù0' 0éoÅ|ÍþqôèîˆD¬D¬P('¸è+6¹D€»…›gz¿ãÿnè±`Èé¯CÔC-]áXUÚ½ÛΈý–̹€ËRôa‹% –ýÒñ0ó©'lOéØ[&ï(ïïHõ)œ"i%6aMJO1FÅ@…D8Ùqlpù¤ŒE ]“¹$ê åýwëvy0äÏ\þv7®Œ±I˜®Æ ̇m7¥.uMÒÉè$Åý #­×x|‰SŸúgb;<·|:}|{H?k¬ò"ÁÓ{�äìæwß áÝéÝ¡"v˜útŽ`OM".ÿÄ+.Ë÷"q=f“; åF&8e*’<û´íH4ŠÈiçÞ-w»´7rý:¤Û˜œJ� \ó!¶Ü$W'8[4“ì«„ËAvìMXFÊUÄÍ�HU®qta!;{;ªë¹ ÊÁ­àG^ôad¶Gê™gŒ¾P¥­)«Œ·È úîØ™ÜzИšSŽøg_êˆQ¤Ü=ÏS ªù¶¸âèM¿‡næ”– ­u%ã÷ú¢ÓÁ8½ Ì úx«=j]m6“aú@�“I›L]ö~çên0.*§ãÏæcžânQjŠ0‚ôêí‰6j®ñ1ÚC%g§�4ß\-GhÙ3Ý•[èàH"’—ó@ù>¯3°+©ÙÎÿäÜG½ù§W3r˜ÚKn>œÒÚ+{ç²òô·Š¬´ &…ñ6u¿_zêmeS)K+2òkò± éØ8ôÝ‘c¼3L®ÝÚí�Žªv²WܸÚßèÑ‘�¶Yຓ@§1"kâr}õqIÆþu ¸ ¡©[#ØÈôð¦‘w“f•—C?s·”b Œ[XAÅÊ Ã=‰‹\ ú„yäü�vJe¹•ÙׂfÁ$0²¤y£ž}:ŽÎ Ø­ô[èr‰zØ>Q†Áx �„“(® ~ 9Å5QþK�¸ÓÓÈÓ&)±¶‘9jÜa¥«`¾ê‹A8¤Ì×– ”©¿ƒÕ"“à†;bR3¸ “D©�W væÇ)ãϳS›Î£Ž�ÚÊ̲A}ÏÐꂇTÖ‹¾DcXHwüWE>Èà‘'•:Ð�•ÈœÄqqoie4>#�÷ -&}ì#}F�í5pÅã�±ã³*"•(taà¡ÂàÅ“"Ñ)®BÜ -·,AEexj¥ŸòÚ†›ûu®R�H×n_¶n¶(ö¶Îâg'v9HÃ^%Ü!?¾"XÎ@µÛÚ6×›R÷…­‰¯ÌÎyÔÆá=ÀÏ‚ö¯–8/Ö3VõMæÂ»8¿±ÿu!ð™rP@ÄÔ¯ ›“øqSzá~åjwñ¤xTèv¨TÚ.'ÿî†>ÐäÒš?Î`XºùÊT÷:™—ýÌ Aã?”1²\@ðd±Fâ|ɶÆD½‹°6õ Xõœ“4„,ˆðÁMÝR¿#÷°Œ¥&ìeõ¾­E„›ŸväÊýS²š+vWÈãsJÿËžýxñ¢Ìœã{ö[·>¦pQ… tÿ³òŽ)®Ì ¤Ç`ãmnX±^xõÚ-Ç®“©=®æ�´|�t¢Àr…βþ‰¹!ɰvÈ ^T¿ ßN‘k1½9¥#œÞiÔ[@ÝöSÉ‘’è&ÀÏvš¶¦_Ö.¯oþUœ�æ÷ÙÕt÷xLÚ½êø‰H/ ‚Ïm…Òfè¿ÃÉ‹.y Æ8Ô÷KüQE¶p:•7'§Nn¾„ì 8lh˯îo=›}¯¾•9P}Ví{sÔèÿŽ�ïnsÀXiVÓ”íEI€íH=ÒƒõsºK—Î{ÍÁ»ØÒcyO€g›¡P˜û‘–õ‰¿ÉÅþµ\3yy8#;çtº2‡ÿê[mš ©í‡ÿ‰y0˜ÚäQv{DŸ×®ú3@ä ã­h½lXÂqKž!®!õÐÖ¹ú§çÚ‡ŸîÀø–�%5Pú]×|¹õ´††#i2‰öíÍý Eäùì›êLÿî­ 7X¥¢)E»[Ýá[Z$ѾƺÅ–½¿îKšW¤¥ÒÜíešY#ñÙ,‰í�Þ„ì.eÀÒ<Š[èÍ؆,�I#ŒôÒ·5´BÚ ¢6Ìå)¥ÙùMP™12]ž Bäã'‘i"’-,¹XQ3Á™€Ø_@øå©ÆY5ÎŒDd�m P Uëe*zï =ý…,òc‡-¿gCó½6a‘¢1ucô°,a$õÖ×zܤ æV‚òÀRå “”$}ôÇÅ~ï¸9EZç1°H.1.–j¸¢î¿Ÿ{—N]aL·.7 ¦¯€DQ‰l¨°Ùñ‘±89Ågg˜­vDm˜ê^żäžïðDUV‰.’‹ „OX“EV½ñúůſ>qáz¯™Q}(¯#¸MoNªþ‚,–-ç~bûc–97þƒÛ W_ýÚ 'sžNYO j]feÈu´Ê6ó݃3¬¥Nâ‘+1g¸`äjÄ;Vn6ý²pf_OBdkàžpìuÕqž\HM…k�ûÇbµY2}¶PÏe'¼ÒqCG¡[J�ì7‰P~Oëê ’k¬™‘Õ3“/—A ]%†°h@ ozWÇlýÒ0—u¹rî[ÿ˜KŸ}–ún²gþÌ@)E¢ …/ï׿•A ãì�š¦›ŸÝéFz ‹ìӓ͸B‰@[Ë %Û×á!Ê~nÂ8o¦®H#7±=ªðG Ÿö¿qÍÐóв`Kaÿ„íHÃPXÙóú{ Œ¯Þz“ð|\+Èç|+Nn{W´*ã›Òý2†usá1\$«J÷‰µ®E3Õÿ°Û (ÓÁò‰¥Ql µÓâû¦ˆ\õ€V 6°ì¶†RÐ-]ú–SÑM¬´«}.ÒZ+í)BÏw{”û]ò�×¼BôŽ £[Ú~š–’‹©–uÖêk‹§*ë[“Réù½¼ÈƒKñ^ÿWñ.ý�yx^èS¥`¹ÇXñ T�9 Á‰}­ ,f%cò¶z¤Cdð°‰/oûXfÍÁgî/òŽæÖLb ãz¹IÑ9z,çik߸m2ÃHßè:ÚÈ™U3±6ê›ÐÔVà-­!S)­Tµþòt —Ãߊq‚üãÎ4zM’î=03mcí(f4E×Ù9¨˜Ji�#çØ$Ö€²‡.¼¶½î—f¹OÛša—¿ÇFaöæoËFV¹68qc•ò:u[P¯_«eÒžfàëf›ÛÖ»�$;R¾íŸÄ=§Œ‘!M�Æ—íS±(ÙbéLI�çoWÙ>òŸ“î铳ÒÓ¶—S{Iî=C.…ŠÛÍ'ÃÎ?^“Hut†q§¹›Yn—¦´ˆ®1o2²�òz.½ :L�?ÑÁmt‘¦×x) Lìå\èíöó¬�©K•a¿´¬p\!)ó §÷¯P#û…?#™ðÆÎêX58æ»ù޵¸*l¦&#àp(müL‡3–B±AóéV$®ò÷\Ö^›G�4–Øï”y³Þ°"Q’©s¬¯aò—R%VªwPRõ±ûo�ÆuÒÍ‘?ºËèðÔø| ÑjÅÆ ˆßFZ© Uíçíw¦³ÊåÝLeòt—Þ¡£±ß\®]�nfÈ yø*e6úŒ.ü¦”P��èZ Öâ‚ º!ýi…ï«{ï¤Ý†S¶hÚëêØgeyäÎy&úñ —Ê6#ˆýF(;`;S÷íþX·à‡«¶~Nþ>^„Æjß½#䬭VÏ%Þ†„Ød8tLí¥ƒÚF:änœ_ îõÈxrr«åô± „àŽV¡ÿ—;œ!ÑÆüHÙ¥©½IÄA�º_\d™êÞYšštˆI˾§ãzÒ!¦%,¼"{–( –ƒÆiðÅůÓïI«»ö�e²¢mnøq¥ŒÉ…w³ËX!qõüm­~"œ.Ã5Ì08¡8’ëA&›k÷y»pÌÝg¸þä¡!O úÆ5Ò/#Fv²Ñ¾»AßaI$¶öùIM$éV]ÆŽÎtõº˜ ¹ˆ\€�^ö*­B§X/e�`{Æh ÎLóê¥5ÎV4híE@òEÁhŒ�2²H1C|ggÍʳÏß® :O­ —B¿ ¸9’Œ0²ïXwTl}Š$4¨é�]¸ô‘“l“ÎôFÝÞ¬½0ÆeSbŽ+¿’í‰<ÑL¸J‘õ^‹!h�òï¡SiûA �fa‚B$?é×ZAt¸# – =š ü¿ÎGú—çTûÔûõU¾‘‘+FèX §L7ÿ»-áãx»µ¿˜Nƒ`¯Á�„6$cöÓ ÁÂBÚõ:—þN’mkCØ=ŽãF/}8âÖã^ÚDðAs¹´®#x_™•C«KT]˜ÖƲÔ¾½møa×á}üo† Vú´âä‚€ +Z*³N÷·G�°.™ IÊ›êáS \†Ä?ΤRý}-Jzã¡ÖbÍ­wêµØµ„ �…È�™_’ä7¥Æó¥sRáÁÅtÍ­n—’ëT;×ñŒl CŽS÷Q’ë¥Õ>T¡ã‹#A陡¯:^¯hõQ”ŠåÚÆÐÌU fB\ÿœm˜\ÕMrYó^ù`—A‡ô–œEëQˆïZ‹’�ÿ̪™¾Ð8#”Ú:V:ÞgJo’C‚ß0~×}”ætž4$¥ºóÔò°Ái“@b8epÚµÁµíÆE+˜b÷y–ßb´è³ò„«.ÓÐî˜v0ù›™H9û('�%™ÎqÓÁ‰‡N«)†{œ‰b²§?›,-nþ x½k Î?UT…áʰ4vl”¥P{%ªÝ‹vÄuݦBnðC¿jI÷4CLJ§�ì³Xk?fC¯åjpõß¿h×q”«ì�50RHU*‡ÒØÌ-m‹:Á|ã5´;Q•›µß&¼ùì¶PérçÕnŽŒ�L‘Uçò×5ƒ÷©yéšI,OY¡*„áùŽ“)XLÐN5 8ð‡L¨Vá6«³W 9Q R#+ކ K¢ìýäXÜg.náá2Šá»í2KÒØ—ïTõÂÞËÇÝ„¥F0XC‡,S_ç-ÏÔ,ÞÇñäÄÜà–¸‚ ö3"¤m²wr•‰kBÇR‰žÎrêK¦Éå.yú°V:±Ü;â *� 0èk½—V¼!¾“ŽBçýê ÔŠ¬±ˆì¿´Šú祽ò´D…¶ïbhtÄ·+ǵ!dƯ¢t'UNa¤…‘øÃÈÆ³RV»3J†™¢ñqôòï(Öô�<xm%cw†8Òž gVlz/˜ZÀφ“é{ꇕõGï@îv�•“pذU×ML-wmÕ<õ[ü ‰ŽêiAå8\0"k87Êž??—…� Zî"¶B'ì�ry/ Œ¬G’ñ)Ê•Hœj¾d/¦EÞLÑÆÿ4×8éG©Vä^LÁÊr1ÿ›¤äP =£¿g�Œ˜(F݇VÅÙY´ü4Åd•SÐL×ZÄÈÿ@,Ú†qñ­Û÷sUwOéB©Ø�‹ðáiñŽ$B¿ü(Ü»/ÞœSÀÑùdñëŽ3{Y¨¸¶ÛAò¥ ÙS'¦êçX*=eB3;näŒ1 îr§ír™‚ÊGÛ¶šãÍ®TóÄÍ <¼Ìžá—‰šy³sWûCáÜ=ªÝÃIjÐyg!=°Š¤�m¯\2£ö}bD!bë¯}ÂWœš�¢åÐÓÝ=XØj´:×…*hýøA81 #$ÄcØWfš'çF]iJo·âY…ÿ�d çmdÃß B~!=9- •ÔµþÞ yMMfª¿l�p‹ÙÞuÁßá°æ•¹6¹•]«Ùøk²¨6´%{둞: µ·Å³ë₍ï�û`眺!T̺p=�ygxæ(q–˜®ÈZn¼@Š�E¾ûö½aœe¯c6ho†Uè�Å[óuø"Ðï¤}†aÌä�“ÐÉ>:óˆŽ)ß»^]Q¬˜#õy«‰Câ«9åÜÅÎÞÑÅ…ÿG¹DZjœ³í&⥎Aà=ä²½um©q>©jJF¨’!ÙÍÀZ »{Ê^Š©óf!— o:Kç\tÚJ8™X@ —úÎj Ü4«º;07:MóÑ!©çñ3Vï‚€dܱ MÝppËTýµ]÷?l��órˆÔÔV/b „Ö†68¨º.'“[±$ƒ<בiﮂ¶æŽˆ¿4 Í®§ðú€1Ü�ñ.†úôÂ~pç”d>?ØÕ¾æw‰8­±P¹Lçbð\8Q·Ì²mï�f\ ƒe+‰õ½Í® ù?Êìªd)dœ“ÉóŽ�¥µ„�…®W™®´ÑIr$YB8v�@Ø 06�Šf%¸.ý·�Ê+1_Ê£€Ìî^Ѥà <•ºîp[GépÏŒwÌ ‚ìÙ´EâÔq6ÛªƒñË´×›ý�_ƒ-/¼‰kç qNúãKŽñLDu÷ïá’ c_DM!ÌâçwsV·¨¹ -ðUÓ÷ãØŸA¯�Š´¼q®g@Ukwíìp~SE9½tݲduÍ�tÿ}*Á&ïYe�zÂîÛSÙñEóÝâ=|çÁ Ʀ ;ïÐ<_�oâLÜ�òÔ|’'Y÷ûÈá=‡2¶y¢nï²Ì}VœúRìtOæ¼ þ•A0gÎ:KÉ{‡ìµÂ]è­I‰}/àÀjóÒ�ah•_t ®I$5‘uÌ&.µÒq¤2ÍÎ^¿w…dMMOè1-)zàuñÃX<Û]ÖIâ ŽÈ" Ý,ˆ/g® €ã|õ¯˜>éŸu¦¶ËÀ9ÃVÿ�ûžÉÒ/ò5k€ì-!“[Äø&þñŒ FÖ Ö{ëñq±ØõwhŽ¥ æéyõ3²]—æäéˆÛÛP\5NDùìÙžožcAÈSéâVm>[þâ}kE:Ž"üºÍTÆ ?WŸ î'aï3QíjŠuØxgÇúnrj–èMQyµäçŸÏ�høV´W†–&ÞÿÛEÙ)ó–È«<ªýLÓmÿѵJEöíÄDâ|ødæCj¹žßA§+äˆ׉Ôwˆ,Ý rcÆýMÜ­«M“Ïפ�kFKg˜ÓÇ ü¡ÇZcxé ìÊ)lQYŽ*Ru¹tO’2¢¼^½òµW@ýäÞ‚½ƒÄÐ`þÜÂT�¯šÜ† fCpK:©Þl)Ü9Øc––Mž¸¦ß®&)n,•ì‹Nñ%ù»ß4�ç{Ä?3�Ð^@>èÈJ„.òE|ƒ 0¡×\�ì§=e÷7üØsÉZ$ 5Þ«w? \."<$Ó)´�ßpäRwèƒÌß6Î;nì\+@°ÃiÍõ”ë–Rxã7Öî.V€~傦Bmk4ñ@áé‚%?-f$1¿²ÍFbñçšã•²ßPïeCS r:ýJ(üqÀf‹µ9âç˜äˆ¶L iáØÕÁNS(†î)»%w–yûyðS(Ô$("­�¤-­£H2Á‹²f>šËÙVïà$xbƒ‹žsÆhÃ%uÎIíòm+'ðNÝç�d럈?¿põË—8}ÖÖÊàpÝb�è�î§‘™ßè¬�à̈ŠPÄ«¯(KL.Íg ¼kH¼a+Œxé‚3ü1˜›+éOéçÌ…ar±7& ëÁvõdVóùOÉËê6!ï3ÞB4ÿø,F|sÄ·¡ž¦ë¿õw@*B`Ð_]æq>ù/ �èÃñ�½ø�×Ô"êÎÇNiK&”…=.ÿh¾À-JÓìæÎ;RvÓõ¨„À;YD¯ŸðÂpâšôT>JmÑØ„§3a¿ÕS ¬J+`Õ=*ãŒ1o05ÖY¼ò1¨k¯2eîÉÒÚÃ:ÅŽò5IrÝ �å¬WÚ1Ë1(£ X=~É`ä5ø;B,ƒd—´5ŠB KZOù>üS.�TÝ Š é%*¸ŒźþíoOú4yJ˜Ô8"B‘¶`G YSôâ#Ÿ‰ U¨I• 1ú÷nùäîy)~Nj7��÷•ZÜg¹\|¢¢EÐ «ÿ«0‚ŽínSîÅ�À¼“UúP Rf=²ÎÒòUE¹!¿_’šïÛ?~ åŽ+æΰÔ[£!W;þ#�„µ‘ú%‚tqšeŠ*ÚÅö»˜ÊŽLð û‹òY9WTd Ê+¿vsÓ~Vò!@œº’š�Ý ;éWÉïl�ÑÚUéf€æ6€ÒG¾�´y ²ü–¥%rŽŠLb@çå-���,ßÚy Á¥Ý MxR ä¼�o^‹ÉüdçN¬Ÿôf¤ÏóÄåmà% Û1÷[òKÇ;‹.žúBºÅ,ý�¢á:þ£þ^§ÁÌ&µ> ê/!†3|Ö«SÞ—yTßF?øË0E22¢>¤jQu?ìžx€©’ûî~$[Ó«™8ô¯ù{Üw!?I‰’a ×)!ö@à°½È@¶ jTz\žù+þU¼•øÐêêÆüß¼–T½Œ‘£ºBŒ+.ú€Ý%Û'±Zú oMO™œ8b(ºÔßg.ÙØE·�ácGZÒËêŸB—æ¾Wx‚»5õÔ0¤'œç##9]!@&˜Ìó�Ý¢FýL†FŠÐ*ß•Âa¤6˜ï`­£ 1\j¶Œ©ûܦ#ÂôÊÁ«ÌÀ5~µZ œ¬;s–í¹ØŸ¯o9­5 :!Ï$½—¡`môŽJºÒ¨ÑC+œþH;q !LO‚ñ�ªá’b�5­O~ 6D„o§õÉòÑkCZå¹@ȶD›©t†xÅø Ûõ˜¿4‡ï¬Ž<œŒU§9ë—žægù²Ÿ•ë–zÛ"rU¯ BœŒ‡,¿|¼?;Éùñî¾²ñ0sê�@aŠ€Ë³�éYòó:‰’@5¦1ñq±0ÆYDãc:âPoBê.Õ­²WZ²ÍDL÷·ÞÜ ÅìZ­°ezž> \_¼7tm–îÓë9&¢DütÉð—Ü•hI >kæ…F€‡þÒLöÑqWPBX`á#¦´«ÚæAßùþƒ#ÎÓXn³$u1�Y ÀuÃ|þE)èx†H¿õ.®-¿\t¿<7¶dÆ®(ìTü¾%ž(Í‚%Çê–¨«¸™Ç¨-’7ï±=ªaß’Ö±ü@†?À‘ÈT¡}ý‰öó·p ÷§àp(¶�RW‚»\ŸT@² �ž½îâ²;)BhôR9ïþ÷ïß®�ã«´ßì?}_™‰l¿ &°Y–ˆèê½odŠ‘ô*ƒïðÊ¿d�D«´âí€�Ì ³ûª]›õëha >ôyTMp´2‹¸e q¬±�8/ߟjÈ ÚǫɿÀÏ k³ Y® ¾ m’èº].Ê}ûß`æ4Ê�1Sy˜;€à,ɯt r!Mƒõ1Á�:°/i)¸X£ŽŸçÌa‘Xö–ø 4ðˆRš(Œ”ŽÕÕxºäIfQ3så/ŒÀ†Ñöž5ÒÕÃ',ö÷,½Ç²ªu[rwÝþ ÖÏn i á‰Tç†Ó9�XÏs§³Šè \·Ø =ºœôî˜1 "¸coäÅ/ê¡ã……¶“ ƒéžk?'-ÍHWªk …ukÈ1 0f›-Ý�Д˜¬5²gñéãªøÖc˜» q�;ˆZÀî5\ÂÓY5*÷[àØx–Àñ¯ß R»Y b¢úÄ_(%�…×L™ëa h²§5(·yÓn>�‘›éDŠ-¤Á»ˆ/HòÒ{uäef�/TCIÇ·R+FlÁ±øÄ» ÷UãÚ8ïúfBûa¦Þ<š’9 ¡ŒUvnɆŒ`g K³1–ŠN�Dß·¬ ÇL§? :ÚYS3oÜ 2b~ôg ó(š/¨y'æ”´¸ç@I%�JšZÐö3 lülŠY±=± ^!ua¯¼eAöè(†Ÿ34þܵÿÏSºaþ^ÀrŠÑrmgG`+n]8Ôī¿‹ù¨ˆ_Ã`ñ øHpn]á¼.2Dìò{µ¨ðDáÁí¶|’�>– ÇÓö~­mW�ÌÚxI�#¯g—zžÈ;‡*Õ~¶ïÅ ¦ëÞzi�9§6@û<û²ÂÔÆºI&o /Þ…t¯Ô,ˆ=?«v•s»Ü¥ÒÎ @™R)e~3ÛÑë�ûcêhiI�—·Ë�¸¥9«¾9Ü|F{ÿC2V1��°÷ÞSYêôše�@µ 9_,˜ í ñ9%¶ó£ùÂúÃbŸ…#æ2ä`O\úÈf+e^ìϦ�ê«_~úÆaÕgÛÖ;¸i † ï‘:§3mmØÁÚþ„ Ÿ{w©!dP-ÆæSêg£0ºÂÁ[Ü{efOŠ ˆ–s@¶ôÏÑ_!”um²hñM}õ!�å‹ë+Ò&�‚6YH C‹DµÕ{_ÅÅЧ0T7m`)C/4 Õ/a‡ •uâ©}XÛãcF ‰›Çš“SéºÄGÔÀbý�zðó¹EísÚ‚X¥çs ÚÿÙ‘žÿ:°÷dþ%ÎN—fÉóá ôVÍó ç掶¤CXÏIýóê +{A:3�Î×\4ñ&0]-k•ÈM$8£Äúâþ…éã§�jë]at ¸ÿ±/æ‰h& Ì(ÞŒj MΜûÊ+˜«ó½ãϹ¡ÇÉ8,'ÂC²Y0‚ùnù­eCÄ«®"¡Å«B¨û1øêåŒù�N>R.pñ1ü§)L­©Ó…WRW‡ÛZû°Ålÿç„£ª–ÝŒµé¤ &Ì‘ÔÜ+UáÌ&Ú«u´ýÝÖ~XªÏ"cÁ"l@u¸Ñ0¾ùòÈý×Ó'Ø ‚S¢XŠÀãZ¨\%téÔrŠ‹n¤¥5Ìç*¨\QzáÆ=@%â|¿øÑû.TÂO"µØ¸dGúE"sXYà!¾äx�­}M§ÖÎAdL¹Öï�„\•«üóͽlö·¦²ñeQMY¼’ãÆÓÑêìÎâ�Ðò^§ŸºŠÚð­)è›òê)—*ñæö} q ç‡ 0‹ãe¨ÇpwvšÓ æ¥I¯¼ØW‡ô,2_FüZl�à:Ô%,,�Ü!º9¾…yÓ”)[�~CZD,ÚëM“ß|NÀù_¨ÃJ[‘1hëäÔn¥Å-ª^÷rsÌ«§ymLBÁ÷Py‡…ÿk#”ÑQ{óxÅôgü[ ØH¬­a¼ ù¯¤w¢wGÕŸù^;Œ<ó?ó¨<¡Ý!ÆbNmÖð<^Ë´™É ýPÖË�Ò6»y^‹ù¡Ð†¤¿•;Ñ„@Š¢¤vf+]û²2{æ¡ÜVFªÚó¨e¦&™k1ÕVîj6¼_£™f½×L2bJ¯SÌÙmý�«3QIÜ]¹»ÜÖæ_Ÿ£‡ð8øŸñ…ÿ· xnÞ@ÿAÿGŒ]�ÎÀç Ìsž€~Ã�¯\RqÑ¥úÆü€s°yFüŒs°À$‡;üäs°ÀAã þ<9Ø?AÖí³©T…€Ý€Œ]nÞ@™ú¾òû‡;Ö0�ÎÆìÿ€9Fü1t€Ò0�ÎÀé¹O@þc­Ï@^vTFhR5•Oø LÉÜÉÿ('ü4¥»øR›KeußãÉÊ ÿU¿�ø|ˆæR´R�¨.²ØŠ„! DRJ…B¡R•)½É!ê‘×'&J(‚ZÄ ‰@¤,¨T3”¤�¸�™DV*ð×ù3’AĨŠS'l‘*SÀÕ�…["(+�‚9¨BPP%1"!A›þNw’#�)‰"I R™.P!ÁS"*”r �I²±(BSÀ ‡À $Çü�òêD«…)ºÀ JSÀ S]r#¿àr'·ü¶xäBSÀïøˆõþ þ ýr!C¿àÓcþÐT;“#À¦Oø ÌÒoø}û’Mÿá‘Ô&wðÒŠ?à'üxåv§ü¾ÿ‚‘pbeetbox-beets-00724b7/test/rsrc/empty.wv0000664000175000017500000003105015253035401017516 0ustar pieterpieterwvpk 2D¬D¬¼â¶é!RIFF¬XWAVEfmt D¬ˆXdataˆXBWWGVHCÏßïë –eŠÙÀt@¥¬ ‘ɦfÞ1/°¤% ˜k^‹�™«\Á¥”Eãž7h… <–°ÍeÀD*ƒb=p™bE‘ÎÁ¨¸‰±I(€šxÀ‰À(N%ªT£´°TéæÂé6™r¬‰�Sˆ(Ð`xtÔMI)gÙxL¨Up M ”¾¡hŒ˜`pH /Bš×`0â@ 7K6ePÉ=J8(p²Íü†Bd h s�r`ÁMybáhÎn2÷T £�ð6Á�:ªû�rÇ`…ŠÆŽ’Ñ%"39>JL9Æ uì)<ÚL;=&B8GAáøkÙFhF”›;n@+A¬P`ÃH›AŠFÖ$FlŠf¾÷À} f©S›áDœ4/°Q¬RÀ+žÓÒ"(â°¤ � WéÄÜ÷´),²0±µÐMP„Þ·$Ë„ÇÄÁqŽÒ�Fàd-À×?©µfs�h"¤ aXjªŒ`²<½†Ã•°9Œy1xŽÁ‡êrVœu°<Õ.™î¤¢Ü>¢q±Ä-8np#á8ŒÜ¹âC#yT†1=Æ �ÔÚ@ÈÅNòc$ŵ’Álrc U¢«‰ $¸O–JªFQ ó&³Qd™ˆŽ4/ z @jQ g(l ÆÖ4ƒ3ùJ�~ñfИŒ1¦Š%€˜¤ÃhfTÔàôN¸àc“8HàLaD R+‡9QˆT~„ºDÃŒ2:Q›IPvjŽñÁë atÚX�Ö!HªFÜ °†ÃË)Ì15ÕqK P |–MáØI=�ŠÁJ`�Õ±êíÃ+D™™X­ƒÐƒC=�2™7TŽƒJ3)‹cðáDÍ,É"¤ÇñQ'#z¸PúDü—‰6ø RYÎ;ÐŽB¨¤4Ž']'�T ¬À‚D3@ˆ…ÖœX J|påS ‰ š�‹Db2Æñ|! xg¾pÈæš½=¢^jc'ɸeÜ`ä&À©Ð DP+ÔÈàˆÆŽñXÈÜ% ™jªY–ôjX†ì�j‘l¡:dÙ’Û[µ>4& Àá>Ä� ĉÒNЃøáhŒå¥€,d N¢³q<^@b…>Ög¾ÁÓŠQÏ:X-è`“Fø¡AØ\�¸~¢µfs� µI”Å’Å óˆNŠãÊñ¢'v‚nBà„ž¹ÃøP.”ãA9؇2Êic"Y è�Œ4FXžªa!�ŒP§"øøcb¢ã(ð’¾A6fȈùÍÈÏ@q*.¨`¯[k�j®Ò ³€‘�c¨YÊñ+ìx„j‚áX‰¾B$ìâ\R+ÈD× R‡€fÑD6ØT³,é"l,ÀRÂ’éŽW€PxS="=i t 7©åT3A˜—0`d„ÜÃ�ÄQ0$Ž2îH;-îÁ�b5Ñ`´ ÈG˜N4�ÁÓCO†P–°¬ì†M! ¤ YpJ…ƒ”ŒD  m€Ø¼,x ´1.Â0 MÆÈÃÊ•DÔœ€´Ñz")6÷Á± P,®hôÀFÕ\Ò�š–t?Š‹F¦‘6²ŽxAkF—X˜äjM P#Þå¨X`dI4Œ=�ø(£ 9» 0óå·�Xš€—tì`¶h AÀÌÙØ#G€¤ÖO†Ö 4šÃó% ÁNvº¨%„N ZD3”¡-97 .!í¢ÎäÄ÷iA”‘ŒÔ X‰à;#QÀ&܄쓭:LtnT‹ àhé¤mP¬„IÁ(ÍK Ђ¤Å-Z¶GO‚d‚7ŒP@g�Y=˜ž (‘¹‚p%l!HLJ|ÂʤƒfédÎÃA�8>@k0'-?c¬ƒÍ‘ Ž‹, f Î¥“ „d³Ã’jØ)2q ¡‘…ej0§ÈhAPë©®=a–Œ2`©…Pò\wç�ñP0Uʼ¡P!à˜gÊòÀ± €§¶X~œ˜µ¨¹äl8ºH,f³ü:‹¬àL;ÆÔ¹$vÂCHª@x?V  Sí0û#"³:X3¼� ó’àˆVŸàÆCEÁÀ4:bqL$`<¦¦„?L5/•ieââ8{`hòbXs¤á`€©…+CÀ”T€Ú2¿ÆR(™º¦šj”ƒÇ*™x„yXòŽ­ #Mb‹p8‘‚E5Àcº¨ã@#+�Q�RèHH>º@áÒ@4ƒ¼£ޤ“ÅÙQ�%óRH®°ôpS�*-¦ñ—h ØÀHä Ï5Ê6Ø9; LT>•$FŽ5hYdaÀ”â2CyìÇGÉ0‘A®A>A#•©õÁ:`@=c“.Tx™1 ;dX%‘ >�âÆFEæN€–²@H‰ÈÌ�Á™ØÁ­Á `æÊÜà@òX% ³ÃX€‹òŒ©b €Xê ÙÜ™š AfS(ë1ú…‘ÙŒ  £™€g�fò…YDËx aP¤J4@"h„B¹ ó2Ã/ È‰ŠŒá�æÊ| ­� ŽÓÈ Ç†m*ˆñ46Í—ªÇžðÍ åx‘¡ Ô´�Gp#áx/Ôbã[€ 4¸@@ -æ$°TF9n€‰g²˜Ö x�XöêŒ�¡Âš¹Z³ Ël a#©*èhêT¨yAÙ#ŠqÁÓYO°ŽpHdJÓNbÁZ‚zºñŒiʧe“Ê«ÇÐ¥2Ö™„£`Ò×|Ò•%‚I°ˆ‰™'(‡ ˜F†*’ÊTó�Ö¬ŽòHƒ+ZÁA” &À˜ K^ n( I†�ŒkŒ`ƒèÐ8°ÜÀÈ#‰tˆ2ÇÂ%ãùaÞit�¹ˆA’AAU¨fýÆe"„±8Ôä²NT² ‹FÑc=•ÊÛpJCƒÊ°¢‘Âø .A<Æ&&ŽÆÌÀ£�Y:ÇM‘‘€‰Àžõ1yfK,(�$£Ê á<àÕÀ˜ kʔ߄‰Zk$AÍ’?AÌK@A˜ÇÑ3%f6” HS£µ)ÇkÀ °ä g;Dµ{”‡ÄÁåÐ8Ò@$p ÉÑ�$ £VÜMÀ<Õ-" S‰; G4M¤g=AsMzMæEe.¡� 0zˆbeÔi¬;óöá¡dî� ÐD °Åå´L¸à0F X9• ýR£Âw±‡¨â—) Ù1& ØyˆØWr”ešmŒ6³MÔ,¤ç¾È´ΡW‰Å²§²rÀLd“zê¥ã�²y1B6o' Ê‹—޳Q–À*KÐ"04EÄ´1qù¸¡ÛAš@�õA›í0ˆ¦î©†ì®K`%(·5'‡›ž¢\ÓåPgý›˜±&´™’€R@3 N•Âu4Fáøø¨xA ‘kFð(;šã×ðĘKJÔÀ4£Ž“GÒ8 DHŒ�Ó ccͰ ±2ÁÂú¥Ábœ…=];p™PÓepj@� ˆRâÈóH)Lö Éu¦«sɼÄhB6°0fŒI)VæÞ2HÉL’`�p| £%3„JÁXTƒ€òÕá×x´£Ä¼ Ú”3É Ù@ôÃ"GȤ j„6M ¡(^kFá1yf�gà´L´d:*ã%¨Ý€=XÄòÖMAæÆ‡ó …l¨Š*E ™J�ìØÀ@qD¦»á†#PZ#ÊÆDGXœi €/Í7šKÉ�–�tAÑ b�ÚS@t\P9˜n ѡ°k1V(Tr18��°�DŽt”ƒ�%€‘i2E&¬Çü†(œˆ†s±Ï°Ê­€>â–à…‘4¹F “DÍ/ÞûP ´Çä±â̵#EX2yÌ•Dd”%3L øOÍÑx… {Äp Xçø‹PAj¶æè"Ô©‚ŽKN4uª @X6Å'Rp ”T„é�˜ Z€XŠàÜ  K`‡ŠF&­D†!¼CI‰ ÖŒGt„F6¡ÀuªÃ9À@2›ƒ�„FرÅ@b¸ÆdA&¸Nu�”$c1Ù˜S„,W ªsâÕ¡�r7@²°ÂGÃp4�ø€<€‰šÌMˆ5E`\Xd€Ø£$å1¸ÃD­5’ p¼ˆƒ,Oìá:6☡'†‡”*/Š"Ì3ó�€P¡^´%Èe"‹­h"uC‰iÍ ež’ÖF=ÆÊ¸ÄH¤ã!„KÈ_²uH$Í¥ÔZ 3ø0HøqZœ6Š�”Iü  \�'V rePN¥†fã%$R‚ñ-s‡p�±ž˜8„»`ÎÐ=¢©0_4¢h¤ˆcýETØ‹ÌAŒ¹´�ÚP™_À€š/1£Á- D5¥–Ž€™2/¡ÙÐR@ç!àG'ÄxâbÍ�<Ë%È1–Á8l8pzp€ Ì*Ñ�³Œ1q‘PŽ• Å 9Ö¡A¤Ê•¹‚Dƒ(P¼¾ A �H¢W„ã"Š%"GÄÙ‰xi‰ÇhûdN•�õã¯?T@³ld A›Êšå\‘a 0i�4ѱ.B>Ëbî3sx8ÃI¿ 8\ “wÀ;Š !åF «‰—:x�SSJjñÕÜO…”!È�2îPy0„WãÑX $Ó@†¯7RjèŸ;À|á#e®¢T¬²ú@ƒ‰j*/€‰�aºaáD l²ÇºÐ8ZÆÚ5SYx„x4ŒˆRI—ÉlÁâ"kƒFhÍ×"ÙDC©R{4‘ìC±€‰Rdxf=R"ÆTÒ f �2†ãCmˆp›daa#¥£‹ˆ£qL6àå‹5z”AR 09Á­Às‚} d£©dbAÌWæÒ�ãín¢¬–ŒÊ3±bGÂ1/tA�q4ŽhŠä;#º§rÑk.9æ.(€´ÐpÐXØbëá7Õ¸³k¬9šñÑ:‚ŽX|r¸tÄ¡Âü@¬`Á¡K€Ñ®q–„ „+¦{Â%ðrŒC–%Çî\r e‚aF²Ã(K' K ‹=–D#§B÷è-Å“�’𢂦À½¢ÊB.Êq¡Hd9ä�Œ.ßÈŽÊ…0pfa²!‡{XTt0¡k!BJî�näW6¥• W€ÙHÔNâ °�IAËT‚F&Ë¡Â4ó‹ò©�¤©B´Ó T¬ì¤6]iq#l ²„›–HO„@¢Ñ‡QFËcwð¨2—ÌÙø’H@-Ñ:Šð a#B‹ì¤R¾#@ÕàÉ�«C…Ögâbâhbä,æ¤`“aaC¹*b \B«(n@S a2Rh&—FÌ’C2eÞ€°P¨ðx*”%�ýcXd`F“…– àoRzͤOt(GcPÛ7HDÈžÐèý„¼OLÖñÒʈŽb(D kIâ �D…—Sb2ÉÀFdÎC/RæH<BÁD8`Œ›êÃ5@§ÅG`€ïi™jªã�vëŒKL>Ô– Ãr°Á|Á’n06"¸“ ”ã5 Qþ%PêaØSO ”aYb‰ÍÕ!yžn„,\j¥Åäd�«K°ƒ!AQJÓ37c-T)'–ƒÄS(Œ …ds¦L]³Äq4Ê€÷1t45²z€ŠÎ|àºp´Á5/ UBcŒ•ÁB;@雀U$…»àˆÒÌ/!TéŽü Sð—â!TâfÄ¢¦{p�tN@Gb²�eÂFaއ€ÇY‚ö0™ºN=©z°2Ê`Ù§0Iñ $£éø’H…£%žQÃ_ |˜+àPÖtM5å¸Aäè�7âã—"e(àP"æ¦tìΕ¹ fh˜[€c-�0+›)P,ãTÎV8\:2,U`�}@¢™¦æN¼ ‘Jad"TÓžtC Ì×€€UëO\€€3‘‡Ð‰2ó°�´ÆÅ'8Ó:Š ôa£!‡%¿,ƒ —^(±t<ÃPy8‡$•$° (©ÆÐPXRsêØ‘[D^¥‚1ƒ%FT6ÒF˜f¨.IA‹¹a`F<×\j´Ì[#ž�&æ“<}0‚ b¢˜E²À( ±žõ°f)OuÄGž*¶îó¬añ ¢c. (¿(˜µä ñ‘¹Y&h‘‡R 3_=Çí§ð).>Ú@«hÐ�›/qŽ…9Å�Èà´‚úÆkw`¦�qX`Á’á>ŒO y@T$Å¡I‰#…qfád(è¡x�qɉ€LÄ€‘–L´6£‡¥€ S{„‚Æš°Bæ©Á¼8ÎÑŒ)`)0RÌ­AÒN5K5µCÍ5Õ©Ò© €™jÈœ¯%‚:õAÖ:âB8$Â%\’8„J*IM‘&Ч%C¼¥í¨ž¼˜ ühscQáò#\B)êƒ4Z|Iò�–˜` Ðé† ­è`¨9’ËiPé0•bL$Á)RÙpBL‰º<ÌÃHá2zÄc‘€M&3úàuÐ… u¬1:.<ЂÐt zQ—åCj²>À7Yzæ$ ‘a€‰¤¨B;ǃ„8àì!™hª©)Ë ÈÆ7ÄŠ% Kf?È\ÃÅêAÙÂϵnÁÔ,7X È\MÙ =o“¥µº ÙIK€•ÁÚzE¥q ³9H…ŠEàH¡æ P^”Έ¦È ™©ž˜šh,¬’ÃÀžú �Ù–ñ0ÚHyêb¢R!5 ïq ïÙhâ‚4ÐaÅ\9AƒÀÒV€MY‡C9¨H–Ø0nŠ!0YÈ z°´4ÈI3*�˜V , b¬8þ�…DÐ#�¡”RH' ¦4µà†<9r<Æ©ÁM!‡ß&IX8""3�1S 7W'‡d²OGÐ ¯ÂgÇ﵈ª10ÖÄQ¡Ëô‰b„ÂN5¥c•�‰ê¨ ŽnÂ"&�逥”ŽIeæ-Ñ5_˜¦Ñ“˜Ï%jºgª<ŽYÂdl@gáç”IOkÁB±gÌPÁ aQvÚÍTr $ÁËKplFcÌ2¸4Ò™bs±½0ѨÒY “g @R©‘Þ�”ì#Jsªƒ&f7=\Øè¤o¦S{ E¦@@sòœTaadP”�;.×°Å`  ‘!ãÑ@‰gh�E%"6š6@šG‚p@ö`–‘82y E•Ìœ'Ö–¡” Hf¶a â‘BcSdÞ#Å'[ª%%nP'€h¼cºX Õ½20–4À¨F#IÀQ¬$š z(ªØ�Ånˆ&p¸.PÃK aÑÃ�],Æ¢As6ÿ(r2Zh§� t*Ì¥ˆ™^Ã`Fž|)¥%1¸U™À=4 ;8dx¬¡ÜZ3‹EX<|RaáEÑ�RŽ/IÙeIá°ùå«a,¥”͈a(‰×�HÚÙPÆ=Ô­³v8�B¢ÖTŽO² �‰À\(/…/BÆfˆEp,1ðÈ W±È JÕl�¡^ŠïŽBL% A£¥00üqÀÎÕp)€N}3‡sC�kÂÊ@‚ ¼Æ°µ ¸60`q‰‡²E=ô|€ X&ì°Ò‘Š[Eø2…›ÓÁ#ÃFuÌIu$.¥^,]<5šK  Qbã�ð—uxM$Ý~�)ÏFÃLÑ&ù…•Dùi_ib0Ó; –0¨Sti(ÚÙ€J\‹®²”É™¾uÀ¢‘)…�#A¤�PHdbÔ´{ 6lÂK¦³ã3RI…;G Xc¤E ¾K*§d°n¦èȨ�7T*ã‚Æ%�¬ÅkŒ>' åÅF¦£öA @¢ÁÚ(ùI· ìŠàyGùeD‰ �©ŽFIž®€¼7˜ÈoI\ƉͽŠÙ( Î;4Ð+BñEX0yàFsÅ1RPaéPjºYplžh,7‡æè$Ä#ˆ¶åSÂïP…| {\u†¶Pä6¥‰ÖPa40óµã ˆ(ËB$ˆ:½9¼ÎÁI4‰Pƒå°4�„yahâ€ô`ZÀÔúð2ÒÁ¨âQÜ�ø½Æ¸²‘Š (dOQ…tÍ•DeC>�éH*5Ú0ž´Æ P±ÕBƒ;@S8l^–à „£€péêx²„ÖJ.±Ð"¸ÇGQŠÍ›"&ƒgdÒ¼›In0ÚE‘èE×Â/lÂ#,0â¥aZì‡A ™9� Xó¬Ii;ˆô—ˆÇ` ÄàÐ… a^àÕ „æ»1Îè3Ó@-�˜2ÙQfy‘u(gÐ02l¡Ͱ|�f´Ì,M¦i4®8;ŽH4ŠÃ`&ÆÔñ¤DÜÉå €X·`"¼ÁÍ©§`ì4¤è¬·"ê‡/» ¢èñ= ‚Ž8à ·˜m S+3k")KØseJ�WåÑ�1AYd&� :˜©v Jij*If)§:�@ò„K5‰‚rœeÙˆ Zƒì!&J“SÍ'`6Ö+À „‚°6Øt�ùŠBïÓ÷ ñ\¨™`ÌZe‰tZŽ�Gˆ/M�*B•«Ã=¸ŠŽJ‚Ä`ÔÀRH š‰Æ¸‰9†rõ@Ááö„üXa‘ŽyÌ<¢’f~˜ß Ïh;A‰­V µh¨-Ÿ¡<¨Aêð…##Hœ(Ö03€§Ó’ZFŒý -Hiwè²óQö‰nZC»cÍSŠ,AŒíœ7ƒ¾ à¢è N!ò¸~ÔŠãh(s€Ä L²1ŽÑ‘ƒ8sÝi±pVå…@X2¤17/ž—˜Qˤ;e¥Cp ¸”%40Œ6”uAšÁ2gyä�ÅÄì1û, p ÌÑ'6�ð6côŒ/#€ZŸdŠò’,® D£p$�ɲ$"TЬ ô–Í%HÑ'©M˜]b Ç âùãDòA4`1×(âT24H9 ñ‘Ã:Q13(/’‚wú P3žcAp‡" ók™ì ÉÁJnÆ%Ø`\r´WµÖCZá’he¨ákR  Ä‹3Ób¾p>ÆHÖô-éŸÐ‚7¸2}IÊ=M™i\D²uX’ZàpÝ®¡N•±# ´Óœ(·€Kµp$�4ûAF0‘£«ög„ ¼�8®‚Ña[:*äF‘5V±Âw"dF$Rj€¥„�Ȥp#ñób�/<Û3BÄR`Âà€˜Ë&CÂÓ+Ä�ª¼4bÆêB¡Y q®3—ŒÐ2ci@‚MÑiç´ÍDgšÊšÔ~HS!)7—€E8õARJ‡ÑÄh€r¬˜:Ħè”#>ÇšBµW&}è0tàŽ‹>Å ,—–ȳûO€%莴€c(eS$(@­ŽF˜�O²hì %tD41ëƒuÄ¡I‹ÀÎ0¦Fć%,@D&4fÊTæš!Þ�C€¨†$âlîÌ´`Ž5%R¡bTs}æu ªP8ûAõ‰qL˜nžJ�(‡$’y³Ù@˜C§;n˜’j³t±·€ÆÀ� M4@ Δ›ô<Ý …*ÃqY ­h×À\jÂ�hxm= ¼¢'ÎjôÇȈ u±÷àìÒ É`8 Œ¸tlyÞqpÀ¼äXH1ó ‡ÕÑpG T–�…©9Áx©Ø$€(ÀT”à $ÈFÇ”ãkD-Â2Ñ· P»s5Q‚Ó×DsGB4x óâÀxpU8 P¾½ÜCa¦ši‡çÍ!06Úð@ù +‰Ã�ÐÃ@¢Å ø0?ì× ”T#:'·BXÁ58KOëõô&lŽQ+`ެ¨‰ FàX ‰“¡%ê˜îÁûˆƒÉÔV`‰TÉì*R¾‘¬aŽ�¾(R$Ë@6¬À!5ÖæÎ\9N�k pª` ¸È6|FMyˆZ4Ë©Y²ð ‘©Qr¼§‰W3{¨¥�µ&ÀŒ �@öè�†°M…ãdvØÔÌ;©bÝ óÔZL±lN+á6À •h£9@—-óˆ±õ£Ûƒ+�ì·‚D¶Êh€Ü4™<:æjœ¡5 £\I\}T "€Ére.hŒÐh°`3.f#þY&ÅÎ�¤DáTkHL@ Ò0 hNm’¢¸@`gj2P!=XãLCÀrgÆÀ|»d’H =ÄÊ0Щ2«¡Ø€˜– Äcº'uÒa4 @ E£ÌAÄš�Ð=½3à4.Ö‡;㊠O�#20J´§íÇE„&hŽC÷‰;ÑñºÐ-!n Ý#z^u½ P^jf�V€DsHD„ l4(4Õ©&ÄGĉ¨5ÎŽ=- & < § �A㬄EgẌ‚EÃÇQÂ<#-…3H�lc0­�O¦™;j�0/Bi´ÌKzHJŒ&ãh26`'ãðZ™FHÄ3W<(Õ�ce¨Í@ÊÐg^‰†�GÜ<"ÜÄ¡%ÞZQꔇE ;hdà™ˆGƒ,!רŒ1· È9OmŽï„ýHDÔcExΡ]¬4àÀ£!ŸÙ$€”jªL ,­çY0AfM$…Š ¬§Äã4Z�—$ ªÄ¥a#aÀNu�Š (¢‡ÜѦi:Ôy”Œî\ú´r„/E60®‹$4â‹ÀãÔ>¼>£D‚àF`z6%æù R¤Ù�Gs|¨Â]0h”u(”—Z.Íø0“dƤ3R9t¸ &´"y ‰ZƒH&• ¦®£ñÐá‘5§šJE=¸‚YÂK¡`^tt?%yà°8ˆð]Y4È9î «ç†œ>ȱaNð~$ûa¬h ”l”Œ˜ —ˆ€ D†°èYEpÜn"âDA6=X®€Ø9^š™ŽÁ±��v*›²�8Ù † í©€t'5Wg¶8Ńú‰šGÃ\û�¢‚(%öÁÕB­oÌa<Œd�‘ó† /‹ª,5W†â‚€B/Žè�•=úТ 9ÖŒ¬±¾@Qš>Tâ óaPœ•° iƒ1Ò, ÉËsŠ„ɺ (X84ÆCiÚcpò‚•¨$<&…¦+¡\"@±.iÑ8ˆ5‘è�5W§a2 ¢�ƒ[B£ñ0ÐË­Sr ,Oh‘9@•h ',A@≃pN‘£ý´'YMö œ(¡,±^Äã�ð]Ð(@M…—ØÅ(@Z� €ëXiƒ™Báx„‡e*W‚”¡š«3žÝOs"YÈ O¾hž‚E!e8…PÆÆOY0Ñi±`6I@¼#ò53dÐ]SÊ¡R.:“žì?b•fG¸ƒRÚ¹0W¬Ì•pC¡D8¢Ô„¤æJ¸aÐTGsLЂ8ª×\c切¬˜k”hB"),ÒÐ�0Døkb( ©[>¼B¨¦}ðµÝ€ ™ÇØ–óÂq+ð „h€4ÈótK ÁE8\B•DKQx‚š(#€6e "¥KæƒcpæÔi –˜6ô”$¬8žÂÃö�ÇA†Ê 2 ˆSÅÞOÚƒ†Jt=D%Œ‡iMª‰pœF?„�S#%‚B˜_~¢‰&Ù’` ï °Ãʉ²©tØP´CöPo€ÀO` ZóÅg‚dB,HТ{†Ês÷ñª8Gbá(�ðºRD*kx�ŽŽyq°æã+�€¨5ÈÔšc2U†\‘£1,òRd£,ìDaîŽ£Åæ aëP±‚¡UŒ^Á3d‰KÑÔ¸KJ(�¨BäY'ö•8TØØ¬™»rÀÁ*G@‰F  M‡*¼ÇÀÌ•¡ð•¹Àq�<0zò Ñ�a¨l4æ ©²è:ºÄ©2)82NMIžŠ8i°ðsC0*µ`šó`©2nBÑø�5 °ô‚f(c¨pÊÕ�„œð"åÒ´e†×8 {ꃌ[„ÅDДr†Iä¬1j6@êl¡…[†gÂ:ÁÆŠP³¼0WG#‚h<Œ â©!qú‘!Pgé£cÈ*¤äغ¦æ�´˜È0ëHG H$OŒ�7ôd%˜‰Ä#2¥±!´Ø‚­ h᪠—„à5&Ì|6p àÀH5—‚‘’ (Nâ€$ü‚pìÜ ‚è*FBÃÃh%¦�u°L80™LŽ,«Pì¹Rä67CDæ #{´}œ\­fŒUlM`=`A™â0C‘øÐÊARK#�‰�p ò €ìhޏ5ð‰tjñM�‡*Øœy1¤YÆ?@‘�’§X0ÕÏ‘¬¸)M–€\§($‘SM…q‚YE1µ º§Œ!£#-S­ƒE,½2„£i¦Áh¢PqEBR)� ò²h â‚Ê%ƒ0‰ˆ7U‚²©<œƒÇ°§‘C2¤(¥P³ñ4*\:º`é�—eRAšø˜o ’jÆ/¤�²µ .� ÖÌ=¸X˜—M€<ÈšÕHƒX Á±:–K eÆkÂd€ â5ÅGcl —æÐL tÀ†Jô:àYCÑ.¤ã  &iT£1(z¢Œ�«C¨ñžê HËÄ­´$ %€ˆœ7„ðkc—Äj #îT™ x‰“ÝDpLŒ ¥@Ïtbäl^ /0Ç@Õ�ç!�h𨺣‹RÎi“èp ¼0ư*ÀÄúð22€³… ¨iM!¨Q ¯�f•°Æ‘޲HèâHYÀãÉ�Ce¢1 6!™>5ˆE0a“L ÀiA,`¹ �¨’³>0t 7W¦%è€l€*9…*aÁ�ˆä�{�í2lÌ™qöB ¼È¸Ñ,<"Ãre\!°Û/�pQØPÄV˜pØ’Ì!N)Væê”dˆT�.“.AìÁKÂŒ£€dÁq±¥ÁIê8ã ¦ÐTOëðN§~j‰#Œ&ôØ�Nc’Ê$RC–û¡�ã�@I�ÉA Òã7&5WFĉã’aØHcóÄé§êà !Æ+Pœ›J>P,AÏ„¦.U¢J"14¡q3R¬§”R1J‘ ¡9np …9 D l¤Œ<ÂÈO>œ’qVƒˆâ�Ñ… ‡+Á-'´<Ѐv3DH Òt� h²^€fOëjæµRš�y,)UöQ?âg�)À©£DP\L!Á28Q pe `Nêq€&�Dc,b¨Â¡ÔÑ¡TQkèÀR ó"(H8¨2d:b¹b°,‹d h< \Re¦¢Z ºiÖ¾Ähq'°Œ)�i^U°Ø˜¯š—"Ÿ æ‡öQ àÄî\ [‡YN%Ša �[NXc–U f”S%Ô3ª©ÅC×ñì8 h‡¦šÖ�¦jx À&Tƒ‘BÅÎc:\B>eX$‰õ¡kO�ax”ªXÁ‘a`¸ªÂ R”c}†½¦©m(³ Q@4g‘øØ(a=¢‡…�ŒãP î°ÔT覚)ó¦ èƒe€lŒ%Oì$¤èÁÌÎAçctÖ@TcQA<=úN)I~*ƒ¿N:œŠ#(­2lP‹Œá ’›'´ÇX€LÇi G ·†Ä Y¸ ¯1µ3™@¥_$ŸJÀØÈàóh¦ZG@&Bd ¹š8=S"b€`Ø8;¢ÉÌ,ÕÔ5Õ¤ÃaeVG'Äš�,th`Û ApaájÀŽUN…�=zÇ5Ê7¸¥=¥¸“8ÔCC‰�hÙ¦8DnS"Ú<ž(d}¸”©½Ôh?€`ƒ!š øa/„Ðä{'ˆI‚ñ)0°£}Æ�$¬gö…÷XÐ!VPÀ“DžW?Eaþf°ÃĘ&vK,LìN…zP"·!2Rñ�<Ç‹8 †`J±Ê%Må™Õ ò¼L`q޲Lµ ²B@gHÊ3d%ë>p¢l„/C Y^ ¥JB9pL$ÌeAƤÇ$�± ™ƒÅ",zÉ‘M u$‰ Ï�ù ‚ßxL6ð�‚ŽÆ òBj®Br2D­”ÔA�úÑŠÒXJ˜Ì‹*F#/XpDhi¥™¯6©à�¹t„È nZ4C<@J€C‡”¹š¸>Å*TJ×±>؃ÜdGsØV@¶™Öì 4Ecƒ 6û=Z A–Ø óÄ5åæMA�T`”ZÀSå Ž 6ŸPó ý :w‹C!�’Ù×lG^@Êñ~z$4¼^ÁЧtj2e"O¡kÂÇÍAʃnDÚM(…SX^ ÆÂ, -Æ ‰ Zk ø«cû;†e $‡GëT.èæ¡¨  Sh ¾Š‡†Áq‚�FO€ÂHâ,/€hÃ3o ¶ ò:àK#@ki ¤�b� $3�ÈÀÚ™óÒL5õ¤Dü<5Çþ k„'KNÆé ™ 3öàd†ÕT³”±Šœr–¸ÃÁJšÌŽqÚa (%«Ñ¡€-–ÆKò0™ÿbeetbox-beets-00724b7/test/rsrc/empty.opus0000664000175000017500000002006315253035401020052 0ustar pieterpieterOggSte¿/ä\ OpusHeaddD¬OggSte¿/ÏøÈEOpusTags libopus 1.1&ENCODER=opusenc from opus-tools 0.1.2 OggS€»te¿/dYoá3ÿ@š™›——‘™–�•™”“––—“—–—–™•˜š›š™—’”˜™™˜–“–š—“”—•˜——•–øøø™�9Ü>ø-ùèE½BSu53œ¬ù€$/bÊ0•Ó”:ê'X*[|äàRˆ‚ûc»} :£$ÖzØúÕì§sD“÷INÀrF›wå¡óß.!^x*iVñº}´üÞð×]ë{�¯àpT� Ì�ŽØ2ÃâÝ*©À`þKùÑkd1¤œ%Ý£¡è\ý“ŸèˆŠË|±‹]­(hÎÒ®�䨒)4¾‰±«ÀFž•[ =Lj„¹nåü{Ì>žor3±@Žlc¬ý7 ìVU«§ÐÔ qx[»Žã�t]{ŹbêС‘1ãDt>í¨çרo�ÖB«¾KÊŸ’qÓAm·Ï]ή¬·1%6ÀÎ ao»¤iâÆ¥e¦¤,]”Ø“ït߉Bs…F¸mFŒyó;&øaß:¶WrÌÛ�ÖÈr‡0–¾ i1U·…ž_-@X)/C’®Î�{.j݈Û*�ç§‘>‰LÖ`/±Þ!8®ù‡=­—}‰ÅµމćøD®ø#òÂVmR Z�›Øà;ÁÄ ¥ì{ŽT>¸vSBû ›¼<û‡­c‹Î>˜+ëðá�h¸}«¶´LU$#r¹!Q¦\øaÕ™ãÓ�Øe¦¨X,ÞR.bn²o<“Nïðî\«ãq ˜Jª–ûš˜|®£2ˆÔÝp¼QûahG —L”oEÏ5€qžŽ¸¬')„Ó½¹Å½”Q<5¸"ªöŽ‚t”nÁ;5úç8óü˃fû 3â)ò½‘…´±Ã\³))…òª¹Aà’⪫þi>|5|/9ÇÞBf³Ï1Ž-7/5,ã…øaÕ¬wè¨�¿ñÔžüJàrU•íÒÏ’=¯7eŽÜ#þ$z�Ôž ï¦Ò…7 ¥´^6r•âÊoUâ�ZË ›®X*ÖØêe4^è>òG®íÛßä^à|¨é1¡MìÙu'r]oˆ1H¯Àrü%¸­´ 0æ,3Veªª—xD®?·1­K+,Iq� 3YÏw,k¿r ˜�e�LøaÕ±›Ààv��âÄB Ýœ[Õûüaõ†Pcž»,DY°¡©µKuæ?‡öÛ^kùéÿÏý0<�õòFWÒã¤~•ãºx›vø†¦Ä#޽ìq䞦×Ê´Á þvÞÅ þù§Gúî+bGÙ©VeöàI�T`ìÜ)‡õäL¦ðø3ÕͼÁɯ3¦Ë÷ÈjŒøaÕÔ�Ásc0fx�‹ë{Šžâ##½òYÿéƒ i„[•~€ é¤×Pz À¿ò6 _ýÊþ4 øaÒ�Ú§ÁçÌXZ1§gºW·b°úÌÚ³‚]­�*ˆß~ÒSä„$“툈œ�fÏÑ+ˆ3ju[#v›òÝ$XHe\n§§Áj£’»*ß5zŸº™c—� ¥[Éêo®„eës¿‘ágɇžÂÝȘ¶¹ ÷ù€²| ¾›|–å»-¨O# b±k0úó¤þ)BøaÕ­]xúë|°òd¡Û�‘Ñ‹,–0ä]ZÕšIë­"”1"¬0j�;Zj#ÛR�-—£§¿7Ê·ãYC½â¶º+Í/8ïùêíÛ/õàæþmíOžùGÏZòå^Zfe ¢5,k¸tÍ…—`\€@ÌòãŒQûgºJìfËž™o=âp,ª° F�“H¼NVŽ”ùL<ÃøaÕ°¿ë+…'µ²cÇìùcI]¿}(ñ»ª�q6#�ghóJðwÖMQj¡q)H6$HæzyXW«8‰9vý¢¸]_YóoDóõ§þm6PÞæ<}WÎ\Oµð%îh‡:㨃.�¨�Ü"®6Ñs ÑKeG»îvd@9ˆ‚Ӹ󟕞ÕÝ/­øJ|2ÿT=�/øaÕ¬Öé÷‡†8ƒ©z #<öœCݸEÈéˆ|Ñ&ökÈÏ�áT{SXîwÕ¡•´a³äõTÚ-ÚEy S/ó^:9‚@ÜùÑ¥ãM Ù©±ÓÙ•¬°EBFÒ—<°ôx>–2°Ÿ�|ó'í¥v„ýWg*uaôR–76AøaÞíÛ¬!ÂÀ�‹˜­³ô¿³7­*Šs 0of £´ÄH!Þvæwꑊþp•ÆyE#U Lƒô%í.µG.#ž� µIŽ4I(j g^ލþ˜f"~÷Ãoæ +µsW(š—4<ñ~íÞå4ÑfÄviÆ:ƒ§¶LΕZΞ'üÔpÆå.�œL1Ý-54UNü] ÎøaÞÌÐ[J2ÉŽ]ïF·ñ@Ü1r\¨ýÓe(lþ¨<¸i t[æ¹Øëÿölg5ÁiF`éq­IÁíÌyP±71àa-Ýï>B\6™&vÎUõ;ú HŽgÒm‹Zrç#±XFÄûí (qËñ\ÿdøaÒf/1@÷qŽ#'•zíûú.ˆB޲%C€‰yG¬òK¯öRfQk*¥ÿ1ͬõsËb°6ûOÃ8á) TP¨pNøeï0!óÆ1îØ™½‚îÙ§Léd˜ÐNâ,Š<19d«Ð"ÅÑlïÔÜó•&aÇËêo1»±ª vJd ÊÁ¢êž|o,/b¼ bl%\;Ï“vÆøaÕÙ)[" áX‡GImìpßÙ?…!ÞÑûðÉBç¡û2<·Pù�•Ï?¨$9îNß[œþø°ß¶¹¤êmÐñs¾ <=ƒýú š²=U‰—o»‚zƾä�ƒe äž[¿¨dÉ‚ÝXšŽp †f á Wð [^fSãú®LxÙ?�AâÑ÷6ù,ë`ÕÄ¥{l?@ù#føaß(ùí÷÷cï�Ÿv°TÕf^ªì“Y.ÙXÃFåÛ‘o«ÚÍn�„Y)o-ü¿Tÿ¤ˆ6AÎ&c@ŽôϘ*@ñ+D¡-úD}N�  ¤<–…)˜þϤ¿z²ÛÍî–±‘ˆ�³hp�—¢½.¬7’¹Aš7S‰<Ÿq=·=zÒÿaSsZÁ,…:ï’Ð[Q ¬‘â ëøaß&¾³ñ4DP{uömÄ€N—ùÜéÀÆ}œzIX¼¬¼i«ô‡s ¢&éÛqØeX¯˜ >!B¬Qˆ—A‹1ú”GäaÉs¦(a?ÚþUº_Ì 8d~ƒ?û¡dZÝ5Ðæ?Ó@mâo�pÔ�DnB`t·Úž;ú yûÎéaŒ?2X"¥§õ™M;�lȰ,Æ™kåíøaÕÔ�Òì”ÁÁ›08n"Oj ÅEõ¶'ؘ¶z�=ŽÁr®¯ÝzÆ.HtÒ0Âu/÷}ëŽ<{ÒMú ðioò�†é@€“S«öèx8‚+÷À¡�uÃ𾊚NJ1õ'¨Jäîb; `Û´<—G$&Ë5¡,þ*ñíë¯3óÿûÖ„ìÖ³3Ëç"ᛟv×ÔÇ\ øaÕ¬�ï±Pžªº*›oqÞ6Q [3!¾ÿF@)P{°²áû€Ï‘gÇtþ™ÒsY…rɈ(/?B„ y rÞxËm_ôÞÁè«`–/ïãšZQ?´ e ƒú?Fggýòèê�æAxß-G&ݦcIkÈ�çNá7;�”&)àFj0'6óP´Ô;*øaÕ›Y@´«Š•æ ž ã†c �t¦¥¬/Ó/ÊVàfLª•ÅqkˆIÓy‚êBð�+Ð?¨„z§¸C¿®έ(Ú¿äýÅ»S¢¸‰$Ájz{åAà€ŽÒÒmÏw?Ì_v÷;üùA©ÚÜwÃ�’ï'CMºÌt…u ðÇæ·áœAÁm‰tåûJw®¤%`­øaÕ«G¥ÄáA0à^.a�¶E*èŒ)@çïþ”ÃX�˜bù3ËXrDð–)–-6«B\!ž¸Ø¤‘‹Ï1BÝ¡€q¯Rmj>݃0’M„‹âí…{6‚QSñVչè ªëm¤§,ÞúÛLõï±Ã[Âþ ¡‘8}•¦¹¹î€Ž *·wh�8;)ƒßÛœf ÝN¡xÓ†2JûøaÕ¬žØé”W"ט“¹0"J­®>òX‹iäã‰U&A3J¶Ÿ?7£ ¸S4âv"£9Ù›úŽª×âñáNn=Í™pÛóÖ;pU�| cpŽZå !+ï“‘¦¹šx,V%Þ.:¿ÆÅÈ L,àz1àç·ÌٻѰïÈaOS˜Â«ÆÆ�Cîì¦È¬r4¼àm„ؼøaÕ›b`®éðàÝ÷'³#p' H{™¸Æ^ÙïÃÛq±ßw2z¹ýþø\ÑzÇ&ꓺB"LªkÊó*8ËM1P’çņ›h<Éî»àðA‹hMM<‘ŠMû†ªÃUÄ•¶=¸a-y#¯h×£SÓ š³Sç˜<üªï4xþ�Ù´“ˆËXP '"¥ðÖjÚ�›ãVÅUóŽR–˜”ÿµžøaÓ,{Qwšs¶µq²þcšAºÔ!<ÀE{mݤëý0•OêÐ_QAY§ß' �oìÔ˜DßJDvêÍÈÚ„÷ð7mÐ`fŸÍî'ÑúàB‰Aç¥R:ƒN°e>ˆ7�Õ!Ö÷-�èŸ�àM™Œ˜c†Z1ÅÏ÷Ñ?TØf¢DPèJ3 f›‡áEx *—œÝ|͵¥ª©.R¿áøaÞÌ0�§Ü \}$—ë-§d’‡Ž«ÙÝ€õWù‡CTNI´Ò3Œº³\޽ø2pg&¢WvÔ-¨Å4Ù‰í÷2ãe?òŠå­MG®×vn‹ê˜™�u›œHÿ¦á¢¿i0¥%Çnj¶‹£–®ñŸrü6àU‡& Z¬�’QCRÌ£Õh ˆL=µZàøuˆÀã=Tܽ±pŒ¼4óèøaÕ›öÿª­•–Ò±3,öD©¨:¬Â€]\ÓËü²6ßk Ê‹?GoÁ»ïCiôÄõh’‹› Õ³k «£–ë™-´¸CSÄ�¹¡O�ìç‹·¬Äµ´(@ •±„6O×¾l6K.òÐíŒK�AÏ|ˆÚ˜¿Q[gïpöUа�u³ªÅy ¦±8eïí2½ò ÷½´øaÖt\ntþÒQ•ʺÇU Ã�`Ž#î,mÂ+ic¶ôÚGà>úAã é#…Ý€F÷òõœ:lžÇâç٤͵‘O3UCÁ[z÷ÒÝY§.Bß# 1oå å»>áǯ£1>e²…ƒ{x=G Â*b�¿ºÕT×ͧÓ|½|¦%ê?Ô3Ǭ6Eiç/“ïªbTá›ËAh˜wТ/dÜøaÞòûèr^|ùxh¶´%�ãà'•ØGJC» _Ö6¡ÚK5(¥”]Øn¡§Û-OrŠd �7�Mµ•vr¼UüŽMܸ!5„M;ƒÓÅ�wøV�Y‘7±û½äÜ.öÎ�)’´Öúxz‡“zQœþ:ÀßàÙò´„ºâæ(:áúºƒjŠƒÉ%×# Ñwœ3”n44·.}A-hìøaÞì�g×îÜgµR=Øþ¼g£Ï¾š9d� t©´/-ØVx*Þ¡�+ã{ŽíûÛ÷l›(R2›öMĬéÔOê@Æe³‹î¤Ù ƹ’øcÿ<É.e#èäOP8ÈáJÅò=Ø­¾J€µÝñøßU8¿ [^îl»¬9¦îíDK¾\ËÁD#‡øaÖtq0Ô‡†gåàƒœúÌKØd¹Ì.Èïý›^ŸàýR6H Å"*ªÞ!�Í—ŠãªvO¯îQçN™YßÇ@„ãÚÂqå ßXÒ(ï�ÔøD®b& üz>Ú¦[™S;9•L‹tNöÔ•‡ƒ'#�e¥HÛ†]“öœ\eL°.ùþÚò@hÿT�¶Ù›DGAŸèOeÝ[­Bƒá$:ØnË^áì$$?§Oâ›ÝÚ&*èôÑYìøaÖqê¨*ûñ:¾Ýôý�R¹†ê¨Ø&ý)ÿ0)ó1L¤ï¹ºúe -Ü`Ýœ›ý«¾v"ZÄn,9t£ü¯Hp°²ÖC Žá%¸ß¨/F¨öÄKŠ+ι½2}ï(,#B¬çŒú×i4Øû]ÅxçY¿²Ó ±Ë½—lQ-éBÒ aÖe8‚9ÞxMÝýY²à.b½LC\@euøaÓYÀ®vÃÛ¤tì|¦ åÞïar·°×M ž{Àq†$¨2¯ÒC4T’]ºOµàøw†¼ mÎÏL—D3ƒWöØÙS¦@9uãݶV®l5a—PãÕG™ aEH˜^¯"kòpHnºñw×°÷©™5GæÇF®e…¹eÄÔÕôÄ�XaÕŸ  L¶[‘q„­øaÕªºh�8Óü:¡ÄQ}6‘(aæf4¬\Á;Š_Y¼­´ðþOT±Hÿ•,îÐ\mÚœ+WW�]ÙpW=Ù.‡¥Óí¶°ä6¿K§ŠÊ»5~ùª8œd”ô7O�,Ëú],Í3�zrš¹OSóžPÔÁŸyiÚCÁ¢W�ÝÅ�[#m~a!X[×UÁ‰zò0øaÕ¬É&ö®NEoJ5�ã_¬ä.‚m{(%™Ëû, ,YÄàóª�EôŒ3÷Iõ3M(ßpLØr&}t®ô¿çNë5R³›ÅÀÓ‘ýÆåŒ`f .IŸs®ý6°©öt±¼º €ívé'3‹¬)²Ï%N³°z›páRo\› ´ç�žvò÷íÏêÉlÌ/Œ7 CøaÖt Zx’Q‡D‚W9I¦sÅ-÷Å0ïèiirŸØ^:jûÎ?ÅPT-ô7ÕN pÿ�›�XYÉs€ªÚúÔuo—¿OAŠa"ÉB--g©ð¸Íšnܪ‘*œ�äƒ8Ó–ÔÑjRtL-/jyÜWŽQÆ• u‚~….þÌ!`h¼>BÐ<�éàð)#,~³)øaÓLuÛ*Du=fÍQÍpåùay�±�GB鯸B¯¨Eéùr/£ (£­%è<™ûÜØƒ“Ü´²‚ŤáΙ<´üçP ºg· ïïHaob–iªU/ÁÁ,§ËÖþ c&狈 ¸¥êz¦â•÷ûZКÜTÚé¥o‰øßöŸêœA˜õÝyQå*+öVýó&ªÑÂøaÕªÐÌLÙíÄLÌ¥lëNoŒg"ü©é\=ZJñòŠ Ïô¹Ô¦ ßiÍ+vÜb/:túÙš ~^kçY¨D/5ÍlT·½è$k}Õq¼¿1—²n”³’òÅ QÛ_঺Û*�"µúNoÆ�ƒÇcjNÁºg4fDÆß7Ñ»­Êt“ç×bH¢Ïüt0Ž ŠTSøaÕ¬�uPú�Ää.ÞÐ#m‡¶ìØ;†åžy,J•�"ĉ)ìá¶ipݹ8ݧ"®ý1…¨Wü€QcC�S_t7Éø°ý÷‚./¹?]Èž÷ɰ«%¯� /±¶n†…9�Hã% ¼ç‡Y—99u63[Ó¸‚üˆ\hø‹'Ž—ÇMfžt½Q›ÙÁXMsR½ÑA/ÏøaÕªÙ¼ãZ Ö†ÿI!vŠu›dH®ÅÇ<½ ‘Ÿ{o¨ Ä<@å<@ìj†C%¨TáäDs[kâ­oÃñÝÏàt³ÿ÷ìÖpªÁ~“?lÎ1Ne$Ä}úE‚Âth9üÿ•ÕEÖt@VNU}qŽ&._+#ò°sÿZ´Èé‘>Zäûky°¾FwÝŸ–…ˆŽ`…OêZøaÕ°jß ½Ee m›þ¤¿ò0Ú^;£(87ù—Æ ×µ”k¢ühP(N©ò–@_#äÔœÀœmû§¬–(¬?T‹eá“ÁË2¯l Ð’¤n"-–lÏðŸYXì˜_ü›Ž¬¼-o^�|4 BÏê�ˆL“W=Tz +H�„å.E­^fkACFIKOQTWY\^adfiknpsvx{~€ƒ…ˆŠŽ‘“—™�Ÿ¡¤¥¨ª­¯±´¶¹»½ÀÂÅÈÉÌÎÒÔ×ÚÜàâåèëîïòõ÷úüþdLAME3.98rÃ4 $¸Mô]è¿üå»:ÿûdði ¤ 4€LAME3.98.2UUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûd"ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdDði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdfði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdˆði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdªði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÌði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdîði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUUUUUUUUUUUUUUUUUÿûdÿ�ði ¤ 4€UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUÿÿÿÿÄø>Gÿÿÿ9ÿÿÿÿÿàÿ(& ¦¢™—œÿûdÿ�ði ¤ 4€*ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªvŇXf˜N¡0ÁðÄ!`8þM™:H˜úö×1Ï·?ó÷rJý¶ñŽ^ÿûdÿ�ði ¤ 4€ÊY é�C!ŒCñ‘‘b8°‚æ�b 0`0a€$Y�ËŸ¯Ïû�9ž[wŠ÷îXú{ô˜W¿/¨ 7åã ƒÁaÿûdÿ�ði ¤ 4€„À 4 ×A�ÀA�`8ÐIÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÃÿÿçÿÿÿÿÿÿüã/†ß¹û0útE8°ë.êDVÿûdÿ�ði ¤ 4€tSEjfVtùî÷;-޲¯"WL$ `yýô¯8"ýض !äϾ”P,¯áÚm8”Ïæ{«¬o^¿z>åÅóþÚïç�/ûÿûDÿ�Ài < t E#Ž€¿/�†÷sÿñƧfé·#`ù`îLÛÇóî;µ®cܳn÷l9nüÿÔæ{Ï *ØÃ;—íß±~1,ΕѬ"ÄiŸ†¯¾~]ÿû°dÿ€ °‰Lþ{¤‚ÇLÉ�Ìà�*r%UùÌ€ Œ+?4€Õ>U'e|Ïyå¶^ÖÚ{L½…&6åùëñ§wÜ? ÿ–óÏ»ü¿œÏ¼ÖµoyX« ÅêX쾞݌ÿÿÿü¦]à‚q%‘ŒíÜÙtD„H“#2¤D΀çxF]!™üBb±Ù„L#$“ ¦‰Jrƒ‚€�l¶¢¡F¨B.* €»8×I¡,hÐi5…LT)6ÅŠ…f)FàëD—ÐÉ|£˜;oä¤xƒà,l³‡¥Ó”/ts]Kå&ÜyÅUÑV-+�·½w­‡@šKi/ÃФØÕ7rTQ‰©»Ý1oY^zSår-æá—÷´,9�?�ä?K†1gI`h“slJÉ¥ñŒRœ4y³8ìýVFeÎʶ7'aôp×¢û�K7/‰¦a^EYÖM‚ž»~î08¤ýèXý¤”–èÊ`õ2j¬²WE7MmŠ,x*öã´�Þ œ{ïÌÝÃêgZÿyß¿Íg�yÿÿÿÿÿÿö¥z½Ì·—s¡¿ù÷ÿÿÿÿÿþƧ? êýZöv’‡ÈH ÁÙÉŠ@D€7jîÔ“±‘ÎòSs/4_Ê"ôÄ/Ü@ŠQsmOSQÝÕW_üHʉŽ{kªZül~Š£‘І+7,ø¼�y³­-9iZŠˆôì "ØFC 2 ÍÂP!³¡Pð(’%y\@Á`kÈâ�1†�E•Y§™1E°}e„ÈCñäU€0«ö{,*?³ÌMÏw%Ìm³·i ©êkÔ• œÖ61wñÂÖÿû°d,‚myS÷kS©Š~í�áUÍqï½²ª^�`‚•RdÓCeŠùg ¶(©d\ çjÒÏᓵ·nÿþY]?8È/ô´JG,N#â0L¾Ãú’ŧä¯üxò¡A~¯ÿÿ8ÄïÈUØWS4@-¡ÿû°d,xUóOer1zÞa"ÍåUÍ=žˆƒ‚køð¤�HLÃJ)"@fG€O²Î0,ô ø`P ‡‚EÃH�Š¢<}—Ý€lB+|&“™|¸�±Â¬Ìj5Ǧéo¸Yï†CñúÓ÷‰³¤ý9\εSSõi ÀàÔéá7O!ôŠ•"–ïˆÒFž”Älâ°Ÿzª9,§‘C < ¨ìâä S¹Ür!Å͇ Ø’›ÖœZ¨ä'¦LXA0…bÆqk‹/5�q©‚îѵŒ‘‡kÞ?^¼±DQgÎÕÇv7Z«ïlÄÍ+\Ùî�œéìÊ|ôîOkkVÁs`$BÀÃ^å^ˆr+J¡ŸA=ÕöþŸúöÝnY?túüdôÿ†÷û$™ö8_wþî³�CÐ �ƒ8pôojXhÈšp@å‹‚$=q4Ȅ؆šiZAáë¥�9*JÌØ‘wc¸\ÓJˆ>ÏdÅFMI$ŽÎ¹p|^OËoÿsoïÓÛ”Xtd–êCÒéÙ×)B8 …Jbw¦\d{‹ã‹æ“¡J%Uqc8Ö>2åñ#Ù1¸‘ª¡W ÍVôÁœ«Ä9‡h{ö¼UªšŠøÌ)'÷“rkn2X8€^ ðÈÔ` „Ié9­ök.ÓÓÂ^“Q“‡µøYpt`BJ·+Io“Åôˆîý\Wñomsëÿ“6¦ß~ß3ÿÓ,MÙcNCîr„ àÆI‚àJx¦ø½•ßÿîùÚ2ÿÿëÿÿ¡ÙUBO¥6Ž0´ÎAã €1‡4L Z¬‚#ñIä]Gö=&@Œ”˜f¿ÿû°djÕóOerEçªÏeg)éYÍ=7ÈÊký”ˆ�ñÍSRù;[�SõvðÄš<8FÉû–øñ/çΜ—!¯Õˆ±F{IW1”W<«™y—'*Ž8\¤N³+bµC�[½.þ6æèÛC£àñ ¥N#|í\¹pXgŽ¢8D ‘óØ+šÅt¬ÓÅr)XÕ(î~l;–\\t†Ä0Òöj÷a¿•�B“uœJ]dC›Õ0^×Íac­¬9 Õý]ò˼*�ý[½ËÕç�Œß;ðH¢@@.9Êi4Ɉ¡5JãEH�38¨A_Ö¼Ê'ð°¸Äg»uûÿu<«{ô™×zzÿÔô*ƒP�C O¦�“ÿIlçþCéXAÀÕòÅÄœ]FX†(©;Š£Â EGJ ÒRÓ z_d^W×2‘|»qMeqºKõE–ãö–ª´ž¹©¦�—­u}aƒ/âÚTÛ y ~õóãaeìhŠs)¨E*�Ȭ¯ÕjW’âÙô´}Ä•Æ�•,‹£t¬R/«ÉlvØŠÔ,çCS˜ÇùIÏ3Ú¤”ð¡»Zbz~�´éôS¥ßBYÌ*Ö™Öí˜:Ù,l.6…ñ–!8d~9 oR¦¬´�Y6ZÝR¼¯e[Ÿ?¬ù÷>ü¾�JÚù£úg@V Uv-QbíäNÏG_þíÿOûÑÝ‘�}zõû¿äe»òßíaþµíXC4€S%< eŒPÓNQoÀúë R^ep}�wZ„>­ÍŒ˜Žv©ùý-ó„JpÞˆ–E(®Àí̾ÿû°d"€ jVsOerIJ ÿa……åS͕ݧSýá9!Iå·Q�ôŠ¢âu¨v/…{Ku5tûcl¨9�¥ó2XP¹Z;ßkýMbz6³�MMŠ¥ö pz.qÿó¸}.8‘ê)�Û2Ü»û÷ÐóWÅÔßÕø+#™P È*ÿà AJE‹ŸÄ;úî$.²€†6±dþ¿éÿÊîÈÎy?/ïý¶·ÿÿZo/ûzÿì�õ0á‚Áˆ5Xï/ÈúöÀLD |P¨TÌšl(p&H±�ÕÞ°$Å!× �›•o%èÚ:b—Wn¯›¾·ÿÿÿüÿújÝkv}I*shìCÚ #9§™„Ä! ×u»kÑ{µjk¦¨™É+Q@·ãÚ·]šÙ+¶ŽºmÿöéFÿ¿nïâçÃWõÈó¯ÿûRÄ;ƒ­µ @×À÷¶aˆ N#œ4ìœHšW®JU?¦^gÍç=¿¥v„y*g^M)\ŒèÑZ¿½W$4>ÚdLN[Íûåú>¥S3õê*Ööß G_ÊxV#³B)ë´eT¶H Œ–šN@Ñk%©§GI,™eU]¦zQ.û«,¶-¯¬ª£"Ùõó·ÿõ¤~ù}ßJWò�}ÞÖT˜E¤>é ÈMŠB#–�¤D™?Èÿï–\dáO=!›Ÿbtph½'r†PŒ·¨ˆX.vlÈKÿûRÄWƒ ­µ =¶!'¡½…Ö.™|Ÿÿ÷ºùãnµXNkíÝbß aWIvȇ¢'HT'@if³³"rÙ•µz:ö²í£<êàŠZZVˆl¥VC¦žÌ´dO¯÷G+>F{)M¨¦³k-«¡‘§!M.hñqõ•Ò'ÆfŒz0@úÿÿúï�ºYïmV¶ígÔÖwµT†‘ x…!G!'GtÕ ÌgùÖ�2éK.ªüÖµ«mÞ“ºŠkœR1U¦cë’ë&ÈÊ ÄhÓF…ÿûRÄnƒ‰Y± = ¶ Ä'¡’�#¤´UdVißr˜Œ —N^’1·|ÓÜQêåZ=ÞÎëO7Z¶ÆÒ�}ùã�û³«×ÆwáñC¼[fB¢¯> ’†R*ˆŠ(£ ?ÎŒŽÿk;L¨�f*nS¡SyÌsfiÝT…*2ÙŠ&®ã;+È•ïÿ¦�µ ¿î‚YSõcY4FÚ™s­Î(M 4�q°È¬4EXuà�(ÐfJ8 vhã dznE"p z³3¬Ó¢zÿþr|í…ÿûRÄ„ Áµ@ 7Á#¶`È' ÷oò°×«¬Übß—w.Lû7eŠ’@K”¥)um.W§[MF¢‹vR6"î‘mÚvbÖf±QY˜ªGuJd³ý¾º~ü2[q޵öŸ�šŠÜfÊBýI�Œ“Ù+q Ñ áY¤û¾èàl;4·pÌ2!˜�äê£fŒKËCŽ˜…I¤«»Y%>®#Þ¾Ûøþ?Þ¯‰�y—³,¸b¡AY‡ž �,‘+�…” %*Œ?ÿÿÿËÿÿÿÿéíçX‘©ÿûRÄ–ƒ ³ =ý¶aH› Ò+Œ§º…-zÎv»c±¸F”ø1Þ�V”Ôß?Bøü'‘ßÈ‹ûßþoë$–R[ Ådt�¯# 4± KY$íq:4s²#M’ÀÊÀÕ= „gìdLt2•f;^«é�cµ]Lô[;£ÕS–ÕßÿúßD÷¾½ú~"‚i]1N^ w/jɃO)ª MFW+MÈ�6_+i¼oÌŠ¬ó%Èìéô™Á® )Ë $'¬ž\W'5³’ŸŸ6?'ÿþpüÏ&Ý™ÞãqÿûR݃ɯ =9¶ È£Xô¡Ùì”<ö =}aÔw¥“ꫜL»©ä¤NýÝgf¡V X‚�Š÷uQNkØJ$&¨gÈ©s©ÐªèÈ„\ôôµ?M?Ýÿ’ÛXßéCe+0Ylö¦Ñi4�,b`ø=@DˆWÿÿÿ-oU¦—ƒIT;f�Ê·j‘ ÇÕ’:ìtÑ… ¹ès5KÝ[$Ú?Ó#D ˆ§�øþ?þxç“ëˆÌ�ô¬-5ñ d_e°ÙSä9Ç$, ÿûRÄÄJͳ �= 6!'¡Øaþÿ?éö”`ÂI‰‚”]ÏKi»eóf;éi#R ¶/;:FSœ}LÄ×s ÓÔÏW¶ó£–=h¸c ¤4\jŒ" Eî A 8. `&¡ r ðäà‡å�¥?ôõÿñò‡¬¿-ŽB¼}åøåVAT÷QÞ>™Z­v_ÿWS›QW3µPÍÇ ›;ÙóÙN~U~íÿëåxJ§nÑ,¹!h,è–Ôš Òdj�-i² ¿DH\”ÿûRÄÕ ¡¯ �5ᡌ˜ËA€ J ŠÆ@ßÿÿÿEV"£¸ÌkÌeR‘÷w)ЬÇtz¯.æE!êK©nèÆvz¹W[ºûþúµu—ö¶ëÆ7”…N�J(ô˜"5±›Öó@ÁaL=#ŽÅ @ÿü¿ü R‡ÿÿÿ䉕àt½wiÒ«UGQl�wE²‰ì¬#GðPà‘ƒ°ºâNÜ#›±Î_ùSÌžž‘œ¬?Wý¢�“c‚ÃNB¥%©ëÎn_XèƒaåÑ0²Áej±ÿûRÄèƒ 5µ`‡¶à!¸I¶ÇïÿÿÿÿiòÌ—31˜[šÏ-¾y?ï œ””󤊮nK6‘â–ªÔÕ{±†yÕN~;sùU/µ¾ö¼½Í¯Š¸»k¡œÐMl0>Pø`ùÑP 8XLÆT,aLq€ÿÿÿþ¥Yÿÿu­>yñ²ïr‡•vá†Ïù¸JK×u|â•1ÚEf®´0’ rl즽þÕ¥éö6\on-dfY”š·®ßi ÕìÑ*¢'m9Å!D##à98ùÿûRÄèƒ e³ �-ÉA¶¡ &øÿÿÿ¯ÿÿÿÞü�"1µ“Y˜2 ÊiR+E½‹'Ç  NàÍOJä(aØ™dÚ%‡y©µþû3;%fr®g,«ŸXP˜¹üKÔ1¬´¼Õ�îS&!§“I…ó—–—ª°Ðÿÿÿüçÿÿÿb]ˆÍaI¤ÝÑÂàšW„=Ë»¨K=\ˆi“ÅñlÁIus?W;ŸñÉeûåß8g—UYñCcÂIêË®)M–VX`‰L3b3EØ„$TVÿûRÄìƒLeµ@�žÁw¶ ¦¨Œ<Â/ÿÿÿÿÿÿþwËMr:jdZ‘—uƒÊ@œÍåW‚ÉÉWŠ�ÉG’=A ‚Á.�yXžÎ<²,·ÎçîWQ`®f[:º+gdr´�’—2vÕ02+#`˜PH"(ø•ÐÿîM©4D6±Ï‹2•ÕJùݲn¬0^ŒgZ"‘ClV�¤±ÔªÒîEy~Ÿóï±¾²ü ‰ú…Èa5TŠ…W¦djj¨a#ÉÉTDL@Ðl”\Ò¶Ä€ÿÿÿëðÿÿûRÄêKq³@�= ‚¶ ³Ùó‘v¾Y™©¶q‰'þj»%#»+Ñž„l2ƒŘ$hœ^´ Ñ‘PIÄå/é^S4à?Ì›Ë3ѱ1WO\+uîŒý”† —¤:�!H¸€N /Š„sµ?@ù>ÿÿÿÿÿÿŸ;Ô)*_�ª¹jdJŒå$Ç™Ya´ LŒê ʃˆ „Ï8Ù«c¾ï¹ç}» Q©ûÝðm™¡Q†çXËïTQÙØ7(ÏB¢£Ääm�2• ÿùKÿÿÿûRÄéƒ ™±@�= q6 H¦ùúÿÿÿçlA¯û÷l|õ¿Têmš(þ™ýˆê-r ðm±Ôe¶ïȧ9Y™å¦â›þþcwßo¬÷OÏ̆awV­“¨)“dK‹ž°àðÆå“&Θxÿÿÿù”޲ÿÿëáÚ¾Ë �œ�ú]¹²ñ¾ê­\)„›�q„]»LBåÂU—RÐó†eNÞ~þ~W™Ïßž¾R»±;'––ZÆ×À\µx©,�·ÙKÂßM·ŽÿÿûRÄë }µ@ ;A”6à³Øÿÿþ¦/—ÿÿǘ�9sIBé¡ EËu;#XŠÊV¢�‚…¹Î—D8�TuGtF[Š‘.Ôïò+»0–õÍêl²ÑÇQêAŽj$¦?~ê•(@MNV'ž -Œ–©6pÿÿÿïúúÿÿ‘œ™P\Т/?ôéB%¯ZÖ*Jt¢a.fæýÁšÖÔ’p‰µ-sÿ.ßÿý9¿ô¿î?K=�¶ÓK^gϬÁ•Ö3‹ :--€Üý:ö„› Û`@ÿûRÄìƒ %µ` 7Á’6 3ØÑ Ë×ÿúµ6Úò²ä4�"ª(‡)�芢êCÕ°¹$3ÝXî-,t9XÆ»4çeSUÿú©Õf¨š?Y“jM¸ñ ðß%\ȸm ‰`dºND ˆÈVÅꀽWÿÿõÝï5’©î›k3·SH ~œëÍX);“ZÔŸQ‘ˆ{ù­- JIxeÞçù·Wýüùó+Ö{¿°òõLäo&�³I1ŠŸÔÄI¢ÈìD`5ÃÀh6 �•A1@�•²ÿûRÄëƒK™µÀ��…6 H³ØÊ$D�ëª~Çÿÿ‹<÷cb4Ås\\ÏB·ÐérZå^ï™n†åMÄÚS¼™Rg̺ìÏÎßzÿü÷×z¬uW¾ØÂ¥µJB‰VsŠÁjá`j¥ ¡‰ÈFŠœ½.ábD °òà0»/ÿõ)�_ Í ¼hÞecöÔ»éäcE3³ÔÑdÙïhÃ(·h÷ÚÎòƒî>¯ÿù‰^?ÿÿ¿ûþ»ˆíüuEŒe�Æ ©ÔQ …””Â:   ÐáÿûRÄêƒ yµÀ�žÁj6`Œ&ùÿÿþ_š@;v¿ÿ©­D üC0ðu"�,g¼C„¦ #6†þœ|¯“Å5„ùnÍÒ7�ˆ�¹ÏΟÞgržnßù¼´4ö7õÛ]å¬+Þ‚æaCÔÈO]:HOˆX×0>heÕ,�­úìÝÕ(½Tšn‰5ªâ4uƒ½é–ýŸ¾Z<�˜öÕë³ûã°gZ£¤ãñsŸ¹.îMózffvŸó�ütïbí³[Õ6TzäjY:ÿ Dâ*qÕ8†ÿûRÄí =µ@ 5Ak6a(¢at$;^‚Z,–HÚº­ �ÿÿÿ÷H(©¸Dzœ†3EЮe§3¦;&QÂä9ou%Ån C”‚d=+_ÿÿþÝèT»X™%8á< bHÃG‹ ‚01C‚ Qÿÿþ�53{ÿú¢°ÚsÉ–¥~ß|…™AÑ4Í�˱Sá:Ì#rm%di?2³Èïô½´ü¿çc_ût×™¶Ne [|óLL,�%é8&Y7™lõ:1¹£±ìÿûRÄì‚ ±µ @A}¶ ¨³ ‚?ÿÿþͨVÝÁ¿ÿøŸln4 �‘ò8õTÅû,EY¯ «ÉN57C“5TlÉ‚n{ Ó€¬¥=guÿŸéÈêYò¼eP–•‚~ÙU (i–q &®pH@)H„�©ŠpBÿÿÿý×%—7ÿµü)ýM>©-;c®k9r/©Ä…ä‡ áb]C‚†AˆÉëŠ$0äLYpÛõÿÿœ§oª½dV’{8ªtú‘Q 1#moHt´YerRDL(ÿûRÄì ‘±À “�=¶¡Œ–  ÅÓ˜]ÿ° 4zb£ÈfËþ|¤0 ¥  ˆ‚ªC•¤>ÁH›IV¾{¦×°å2l“)M1 R3ÿÿÿT·e£±ŽèŠŠ ÊU,1ÑŽ–$Á� Õ`Ò µ¬Õ\u"˜ÿô¿™æ¡…?«m8ëT),ùK_û¾^UQó3õ­H†©ò”>‰ò2%~#¯�øùþ~:ŽÛt(s8×¢¤¨†« ñ2F �ݱ`ôÐwk�¹ÆÉ(ˆ€ÿûRÄìKõ³@��w6`Œ§iÿÿþi3�m EMÿÿ¼È_nLDWcIÅ3“Ú ¨G!)\ÊyûE:ŽÇpÖÃ&CmMZÙ7‡¤ÿ–þ|º™ÿ¨ Èì&ÚÙžL™‰*(¡"bLÕ$"�]!*©•Qÿÿÿ S¬eÿùFg/’³4&g§õÑ Ì蔿J1¬ TÃ1ëK;„nå\Äšc(0£N´,òÛsüçsŸ)%�“‰ S*DsŸü‡óüóu�ûb¤ÅF䉜¤àüÆ\Â(ćVZa”BŠ ,`v�²JŠ• ´@�Ò·ÿîÙgs{ÿù•©<Æ&Nr=îyÎÆ¾¼vì8¿™æ’ö«XÛ;G们ªçÿÓ·íëÊ®£QJìŠÊ ÎìcÄ1ÅPˆ&4ÿûRÄïƒ }±@ ‰}¶ Œ§i85a«d?ÿÿòm?À2ÓZŸýÊfyÝÃá•QŸÏ)%[+lg®V£#‘¡^¬à��*�ݺ©�×êìÞ÷ûÛ¿/!rÈT®}÷'.�¢U惒¦Òç¢mÀ›Q\V`}f€QÿÿþN×�Lù¿ÿºñ–¤^CžêÞÎwÓ `ÖVq%Kà yÝ¢C=Zó$Ô‹:Êt¢Òòú^\ÙçŪ*鋃 É,m' œ2F �¤š¤ÿûRÄë‚ u³@�>É‚¶ ¨§hL›À�R)\ÚúášÿÿýSÙÎÇ&‹7ÿMœ"ŒÞ‡–kŠ: ”a!Á%-ÐÿûRÄé‚ I¯ ¡ ;IX6a´�è› ÿÿÿ±ÌÅp†@£¡,Ìßÿœ%èw*LS³3ÁËìÝ209TÄžs)ʦEtº¹T΋S©èVf{nÏFûÿÿÿµ:ŽÞBÛ¶'¨bZÔ(–HË €™í“Ì”¨ ‹j¾u[kiþî—ÿŽŒ£e aö¿ùezà’<Zõ2UÎE3-P¢p¢²;™�Ó1•Tò¡*­IÊÃv:5ÕÕ¦–WbÿÿÿÿKF½mK^áÆØ#.•ÿÿýÿûRÄëJñ±¡ UÑ?µâtŠ»�<Èæ(²äb+‘=í5˜‰—Ù¡jÿý�jB5Œ�t{·ˆ�J¼b"ìðÒÅ $/7“Û­Ê_ÿ‘fÜëæìË��‰•›{¾{9ï|Ú8>0 ë `…eKkI?‹²žrØÃ³çmŒ«Üó±)’Ò2þÎÔÆ<¥ØÏ•s9‰º!YÔyÌbM™† **:Ì×mÑU[ÿÿÿÿÝ™¨ö»:µdaö•�C (¹Š9»î ?ÿÕÿûRÄõNµà™�ƒ¶ ô!&ø£':¸—8µc…3¶ôéïsAЫõª'ßû¯4÷{2ÓKcÕ>È…X™‹eÄ43B3Ýn…ùŸ—åÿoJ§¹Sœ™Œc$‰4šFÌWU®¡"M3¥Ãž*j(Cp ¢rÝ« ÿÿØd<ͱ¦ŒD8L».ÿ Y“€¬=�{¹?]T.sž]…u¦m©9Ú�ÊÝ *»æ°›ß_ü¿ïçñõ^_Ýõ:­Vá[4®a÷’» Ð/*B„Ô ÿûRÄê m§  ­Ù”¶ ´!³¡£ËcD�œ§Çó�‘”¡Ð@ß*´¿â²ŸKÿ4#õp”[¡kUI„G$7)¡gÖÚ$ÍlÖˡγ?ÿÿûw§g»3vA„©Âܪ@3¡�îF$Êrï³@ÿÿÙ²ODd9ƒJ7"5Ïü¥þטWBMsé[Ae[íCPÐ� )ÓËË´ÏrSR6*O3z›1ùÄËŽ^ÇYÿÿó¿;Ÿg<„÷!MÕ]Ïfžá¦QCêi$zR²Ó`ÿûRÄë‚ é³  ±Ñ“6 ¨!§ÙJá€6µ�ÿÿÿ½Њ1�~„¦ÿù&GIÐäæZ Î+×·ÒzZ®U$·s…)iw*•·78YäQÖ‘U«ñ!žóÿþþrGÜsn[Ò„çßä‚^eÚiœÌU‚¯É�Ð.K*߬Eÿúô*å“3Yħÿì’"§íöš)œ³ÈŒó¶  ªAj¥hÜP £ ê�*9`¢ jÿŸŸçÿò¿ý·{³ç­2eÎ@ÎÇNh¢ÿûRÄë‚ ± �>ÉN6aèŠz´†Õ³‚‰‘$ ·mcŒttäÕ3ÞÞ^ó?¿þw§G/>}Š«ŸÃ6õÚWMH(€ˆçB1#ª‹F‰Æ#ÖÎŽ£¢À6ÿû?L‚V@˜‚ïóH€ä¾nˆR…•2»d‹·g�š÷‹[z¾àšÝˆ=Æ)ú,Ľ>el×î�‹h›ê©š¯Ÿùë¾úÿþ8žõi¿AšI̳¹Æ F<É$ñ �p†â„(¿r4IÿþÿûRÄï -¯¡ 7Ƀ¶`ô!§h( L ”�ã·t?ÓþûèºV¶áÈs5B¶U)8�&°õH?pÄ  ÚÛ«Â uÒ/5amë>åùÿÿÿÿþß;3¶únôY#šKC²þ-R�z¥ºÌÀ±i½¾HÑ$ e¹îÖ8fBÞ-vtïÿyÑfœ…Dµ³… óë=B“ÐszI›ba’ª\‰T’“]–_??ïÿÿÿ·÷;™{~uÚ²cÓIUP%€ŒC+‡0ç8W-Œ€ÿÿÊ-ÿûRÄç‚ ]± ¡ Ý ¡ã´�Ò{™ Ó¤rìF‡,ÈÒÏ'=A¼C—'émåP™ ª›ÊÃ[T¶³Û�‡&”�cÛòn•5-~Égù_ÿ‡3úiZ¼­÷ŒbŠàÖ4ÉÅ g¬tÉH,Œ2†¦!ipM4 ‘ 4ÌŒÀ×—ÿäÖË™ÉHÈÕ–¡‘“Y�ZËPÉ•”'#Y&²Ë!”¹¬œ²öJGü¿ÿö‘¬¿#“,²Ô5k,ŽF³Ï²æ_ù�Ë–( NŽF¡�¬˜‚šŠf\ÿûRÄñ Y³  Á‡¶!hšúrnªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªLAME3.97ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄì‚ õ± @oÙ�¶`h¦øªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄìƒË]°Ú €t4€ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªbeetbox-beets-00724b7/test/rsrc/only-magic-bytes.jpg0000664000175000017500000000115615253035401021673 0ustar pieterpieterÿØÿàHHÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÄ ÿĵ}!1AQa"q2�‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2�B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?’€?ÿÙbeetbox-beets-00724b7/test/rsrc/year.ogg0000664000175000017500000002055415253035401017447 0ustar pieterpieterOggSþ–ç=݃[vorbisD¬€»€»€»¸OggSþ–ç=EËÖ—:ÿÿÿÿÿÿÿÿÿÿÿÿÿ2vorbisXiph.Org libVorbis I 20050304 YEAR=2000vorbisBCVcT)F™RÒJ‰s”1F™b’J‰¥„BH�sS©9לk¬¹µ „SP)™RŽRic�)™RKI%t:'�c[IÁÖ˜k‹A¶„ šRL)Ä”RŠBSŒ)Å”RJB%t:æSŽJ(A¸œs«µ––c‹©t’Jç$dLBH)…’J¥SNBH5–ÖR)sRRjAè „B¶ „ ‚Ð�UÀ@² PСЄ†¬2 (Žâ(Ž#9’cI² ÀpI‘ɱ$KÒ,KÓDQU}Õ6UUöu]×u]×u 4d@H§™¥  d Y F(ÂBCVb(9ˆ&´æ|sŽƒf9h*Åætp"ÕæIn*ææœsÎ9'›sÆ8çœsŠrf1h&´æœsƒf)h&´æœsžÄæAkª´æœsÆ9§ƒqFçœsš´æAj6Öæœs´¦9j.Åæœs"åæIm.ÕæœsÎ9çœsÎ9çœsª§spN8çœs¢öæZnBçœs>§{sB8çœsÎ9çœsÎ9çœs‚Ð�UA6†q§ HŸ£�EˆiȤÝ£Ã$h r ©G££‘Rê ”TÆI)� 4d!„RH!…RH!…Rˆ!†bÈ)§œ‚ *©¤¢Š2Ê,³Ì2Ë,³Ì2ë°³Î:ì0ÄC ­´KMµÕXc­¹çœkÒZi­µÖJ)¥”RJ) Y€d�AF!…Rˆ!¦œrÊ)¨ BCV€<ÉsDGtDGtDGtDGtDÇsUõ}Sv…áteß×…ßYn]8–Ñu}a•máXeY9~áX–Ý÷•et]_XmÙVY†_ø�åö}ãxu]nÝç̺ï Çï¤ûÊÓÕmc™}ÝYf_wŽá:¿ð㩪¯›®+ §, ¿íëÆ³û¾²Œ®ëûª, ¿*Û±ë¾óü¾°,£ìúÂj˰ڶ1ܾn,¿pËkëÊ1ë¾Q¶u|_x Ãótu]yf]ÇöutãG8~Ê€€Ê@¡!+€8�$‰¢dY¢(Y–(Š¦èº¢hº®¤i¦©ižiZšgš¦iª²)š®,išiZžfšš§™¦hš®kš¦¬Š¦)˦jʲiš²ìº²m»®lÛ¢iʲiš²lš¦,»²«Û®ì꺤Y¦©yžijžgš¦jʲiš®«yžjzžhªž(ªªjªª­ªª,[žgššè©¦'Šªjª¦­šª*˦ªÚ²iª¶lªªm»ªìú²mëºiª²mª¦-›ªjÛ®ìê²,Ûº/išijžgššç™¦iš²lšª+[ž§šž(ªªæ‰¦jªª,›¦ªÊ–癪'Šªê‰žkšª*˦jÚªiš¶lªª-›¦*Ë®mû¾ëʲnªªl›ªjë¦jʲl˾ïʪ)˦ªÚ²iª²-Û²ï˲¬û¢iʲiª²mªª.˲m³lûºhš²mª¦-›ª*Û²-ûº,ÛºïÊ®o«ª¬ë²-ûºîú®pëº0¼²lûª¬úº+Ûºoë2Ûö}DÓ”eS5mÛTUYveÙöeÛö}Ñ4m[UU[6MÕ¶eYö}Y¶ma4MÙ6UUÖMÕ´mY–ma¶eáveÙ·e[öuוu_×}ã×eÝæº²í˲­ûª«ú¶îûÂpë®ð p0¡ ²ˆŒaŒ1�RÎ9¡QÊ9ç dÎA!•Ì9!”’9¡””2ç ”’R¡””Z !””Rk8Ø )±8@¡!+€TƒãX–癢jÚ²cIž'Šª©ª¶íH–牢iªªm[ž'Ц©ª®ëëšç‰¢iªªëêºhš¦©ª®ëºº.š¢©ªªëº²®›¦ªª®+»²ì릪ªªëÊ®,ûªº®+˲më°ª®ëʲlÛ¶oܺ®ë¾ïû‘­ëº.üÂ1 Gà @6¬ŽpR4XhÈJ €0!ƒB!„�RJ!¥”0à`B(4dE'C)¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RH)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ©¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)•RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”R �Šp�z0¡ ²HŒQJ)Æœƒ1æcÐI()bÌ9Æ”’Rå„Ri-·Ê9!¤ÔRm™sRZ‹1æ3礤[Í9‡RR‹±æškVk®5çZZ«5לs͹´k®9לsË1לsÎ9çsÎ9çœsÎà48€ذ:ÂIÑX`¡!+€T¥sÎ9èRŒ9ç„"…sÎ9!TŒ9çtB¨sÌ9!„�9ç„B!s:è „B„B¡”ÎA!„J(!„B!„:!„B!„B!„RJ!„B ¡”P`�@€ «#œ�²€– R΄AŽA� AÊQ3 BL9Ñ™bNj3S�9�tjAÙ^2 € À (øBˆ1AˆÌ …U°À  æÀD„D�˜ H»¸€.\ÐÅ]BB‚X@ 88á†'Þð„œ STê àà ""š«°¸ÀÈÐØàèðø8>€ˆˆæ*,.02468:<€€€@€€OggS@–þ–ç=ý‚å'02310276;:?CCBl…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹¬Ø%ô B8FkF#ëœzÊýýžåJI`Ÿ76BU5À: š†îK.Þ[/IÀ´˜˜€Ž€ ~ÊýýžåJ¼çÛJÙ@!TÕ€ €z wPˆ{@Û‚š_,ß5ðè@ 4>ªýÿüå žík¥°@!TUè40ÑMtô™àÉÆ+ÚÙÁ…WÇуàÐ>ªýÿüšäâvy¨…PU¡ô…|G×�OӱЂ††�ÊpBÀ&€>ªýÿüšäîô4ª…PU'Ð@$¸O}�Ç%åMÒ;†:€ žä>ªýÿüšäÒ´ð&”ªÊ* @t𨴯ùçaï¥)t (4 ƒ˜šýÿOre1éM0BU 1>ÞY(¥ÚsYÀ&-RJgè¡ÕMkòØÀ‚VšýÿOr¥2ØåIØUUÅ@EO5š‚nE~IôÆÓ´JÊqØ)d¢U)°$ @šýÿOr¥28åMèªÊj ÌY�¬"æeç…d×Ôdþ‘òcw¢ ±“¦‘€d :šýÿOr¥`°Û›¸TU:Ì]¹¤¿\Ïô³\ÏÒ{QFH4¬T05Þyýök”‹2¸ÛÛXaE…P + &EÒæ^ ô#©”¶&Ú!ir}Ï””Ωaku¨“)lY �‚&˜ HÞyýök”‹2˜íMP*jT¦Þ1{Ã�1^_Y•¢~vçt×ZŸ}¹.ó­¡£ª9“5\1á)èàÁ_#ÞyýÿþåR Ny“B1ê,˜r(¶Øò³4ptmp sR›¦£L/g9‚èÞ?®Í0—M)°”,ZýÎu¹ƒ‘Þ8 4´X‰ h©u À÷ßÒ‹ö~>S£Èü†ý$=cr¦Èß7²ü¼öŽ¥ÏÃŒóù0ƒÊ«®b¥*¯ß·þQ�ÿŠá¨Y4®#öO¤Å± Š«=¡ P{údX]ÎÔýÎ59 £¼ „f)6ðÖ”³A`fœ“€½^�Ä!ƒ<©¬˜i0/d¥·?/Ôh³=é«m¤ò¶Þ­™ž��wÛÕZ:Ý–ÿ‰�^®¦×Ö‘&uVwû’CÅ_Åjð-˜mŒýÎu9 %½ Ð"++IÀ@âÊAGÕ�rý5]óo”X€¯/sãÎ�\ú çHÇ‘ÙqoÅóÈÐ3ú.+¼ð¬qÖ\E�¬SF’¿1R-à"ç ÜI¦ÏlÂjÂɘÌìæˆýÎwÙ4-= Ĥ¼ÌdÀ¢ÐIà,1æ8‘qü]âj­_è÷⥧Թéô''ïsçõu|‰ìwûæ¹ÅÇë�³Îå‹�/ó¡<:�0ÑÛå$¡Í½'—3Œˆí®�ý ýÎu9q­< B¡¡ËÂÉg�Pà€~57kg§P¿d´]�ÙÛü¹œÎo¿’_Ú¹Js)êã5÷Òä¤Åp–ô•õÚc\^;Ç¥QåtFôbˆ[D®áì §­“ýÎ5¹ƒVÞh’ʦ¡°@vv¿´ÄN˜¾d ¦²²Ki*¯u67[˜`&· 'nV‡§¯‹“ËÈcºt“Ÿq’C>-VþFŸÄ¼VÙ ]êïtGNÊy49ªéaœÙMãýÎ5¹ƒä�¡Xd‰‘\%`8�'\àÁÁû5ô�7‰M?/'x‘,ׯ×}Y¿Ž½nmcfFU)¸¸ð“‡0ÙëÞ¾ÕÑøÚ��·•êP[©+T²ûë¼ý2š\ÍüÓSœ ÂG.W¹èX©;·åUFÀhkôo†FØ/÷àÂu cÊ:ýÎ7Ùƒ–Þ8€˜š• ›0Ød7•\´×vÎ}ií½E«MÝ M3‹Š"äðºÏ~µ½b³¶#Ah©'òR‚ÑÖ&y,]~�MG“-9¶#8…þùäë¼�#s/yýÎ7Ù8ƒQ¾1ˆ•Ö%ˆ8€iup;š¤_I5…ÀÖÿ?»ØÄ&òÒµädu¡n±{½ï…é!‰Ÿ»:•¬Ï…úzÅU.25žBÉ–+Êèq0ïîQ®*/CUë&^ܱé-ýÎ59q#} „&å68ZÀ€ôлt3ü´WÜ™ohm™äP»-¨Y?Ç{ž°êŽLXø8&MöØ f%ªO©›÷NÉ”‰Íͯ®b¢ì½›ìÎÈPw¡ëWI;–ýÎwÙ(ƒ–ž„*hRdÁPL�Kºá?7œ�I—»B��Á¦Ñ|_O&±arúäºvQà$¹k×°d­Áå²l­Lc/["°R#lcú,èVÀÝ�Š…«äàHïbz¬Û{8˜TýÎ7Ù8ƒQÞ1ˆÉJQ3=HÐi—� ‚©æÊì•ä¸óM6¿ÝRmöµ|fê «ö’ôÑZ*Ìü(NbÎÑÙ&ç²ýÎu¹ƒ–ž@-jIÁ…&&èh‹o\ˆœ‰[¢ÆüJx2ÝÏÚ ^Cí7^:«YGcF¦òO}žÝºž‡ƒž�™‰°±<É~¾¬2Pâü"SÔÞ‰íõªÀö™!Gæ&ÛóS’‰�ÎI…¨ýÎu¹8ƒQÞ(BÌR¬H¦Ð‡YB,ƒ’²-oÅx3CT§XÈèòßÑ| éÈÓùÆûѳ^^ª„^‰)5=‚%G½pïb€{fy](€>(Ö÷:;ubjÙ:kGG:OggSD¬þ–ç=‡¿²¬‹‹‹‹‹‹ýÎ59 %½ ‚”. :>�þè]µ¤?÷TãÌxL€çsÔ˜žM›PÏXšÁ„—+q!^#§ÃaâèÑ|S«ã.�„™ãµ•«Q®%(Îsnå¶©lõ]”N-{~ýÎwÙ8ƒ™ž0B“b…qÄñ–X9vñ)l}¬Å¼�b‘Id=!û…t,W¢7Åæÿ9±¸õñ­Ûÿâ® Rñˆçƒfƒ©ÄÀoé<ïËÓ—·§¾UÚe±”׫üpõ0Úé[(wÉÎ"…ýÎu¹8ƒ–Þ„2h–¢"hrðÈ)=|éP›Û"ýr:Iò"q�ö°Ì˜è¹¨š¯à޾Rß"à€"«•uÞ½‰ þ¹Ú‡¿š.øAsñ©Ïˆnµïn7…£'òèeŽ~ ýÎu¹ƒÞ0B Í c@2 °8èä>h»ï_6ƒzyu—YÆü|$Ô•»¹Žëö¬ÊÀÅ…÷ñSìÙ n'E²0!¸¶²ö>~v3üayè™zŸ›9óMÔk ¦1×5„éW7ñ#ÞežÈiýÎwÙ8ƒ‘ž1h–bÞFh‚¦zmœòp4<¯å²é*é´ ´ÚäœÉ"N¨„ªñ|oâSðjl’ÌôøœxŽMqIß–Š'S´Î—WøKw®²:&U0TÌn;�‘bbž ÆPÈeýί² 8P‹<Üà0P8�Ó¹­j xz}]�Übeetbox-beets-00724b7/test/rsrc/full.wma0000664000175000017500000006440315253035401017462 0ustar pieterpieter0&²uŽfϦ٪bÎlšܫŒG©ÏŽäÀ SehÄQ€>ÕÞ±��ÐtÐÊ› € € ôµ¿_.©ÏŽãÀ SebÒÓ«º©ÏŽæÀ Se4êËøÅ¯[wH„gªŒDúLÊ”#D˜”ÑI¡ANEpT3&²uŽfϦ٪bÎlB fullthe artist@¤ÐÒãÒ—ð É^¨P–$WM/AlbumTitlethe album TITLE full6WM/ContentGroupDescriptionthe groupingBPM6WM/Lyricsthe lyrics LABELthe labelTOTALTRACKS3WM/Year 2001 DATE 2001WM/Composerthe composer(MUSICBRAINZ_ALBUMIDJ9e873859-8aa4-4790-b985-5a953e8ef628WM/PartOfSet4*MusicBrainz/Track IdJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/TrackNumber2,MusicBrainz/Artist IdJ7cf0ea9d-86b9-4dad-ba9e-2355a64899eaWM/Commentsthe commentsTRACKTOTAL3*MusicBrainz/Album IdJ9e873859-8aa4-4790-b985-5a953e8ef628GROUPINGthe grouping DISCC5*MUSICBRAINZ_ARTISTIDJ7cf0ea9d-86b9-4dad-ba9e-2355a64899eaLYRICSthe lyrics"WM/IsCompilationTotalDiscs5 YEAR 2001WM/Publisherthe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104$WM/BeatsPerMinute6:MusicBrainz/Release Track IdJc29f3a57-b439-46fd-a2e2-93776b1371e06MUSICBRAINZ_RELEASETRACKIDJc29f3a57-b439-46fd-a2e2-93776b1371e0‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8atÔßÊ E¤ºš«Ë–ªè/he labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104$WM/BeatsPerMinute6‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aTRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aWindows Media Audio V8a6&²uŽfϦ٪bÎl2K‚ ]“‹„ç ç“ÿ@ ÓÃÏ6Ó‚}mà ;€¦Jà$´æ“$�Ü$›ì ?'qU1Ù1%¦4©€` -I$ÀIP�c Ô I¨�R„UI10U5R’I‰¸IjR` Ù$Ę@«JTBTÓI¥1,E4” ¦”�Ò’ÒÒ€I:¢„bf¥1&C›°` �³QR@H@1Všˆ`šˆ †€H “:ÓP@¨þ¥�KÌI^o'�»@*@˜7C²@ •ÂL À$¨Ä %©--¦ši!T€H””¿HEPùj�H@&B4ŠJJÁóä"„0Ò•…ý Sƶ°|µALU2”’k?ßí/¨/ß¿¥,B(âýqôŠ1BÒÐ~¶¶š-ÜKlø¿!+t„H¢�„„å8� H¨‰¡h-Ûߥ)B Ûô-P_”PVéCäQný"—év0{eýIBÒÒ�ª¸�V‚i~·ÆüPè6òµA \@ÑÅA KT¿ÚÛëpã¥k‰¿, ñøRѤ ­¿vÙFPµB(âó^®oã§�Íù»yZÀUÁ”P„ã(À\KYFP…»}¿÷o¤ÓM–Ê?_¥ Rýmøâ·> ·× p?,£ŠÝúð´à*à}Æý–­ËKx)~üþ°óyKïÒoéãýÒ±~ìù¼§(ðƒïΚÆó\yïû§ó¬sXß•?´­-ÿµ´[–¨}BÞSJÒ8øÇ‰9ïùå>Á·÷úýqº_ͧ‹õE¾±øÿ'~ú—è·ÑÄ·ÙH¢š_%úiÝM.Ê]ŸÙK°´V²ž+sô~_§`;t㎟ߛü°c[ŸOšã[t-·A¥ ·?ü¿|T>¡ûúBÒÓêr•¥¡”­ñññ-¿ý¦ÞýÙ·[–Çý>ót~¿'A·Ð„%lÓE(?º0çÔñ­ºi )·Ûé¥òßîÞ·C÷ÉnÀ@­å4qºR#)O½k(ZvÏ¿:< ¿ÊhÀT"±Ÿ-­­y¼¥6úr‘Å@[Á*�XÈù­~뫈3Xöü§=ÿtþ¸¿\n�ÇÇ‚WÜi⦊Æ=©(Y�XùºÇ[[¨Œÿ)ýùº?+{ !öt½/¿Khó\võ³ÇO„Q•+yÊ-�ÀU�‚[ucåYò[Ð0òøqà?5€ÿtà”¥Ä\úÀN‚‡Á§`0þ¸2š2•¥†{Qàx6š>ÀT—ô%ù¤º[þðü_y»{ˆ7öáæí�·ñe)Ê_y â × ºØì¦šàâºÆ|NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç§ ç–ÿ@ˆð%,V,XU2¼�ƒ¢ d†´µ°DôZb`°D€« ’ZÒÄ’XªpÍR/¸I… &`c †²X¬ÀH1…$Œ)1´ÌJI,¡•2"MK¢ ˜A2¢B`’*!&©JADÕ€ë$Ši�–„¤‰ E&®‘(hØ+D¤„¥!¤Á$ˆ‰``:–h&FÄ꤈¸l¶¶ ¬Üô�F”a؈…E„–¹‚Cv[0¤á@™�˜˜00Š&¬“‡)EdìEB��MCQ 3P ¾4R EB( ±JKô¿BPPB0è@„„[‘M/Å¥‰ Û¨J€°¤¬Rü¡`ËTþêOT©QcM¼�°–¿-ZZ¥hÒý nÊ-ôñ:\kaúüÖÓùSÇÅæŸ~¿×OóÔ~Íp; yHZÊ ÿÌ¡q!ÒÆ¸8风ßùÓG®/É ¥¯Én‡ïÿkHóHÀ_µ¼ýõpºZ…§ÂÝ”ºSÄŸÏóãüߥm÷xÂiÊ_;t8ˆµn®§òO8‹êÆ}”ñ~¸Ðit²ÞSŸ¿[¬`ÿ`ª¸pD†¸„såBÞP_× P”Ö=Ž·BÕc'(ã�Õcy®'ÕÁ€ÿoè¡ÿp›cóåÁ^vkL£þ_“÷KWQÆ·‚WØ ­ÛŸ×ÁV}F §=ð_×ÞSBÕ4¾ð‚,¥(À~oóÁ*ÓúǬlù-ÜvǾq�NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“¹Œ„çÕ ç–ÿ@“¹Æ_­mšVÿ b†­°&6¢ H7#@&RI($L™&ú»’@(Ó£" h&gQ‡0c "`éì “†2QyJB%,Dš€&`–ŠÈ¦S„ 2Ì@0’i jH”Ã*J ƒ˜1 (‚i¤”  $¢©Ê ÂJa0BJI%�¥­$X €H–„ëD§ � X©³B «-#@Á!¨JoV ]G@Ðc¼«-TËNÉéªÁ³ ±¥†®˜ªI1Q‘¹BJ…� LÁ’…€À$˜„îši¦¥@“JÄ- .ËôŠQB@~„HDBÕ%4ST�(@JIJØ¡…¥�¡òX¿DS+eóä!/È~•ºBÊ”#ö´r¦„QNâ}Jj—ÁÛ¿·­ÛŸÒ‡Ï‘@vxŠ-£ö4>~mÅÛ-SÄùm%J-ëU_qþü)4&»)ZVô‡n´·H~·ùŽ?ÒVŠÚ?'ã(O©@}ú®È»gÏÒx�·ùÛ­ô¬V�húâ yíúâÍþ5¿É¡a€é·þNÚœ!mú+ŸÝ(óKÏ’HÊCëzVÈB?YHâCÿ4û�ôûЏO›¥mb�Ë•½Òïíß´Ž5¤¾OéÄ>SùÛÿ*P¶ÏÉõª°Ï|€©ókvî%¾/αè¡8Í­Sû§\täKùþ‹¥óÝëq|·B7K­WOçÅÄy¾#û}ùùº_£=Ê“üåÿ›Z¥o(·Óo¬zœCœ÷·þøøÖ¸ü#žÿ¾$ÛÖ–ðéóúÓOšÊy¼rŠÆ[Êx‡šûÊi·×QÇû§Í[¸ÿ!ûü¿^t¶{~ø––‡šÏl‚Kupeµù­QNP·ù¦ªÞ%ù¢ŸÎ¸ ¥€NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç ç–ÿ@üð-TÀ×ß½Gé=õ¶4C $š DΠ&I�:MOü`áÄ´€6 ‚FÈuaÌTAc áA@a@-2E@i0–,P I$¤ÔÀh“:I‰-/�B(, áá´¤¥cRL Љ(H©JMDÉi@š‚ÑIQ¬6  Š†KL’™‰‚PL„ÂJRH4Ë@YP 5€" $†ÀÄ iJH`$°fb`liÌC`)Û¼Àç¿�޶ënæ6€¬Ë ¤†5@Lµ hÃÉ$‚€Ä¦�Š¥`+:H„¬QE dÁŠQA¦…€E-|ù4ýúh B‡ô‹ú(BA@Ú){¡kÍW 8–ò‹cÜCeµ¿ÝEx o)Á1”»/¸«õ€©tÿŸ%câG€€¸¿óvÿ5æ¿o©KêÇ(Ê^NNNNNNNNNNNNNNNNNNNNNNNNNNNNç2 ç–ÿ@b—•aEDØ%�­iBLA2d 5Ôf¬vî‰ �”Õ Kd™ @ :„€&*’’!¤!bÔ"f@‘.%©¢¬‰¨�ÀZ JR a,’CP†! %3U RDI%×Q‚˜ªÂ$HA@“0™(XVPÁ 0�¦¬¦¬,Œ"€*‚°‰@0RK¨вІÔL†„TH‰U% ± (؈ ‚þLŠ¢ÃUkI ͬnTƒbe‚.ÔÈÂT�s!¦éDư€ ¶Z 1`‚ � Ja$¬°Ù k%Ôœ±~ý™5|¤¥m4;jΗéM)$iH ”>R"¢Â“Y ÒE @[¦€Ä)( %ý55–ÖÊ2ƒJ¨·Qý 4!(?·Ð‡ô¦ÞÑ&*>âvÜkOŸ,)BR’µBi ¡i`·JRùú©OÞèEDÒ(ðŠ?K||PýúpñXüD`>'ùN}oãý?Oäè+T-¤Ÿ ·&Þûˆe?¼¢ßúã‡ÅG¸ñRø¾â§óþ OpøUSoÊ-õ(+\h}O〟¿¬rrŽ7AFP¶ÿ">„e]¾[âü‘á,¦�É¥inœ§)â¤V7[Ÿ~¸éE[ø©âGQo|C¥ø�’VÇ¿a÷Q€¿iGëöâÿä]>U¾%·ëeoÀ@Të…o)[[|íèýå'Â%·>óVÇþÎ _`’¸JÛþ+{ˆ®ÁÏtñþíÔ„‹š@óx6’ÿòZ·¥mOïÍ­%kÂ.ŸŸà‘k‰ñZJ|׿+�öSoý­¾£÷æœDqö·æò‹c­Ç÷”å ßy²·ûÊ2šàÛæ©®ÿ’£Â+Vúàʸֲ•ºàÇú[/¿YO|šióTÑOèÓ”S””ñÕ„ç·éin•¿ÊÝ”qÛ‡ínÝáÒr�ùƒûÊi¡6ô�×ê±ß‡mlv{qññå/ß[ió\kYBÖù?4å±ÒµÄùiÿäùBp°IÇù?~µžÈÏn5 œ¥6êÆÊºü펥öQ€©/øŸÛèÀ^iÛÏê‡ùRZ`%ªÆÏ|‚[u¿‹=�|#žß»~Rÿ>J©ý[ò‡ø”-q×óUŒµoÏ5”¦ÝžÎ—·`•–Ê+œš”[–­Ïß¾¬u§mæÿ�ÜNŸ¨®ÚÕÄ;çáÓð}‚QoüÍ»ÍNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“s‹„ ç� ç–ÿ@Äò²AP{õ¶ƒges@� ²ZÕ5¶ÁÉJ ÆØÄ‚Æ„È'´„•Ÿ H5 �„&*N¿ä‚‚’¤T`b J †BRM ’„ÀD/HIª*%t. ˜"ЏA2iT"DH ª™€„’‘†[Q%• Hª-ˆRL€ @hD ¦pB6@À"óe KPI º,DÍB`D@… =ÞÜÛŒA˜UÕdʆb eÄ@D²HiÒBI’�)nä,$JD¡¦—ÉX€ @BL³�4‡È%“)&’”�KúJ%lÓÆH¥ô¡!mÙ‰vÜa4ÑI/‘ ûðø¥n¡¢ªVЊÁ}ÇHCõ¥´-¡ú8Ÿ…¤P‡Í¥õ’ú‚’·Æ„ÐŒŒQEÉK°?°ù ·Ük°úˆ ñ:´-­§�)X>Z[âÊKyO…­QÇKûzÛçÀR•¥�äµEÐ8Ÿ?h·ø“úÊ2—éâA·¾+t¸‚ÊVŸþOÿTÖ„mߢž;z×îØãXÕŠRþ¸E->E»¼±—Ïé·ˆ·¾·›}»ó£ÂÿB„PÿÍ;~%¿7\=¸©£ø_í÷íkò[›ësဩ #=©ÊÚÞ¬ÏÂûu4¾·e."Pr…»}4­­3Ùýpå’›wâ/ÿ+{ünýq-ç½)•¯Øü¿\|x%ü–Ö¼Óçå/«ƒ�;—ÇÍþÖ‹¥�µ”e9C§Þ­?°µnóuÔ۰?´~¸ëLå/¸œC`.7Ï�ýkôégÔWÞ{~­ùGäšáÀb±øÝ/\JÌí½ýpþíÔ­ñV˜[EOËÍ×Mpe6ï[ŸæŸçÉnʳÝk=ò•ªRâ"?_·ø ÍÇ{->tûñe`/7û¬{pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ç¾ ç•ÿ@˜O3  -ð9²ÄÉ×Xá«£Z�¶A�¡’Ö)ƒ:�Õ’T««À%A€�$ªd„!±LA’‰ŠÌD IJÐaIJÀ¤™lˆ¥)% BHLÕ ¢Q%0&ª%0‘I šHX¬RŠQ‡ I4¢RDÐCe IiŠP³‘&Š„S5�$„�˜–š‚²ŠP”‚* e! A;©Ù”š�‡DTMPIh"PfÓ2 ‘†XVy“¶@ �Íæ$À‘`4s�0W–X[$á†HbgD“ƒ½$UlÀ„*$€‰«R’¶DBQBhA4”?&Œ© „¦¬a¿/�šQAD´¤”š"„¡û°þ„-x\‚R*Ð샳IXR툤RA|š_ r‡Ä q¡jßJGJh‡Ô¿¦Š©(·daGHÈâmÄÕBBÕ/¤¬ƒ¶âM¹øZ}VÜ·ÅBhâÍ~IZ)§(ã¢ßM ¡òM [®Ï�­¾ ®Aºÿ’Ý8ö(Z£Š—Ä[ÿTëNƒ€“ûý¿óX Ýnü£óº?/ݹPiM?´Ð) vå®*ë¸B/ݽóühX§õG愾 Iü‚h·×Ïwþz/7ÅûðºÇ ­Û¿vàŸÉ÷…q[ß[ë‚ÞùÀÿ7ù„q¾(â£öù´Œü[¸ð ¿ 0Th·~GÍ%ÿZÊ-þi¬ù&‡ÿ§Þl>[Àoÿ<ý87¿ËÍ¢—öêV¼×€€Ø?ýøGõù"œZeÒø$¥ý¹ý¸Ö7íõpq>q ”g±ã·`•?¬öýWç”çÊú¸2—ÿ´Ð³8·€³Û=ßà7õ�o·ÓÅÅ€­èEcù¬§ò®æ±£�ͺ}¸ðqú ¶ü…¸ ¶êÇÃæŸV™q Xßž® ÷ZÀh‘'äø¸‰ƒjÚÅþ 2•¤á NNNNNNNNNNN çì ç–ÿ@õõ1à E.üÆÍÐwa(,± ­ÇB utL(fcDÁ`�. �‚%�ÉÚI¨€�-”¡ H$�„H’ØI’S&$…RàI,™)¦ZR¬6¢ÄŠ`BÔ”„‚)Am)HF¨(�C&˜MH u�(”ÌÊ�T$‚tH )A((Q5S'üÉ�†ÂAQ¥I”3q†`$QD a·S57$À³-Ð%¦ØÜFØ,ŽË&o­2¼hÌho`…„2I4Èa«’ÈI¥ a楇ŠS‘蔬IªìÕJj!4ˆŠ · $-¥ôBÚ Õ Jj¿ã(ŽFO•ŠPŠV…/¸‹çÉ·„„P_Ë'È¡ij‡îÇþ.$:)âG[H(Z·-:RÔÓÇBÁõ½l[ÐùnßA§ŠÝJÒx–ê%(+@|ÿ)+’]šhZKì%/¸¿e?ºZ vÿÈPµnãÊV+šÂÜé|¥—õŒh§ñ…º€[¸èX i¥õ‘-U¤~­þ$ñ~T¿~µû¯Õc?Ài¥öS”PþßCáNâýù¼2Ÿà­;`>ý¾ð‡R-Î"Û©tsïÐù&ܶÿ)Z[3”¿ÀX%ýq­å/©Mü£öÓùO„Vè9E4å/ßù¤g·›®ùRšá«ùÒÿ(¬l÷|°[.‚•·ÙFUÒùŠ)ÒÈÏj_×êÜ·ÇûÀhðµ«vPµæßWQùºío�ýuÃáX õ»ŒÓ‘.P¶éd~·-׸ù¯6•«vPét~uŽâ'è[“ÅÅù-¥múp.—KìöOêßM¼xA÷ì')E6òâ/š)Ê?#nãvË_«r?\N–}€­Ëx*Ê?UÂø× Ýpº^±Ý-H}XÞn´ÇæéI”çÉžç(¢„eÃæŸþ`NNNNNNNNNNNNNNNNNNNNNN çç–ÿ@ç%ø,H¿A~”’Åð!½�f%°Ö�Åíz ÀXd€ �ˆ$¸uÕ€PÈ- ’P ’� ™©1 ’J ¡!5!µ %‰L€I Œ3 ªDCú¥¨–ja†“¢ª‚œ$˜ `©…T’$–¤„ ´ ™0 ‰ˆ ‡Y(L ™aP2Á-;*j@ É–U2PvÖT@ˆØ€€È&bÉhh €I �Ø´Á*†ZÀº[- �²¡Ä•6I6��É]XD‚Š‚£¬ò�’YC¤¬…� S PxŠPP MRH¦TÚˆ•¤ˆ ¡hJĤPì¾ ¡l-?B—ô»)ÂÙ„�I¦Š�ÿoË ËúM (¡&š2…¤>-%+eb”ñ?ã§Šßú¢“JÃ(ÅÇ/ß­/Ú]—Ë|r)¡ FRý%`éz™Yž4')¢š-ç�"Šx¿Iâ¡úÇÅnÀAñZZAl>}C÷èn[ý-£ô‚´°?§á÷Rùÿ.7õ_å?’+Íe  ¿Ê8‚ßhóU�Äø>ÇGì>À_—ê±–gV’·GçûÀT£`'ß–SO·þÏðSæ²…¼öý?ýe9A£ò|!Çæê­äIn¬d»wëC‰§ôýòÞPµ@JŸåÿn!Ý,µ”-¾ãüÖg_ñÒ_  ”[Ñ\cÍq`*-öà2Šm�ÁR8ðKæ�š[ãüÿ'ùí€ßÖ3ˆ©óO¨~´|"·ù­Q”q¬g_~O‘àT¤V6 (BÞ{ y·?¦ØàJŒ¤[ÿ+{¥�_Ïß-V7êÜœ¥6ÿËŸ¡Æÿ>Jk�+Oÿ/ÎÝÄýó¥¼ÀÝÅ€Ý/ù× ½ilà,Æé~,øF‹xüë(§)§�)A£´þ––¼Ýce.—ZÁ"NNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“-‹„ çIç–ÿ@˜_×I°Æ44¢{ˆ`ÙRAL—TĨ�É€RÆK@*L)H-`‚ Lfgb*T 1 DÄ)0™„IEC%0"0¶üeé@v%þv+"”�TÀ$Œ9J*T‰dDÌJBh%aˆuÉ5)(5!"ê l"©’Pƒ„[´ ¡%ÖM!¤Í I(©8A•Ih5jBN�  ™è‰Ñ æ[T4oa€ïLl�ÑÀ“ÛNκ0fÁ‰$�3¶‰)‘TÅ‚H¨v4B*0�DJ)(Ja"­C@�˜(`)!4‚iJA|²‡ôÃó oÀ‚Š˜tÔ,_ÑJè¡I|„RâùÛSCäÒ�A)|ù)¢”ºRíÿB_ÒJ·n[¥in(¥n—Öþ:V“”>|ú©6íSúL­»)EDÓù V–ø�±ð»z4?|µGå”Ón«s÷Ï©[GJ€RƒÇæÿ€þ±‘NR] _ªÆ·~ø€âJßêŽ4­>|‹u (·­#)¬oÍ÷çEo–ðV¶2Š*üÕ4º ý:RÐRø$~ŸÛ’þ¸ÿ^k‹‰÷q;ZvüKKOÿT¾[¡.�à|h·~Ñ~‰âqö„QX߯ßçn£¸‚âýþU�”q­,¿Í¡múÞSNSùQ”W (Ê?*Ç¡o=ߺ2Ÿ`‘nßNZã[Ïgë\HJßš}”V2ж_-Ûß­­"� ¢´Å¾›v �–¿+rÕÿF±íÃ=ò•§Þmý!5Àò‡ùC±ƒm¹Ä:?o¸“Ç€²—ôþNƒ‚JÇýþßÍÄU¯Í––ÿèüÂ×…-à;cÂÆ)â§õ�Gï)·Û³ÚªÛúmÁ4x +vúÓ—çæÿ.*”¾?¿åV=EJà|û‹ŽØïÉbšàý~¨ãt°NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçwç•ÿ@5øYà J•þ{l¯¿¢Í*ƒ'þX¾ 4ݵ2ˆ€ ƒ¦I €Öl�(‚ˆØCœ8 A’tMY$Rœ3(IK“N’ɨÂA: ƒ,LLAiÔ(&BAÃ2€Ð0PU( “LÕaI@$B+2„’š€ª %™(š*U$Å&I5R€�DЍ%Òì‘%!¨B�‰‚P!'¥R„Š£Ä % 8S!AAAfXPµF†F�PÒ"Û:Ëš¤9Ê�¡—¶&H*–b ¨iB@HBH ÂH@4”¬àUv@j0@@ %‰h„PýúI¥òÚ(¥Ø«I¤…´Š$Ë÷áÓDЍGªÝ?[&•¾7d»4%nÞŠ*Ò”¢� Ïí`…‹þ*_¤Ð¶8Òýihq­¡inÝú lZ¥ÿð´­->©ÅEº¢(é㦈HJxÖèâ[åªSJñ$£ˆú„q->·ÓOï÷o}æŸäKK÷ÿ™E/ŠÒmëOÿ>4SMøéJ×ìeHN¥ú]ÝF –Š?5µ«sëz_Ñoói âBº c­›}pùºP�Óñú¥Ð+Íe#)üŸŒ¢Ü´¶ü¾þ:ý McÛÖÐûŠ”[ÿiFRµGïõXùíOäŸ7žé Æ—áÿš[ã ãZBmâÝû·»o5žä?ñ'õùþo¿OòŠp?•6ñlzkR‘æÏ們Y[Â\DüËêà¬t&±Ÿñeå¿Ë¾ûÍçµ.–AÊk÷›t³ü"þÞÿôx°é÷›ýù¼÷/‘Åùà.?×å€ÿ\IÊ-î—[¢Üÿ�àðŽPúšÆ}Io>L¦ƒžô×Êû®H×ÉÁ/šÀUÃ\5�ù`<£xBŒ”~ÿvÇ‚éoÎÝ€­Ø%t¹ÀN!ÿ_µ¯ËÂÎ{eíÇZak=‹ìHNç¦ç–ÿ@bð#ÕØòsg¡uÍ"HÚ›]²ËÃ&;b&#`�™�¦‰,n€h$Õ«±I"%2C̘ Âpà5;� ¤™I&jÁhh@I-5¥0¥ „HJ" ©‡EM”ÊHÈKeÕ)(4Õ‰TH"”dVDˆK ¤B@NA¦fU€�d¤‚RN’dP–¥«B`È„¤ÄˆI %’Ì&\’K"Ú°7 T¨lžî…XK™¸HøcR%Q¡…›É1 !&bZLƒ@YÀ¤“2ÒHJ*! ™šP±Á¤¤¢“ XÒPL>J""¡ „�±4ÐE¤Rš( „>4Õ4¦‚�ùlñÐ’°©Ä”Rú i Kô? ‘ BÓõº2˜KñRšh[âÐJVç(¾¸Ÿ~ÎPP„~Ëêˆ}o¥ÙâD”¿(£ŠÜìRšÎx�±|ì%Ðic\ XŠGR·FD¥ð[êÇvÔÛËô[ÊRì-ñþ’þßBQGíij_~O�…º)Ïk}?°ù9M5QÇo¡Ø~‡é¬z´¶´ýñÅGä< mÏзÅot¤óÑñQáúMâv¼(Ûßþ¿IZZHÊ0(}‚»~®Ñ æ©Ê,Xëv÷ëyJGéiþ�•ª?<hÊ_å6ì÷âãÀyFãü’kƒk~$;/¸°çù`ÙúÏ{w¹Û~UŽÿõ\[\Ö5¹þ -ô,Ê Â| _—Ζý-§(Zü–�ÿŽÝ‘- ¸Ÿ~b¯?;u¸øEóðú‹aÂÒÖS€¿KKK3–÷HÚ;}pøCò[¢±¸ß罺ܵ斖ø°·>£òýà4>¬t?Æ¿*x°KûOïõ”:~ÏwÞoµÂ·ƒe¥¥«çKþÏ…­ø+_ÀãZ®ÈNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçÔç–ÿ@ïð*|¨ßW¯!¢e‚Bª( �+ÚlIƒ¶D5"ÎÀ2AVT˜ÑH10dACDÁKpŠhê[$NÑ Ú€I*ÔBI"Ä ¥¨‚F©ª  DÌ  [ (¡a ¡PH/é‚$È2PA�‰I(A‚@! „§¬[Q`L‚° @¨·PDU �ÁI Ñ”…I $A2CZLÈ2‘ I€2bR©Z4n¾Îúu†††BªÙ`›•l)"[«£¸Â@’&!bL8`¥¦PH1NØR”Ø:ŠKö @¥ Th%úLÕE, JP]‡eZ|è¡­¾vô"�àq>?› TZãvôš8¨4~°î‡ô Š/ÖŸ¢ŸÛ·|“\/ÊÚÛê Ó÷ëX*(JÚ”ñ!úKo�‰ BÝÆíé4¥úÕ?¥¸À\Aò\?¯È Ò”[‘A·Ûß­åOR+… T¡â§÷”бý~T[¿_§ütùºEGô­Bmÿ¤¾}n·~x �[|ž$V5ºŠ–¼#ÅžÏݶ -Ö÷ÖêQ\ À´·æ­éZZ¢ßKþ5¿ÊßnÊ¿'ÕŽì­e)[üÐþŸÕ¹ØoŠÝGæ|ÞPµ\Û¨Ê?дýnÝžéýqдµùà”Qá×¼>üòšàÀ^j�Ï"9jÜúž:áÊ~–“”ù£žØ ?—åùå6ÿÚÝ¿­$'ôŠÇ·­[¿h¥k=ÿ4W„<Óˆ«T£Ž‡ï³äâ[¢Ÿ×ë=ë¸Uݹõ¿ÍÖ1ý8‡Áµ$Zq _¾® zاͭҊkÞýÐV’ýn±«„Q”yº_× ÏpûÍþ°Là'Òú…¿~te/ÝŠàÁ¶¸2€NNNNNNNNNNNNNNN‚ ]“ç‹„çç–ÿ@tÇ€€ +WÕ7÷ Žø;!¥„@è˜$I¬Ó*ÆÎÚ–€Â�„bálˆ.dD”P"ˆKa$Š¡!¤È0Xˆ„È�€X„� I" RQ)&DÓ J ‚V “`RÑÂ(EIL��ÒVx1TÔAL A& €°BeˆØÙbDP³„¬@T¤¦$ÀÙd´B!"¢V0:5Du¸"J$CH’@f¡�›$LôÖImELG`ã™,h,fö¼I!®»€„f‚„j2‚� B Ã’�P@ªtŒ*•Z)4&Zù&¬P�V)JjP‡ácBÚ’ ”>&‡È ¢ªÔ—d-¡ù¤Ð•ŠêŠ)ã~VñÛÓÆ¥ùã¥ð BP?r‡ô5JØã~„SQlˆ|�•µªVðTÿ#;4-”¨@ '‹ŒCê´¥õ!ÛÒù&šhã„~T}~ÓoÁRÆš8Ò‹zݸ¦€_,S”[Ÿ~Ö²š8¸íÖ쥨£Í¿K÷öÿÍÐ(·à'ïÿ+æëò)óO©Zt·›4­%#öù AÐVoy¥¤þgŽßXÉâ6즜ö§"T5ùù´qÛðKJ­?·‡ß¿Ì¿[üÂ+�$£~k_�)ýqe ¢Ørú‹tà/Û¥Åð¹oo‹õ¿ÏòtýnÁXÕÞþh×p>ótþht»ü£œ^n¢0šB+¸�?øFœ¡(¥òßš¥.–�áà8¸xèMc­y·ÉOš@NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç1ç–ÿ@ð*ÿ—ÚÞÅѳò.ÔcÕ� Ãgm ʳ53($”²2A!²0Á«!—6–ȆÀEI  Ë SwT$,D¤T€KÔŠ¤0 ¶€)‚”¡´@!² hM@‰¨Ó„ Âp’u Š’ "“%5@�HHË‚BP†msI€Ù )HAЈÃu²RÂ@:%�AJ˜p H%¦"MÚd¶a¬ÙDÉ`$À�¹a[¡F64\á­¹�cPeI$’Ð�ˆ-iI „¥(¨„:BA€±BBP/Â#dЄÒþh ÑCåˆJh¥»*,@|ˆ—A)ãM)BÔ"”ºM.ÉYë\KA# ñ4%ÙÊúV�CO…—ÆÞ•ˆ[E+ð( [–ß"ÞµE¹Ðq[Ðû(¤Û²”ºš xÜ•¤Ð_Úi}ûZÏ|?ñ%«zÚ?hM¯Ý N–~ýiõcÛÊÞ{RýjÝùû¦š“n®?ñ?5Œ+±�mØ cæé·-¿À®$Ò¿t`‘ù.�HZÊV¨ý¾ý-!."e%kB ïË�/òŸÕ£Â+nƒ‚JÇâ¨)}nªú˜·qñ‡ët% £�ò„‚;n7ÔåÉ Æ•«pM å°(C°ì¡4�&…º <`R·\CJméK· Ò‡ø+·%ù·?|¶EKv “ÅÅRßù�ìŸÕ OÊÙ@Ê)"šr…¯7Jh|µM¾„۸lj¸ãñ-P•¥¥´¾·å!ý!h`*àý¤ŠršàGî…¾%®1úÊ2‘û|—ÞjŒƒh}oZ⦗Ͽvëy}æ�x°꜠g·P•µ‡¿òóYFXþIYœG€€xÒ¶¶·G÷ÙM¿�ÿä ?iÊ0æK§þ$[©q”¦‡k�úM±Ã�/ø¨·à>5™Ûr-ÕŽ�ßä‹zݾ‡ôñ—åm (ÀX6 Ö7cà0þØ÷Ëo–©ó_¯Î—Kñ­¿Ê2œ¢ß€�,·‚ZõÆŠà·çµ([F{-ƒì¥Ø­1E¿=¸‹ˆ¸$tµ»ùòmôÿ>é{zE9­ŸÓÿ­çºÛ¥’þ¸ršátÿ\"Üxß¾üÝ,@â}lu¾Ý”qþéFQ‚L§šá[ZHNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚]‚ /‚ç¼ç–ÿ@ ®q~&<ñròX$é|N¶t 2æîò³²Y ÁÂ- ºfC«¶ˆIE@A &L$�"©  &`j”Š‚ªJ ()J&¤CHJ*˜�%W 2P’d B¬Ua P(!%"ªID%!ÔA0SQ2LH!-~Ij¤ƒDT‚$ƒ0t€€Â „à±*‚�,H�ÐÁ!Öš¡°Êº©-“ÈÙBvƒ2u²DÁ ­ªÐÐ –ÁÖ¤‰�jf*F¾ êR€ ™|ÊJHK* š„$Ê[Q(X„€™Z(€)% 4Š©AL Òü‘8TÓV~•‰¡@I \O€)…·š•M)JSJh¥|I¡l%ÿ²�K÷Å)ÓÇE%nÍ©%õ%&ß–)+UiK²’x’±·ÓKÿÚßõ®4¦ÞOé+o�„­H¥+gˆññCïÒü¿Ó”¥öSÄ´ý4ÓÆE4AZKôå?—Qo·%+iâ6ôÛÖÔ·å$ÒCÿ7€íëa>mk�òã[¤ÅÇú¦Šxß`.?Úk…m+x (}”->Êù­þ_¡ú|�‘*×¾œV=+’Þ¼è/²•¥¯Ù¥_¿Ï‰ÐV²•ºá[·'tÑ”?·à<§ÍþN–t¶Qù[üÕ¸¾ý!jP)G›@æíÜ·ÖúÆÊ|_’Û¥ÿ_µªhŽ*¿·e¼ß6ãæ–ü#ÇÆþÞ—ÜyM;86-SùþKtSCô¡ú_ÛŸ8†Á-›¥“oæ­Î”µÀü¦¸?Võ¾>3Oç€�›ýºYOº—Ô¿|’Œ«Š_¬kƒùçüž r„xAv_·H¤-,iª  R…¡ —Á/ÍeO¡úÀ¦š ô…ªiKòM4Û�(ª´ÑA AâKñB-ï¥ñ|$#ö¶€V¨©üÊŠj?hãýÓJRVݲÑK²ì% k@P´¶û÷ò´ŠR—A+i·­ÑžÉ¥qŸÐÊ)ÀVü÷}…” å(~•·ô~c‹=íÈ¢œ‘Xè'ŠšÆýŠ_>¬jÓ+O°ñžé 8 Š�ÿ(§Íe/Êò” QCäÒµZf‡öûwÛî,û)}û£‹õúEõ¯5\4£ŠØî/ óyGçBOço·~Yïžÿ¯ÖÊ<ÞS”þ_“ˆ¼u�XöÿÕc'‰."šÆº0ÖÊKˆ¦¸-é/³ä§=¿YJ8‘Xÿª+†ßXÔ8†¢±ø’ùmÄ7NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNbeetbox-beets-00724b7/test/rsrc/full.flac0000664000175000017500000005260215253035401017601 0ustar pieterpieterfLaC"÷ Ä@ð¬D!îÄvoWeƒ×l°÷�� reference libFLAC 1.2.1 20070917 TITLE=full TRACKNUMBER=2ARTIST=the artist DISCNUMBER=4ALBUM=the album TRACKTOTAL=3 DISCTOTAL=5 COMPILATION=1 DATE=2001GENRE=the genreCOMPOSER=the composerDESCRIPTION=the comments TOTALTRACKS=3DISC=4DISCC=5 YEAR=2001BPM=6lyrics=the lyricsgrouping=the grouping8musicbrainz_trackid=8b882575-08a5-4452-a7a7-cbb8a1531f9e9musicbrainz_artistid=7cf0ea9d-86b9-4dad-ba9e-2355a64899ea8musicbrainz_albumid=9e873859-8aa4-4790-b985-5a953e8ef628label=the labelpublisher=the label?musicbrainz_releasetrackid=c29f3a57-b439-46fd-a2e2-93776b1371e0�˜ÿøÉ•@µÇ!Ì¡'†hPæhRs%… $¡aäÌ̔Ô9C9)™<¡C™”ÌÌÓ%8Y”Ÿ)…% aœ(r’‡49CL9C%RY’Ì<ž… dÓ ”)™™œÎd¦M 礧2…&yùgÐÉågÊaá94�% L³9œ(Xp¤¤¡ÃB…3™e% B‡ ˜D™¡= ¡@³ ) !ý Ì’˜s(NN’…2P¤¡åe&faʤÐå3$C'3™ g$³ 3”%8RS%™"Bœ,’” IC„By— °ˆaNˆ”„Lä‘ ”Ê”¡”’yC“2i…9ÿÿ¤¡a))™B‡ f,0©@¦„¡IÉþ†Re ¡(XS� …†Ng:OCž†s¡C™C<3Ì4ÉL(hÌ9å”)“"))(Rp¦Jg3™™˜S39òÊ�I’‡?)“)9C3'(e äžPÊI,)(S L”)'&p¦r†œ¡Ìáae ”2P)2�HD%B†”†Je2yB„ˆP‘‡‡(~y@¤¡4)“L<™2“¦K(y(”2“‡3ýPç)3™™”)<ÊaC˜R�¡g)“)3æS0¥ 䟔ÉÒ2d@°å$晡C…†s,Î�C“™ XzBœ)™’�a@Ò�¦�ÌÊÊI伡I’‡%0æRe'ÊPÉB’PÌÃI”'&RP”2yNe2 ‘ 9ILÂ$2™)"% L¡Iš”þXRe&P¦pˆ(L¤þ†r…Pæ…$ò–,2’Pˆ”2’g JÉ43š¡CL)™Ìó”3' Ðå$C„ÉMRS%330%3 p¡I”2“†�IBr’�aÿùL’™2“ 3”É)'œ¡Ì§= ’˜x|)C9'èe$Δ dæsÒ$"I…9ô” 0§2̦g4) )(J¦g p¦fs)†œ¤¡…™¤ˆLÌ“ÂPçÐ)’„@ÐäBr� D…„¡á¡’�¤¤ô<'BP,(g(aaNÌŸ)ÊC930¤“ÃÌÌÌ)(RrPå0¦L¤ô9C””9œ¡Â!™HD fJ ç ÉB r“L‘$èg= 4Í ”9ÿ<¡É™™Ê<Ì™L%”’JL9ü¤ó9™C™L硜¡IB!(D9™ä§ L¤ÒS%2RRPСáI…†i4ÌÌÊ” fr’r„§9HD93ç@Í Ê3ÐÎPÌÉ™™™ÌÌÌ‘r™% 8d¡ÏBPÉÊLó9)C9”3’S32†JdˆL¡Ê¤¤¡Lá¡Ì")Ì,™Iè””90áÉL¦O”(g e&Rt3” D99I¡IL4)(y‡(g?@§ L™I”Ÿ)œ)Î�IB’‡))(r†PáC””9Ë sL2’O)%(O<æJJJJùÌÌ,™I$C!L9B„ʦMçB…‡(e$”¡2Â…8y”“çåŸÿ‘L¤™™%0ç”)'�IáNL)3å I™’r‡™ �œÊ)“L””ádÌ”š9�'IL”””9II)3?ýœ(g…2R†fLÿô2“!(D ™C32Jaœ™L,ÊJ˜rfH„ȇ“<)™…&hfPáC…8r!9ÊJrPˆJ”Éèffd¡Iå9¡B�§ÐfxÿøÉ’@µÇh!)œ“4)2™™œ¡I™™Âœœ¡ÌæfH�¡™L3”3ŸC”ÌÊå&s9Cœ¡IB“ÊÊàS‡2D2RRP¤Êý ðÊL¤Òz:†e Ì™çÿ¡Â$Í B…�Ð"LÄ2S„I„Iœå&|ÊLå&P¡Ìœç(fdša¦M™ÊL¤Ê”(JLÌ)(S'2PÓ g!d–JfP¦ffLå$§ fL¤ÏBP¤¤¦fK3Ì¡BP¦aIÌ”)2†hg4(hD L¡œô' S% r\3„@°Ïå&PäÊ"žILå p§8D9™ÊLÊœÎffaIB’…% NPžaL”)(y(S“)0²aIÂ’…' J ™ò…&P9@ær„§ fL¦¦M… LáÈ�N(RfP¤Ï(RP¤ÿ‘& Έd"rfs9B“™“òœô(Jr™(P� Ì” J¡œ D”)™”(s'3œˆ¤§‡3ЙL)3ÌʘYœÎPæRe2JJ’På æ™4Ô)8P¤ÎfJåž’™""ÎS’’�IIB˜p§33%8\9žff4e$ÊIC„I?(RaLÃɦÉÌÌ¡IžS…9È“4Ì)Éš Nr!(RyB’xJDPÊ99”9ùe‡=0ÊLå…%™3™ÌÊ™¡œ¡Â!(S&RæaJIáœ(S'0§' 3ÉL”)̧ dó‘ žPæg0‰2PÐÊL°³B�¡’PÉ”šg>i'Bee I…8RP¤È�Nd‘ œáNLæIL(Rg æS% ”�ˆ&JLˆIC¡BPˆJhPäÌÊB”“œ¤ÏŸÐå%%% ¤ÊJaÊB„ó–r$™He$ÉB!†™?"Éʘ~s”3™LçÐ))ú(I¡ Rg(g0‰3Í’ž†s¡È�BÌ4“œáœü¦ffL¤œ¡ÉLšOIô9CÃ2|ˆ%PÎ ”Ã)%2PˆJ ”(p¡C9333š…0ÎhsC� œå Ê,ü.)=!å ¦NRg” &rPÎIfg0Ó'aš…“3æRfe B!3™)˜Pá@²J8PÉ |ôÃ(PáN†PÎJB…&PáÎae%32’~dBag2’|¦s@‰0ù™’˜S33' ” ”&D'0²M ”(P§9Cœˆ¡Ìç3œ)")’!2!ÉÐ(RPô9èd¡Â!†g(Re'ü¦JB!HS)“)’�L”)8XDe0ó ™”)2“þS'”Ÿ)2“”ÉùB“2“úfs9™C93% ™ÉÐÂÃ)2†rP¡L”?)2… æ'ÊL¡Ìå'¡ÊsÊdò˜s†JIL”Ì)™2!†“3) RLò�aILšaIɲR‡&sœæH… LÌÌ”ÉLÌÌ¡œÌÐ)(D39%'¤"‘ œŸ”2S%% 礡I”ÉL”3’™™?(S0РRgŸ”Ì”2P¡)ü¡É”„@Œ€D…„ÊM0”Ã33&“¤¡Ê™'ÊJ”™ç)™’†Éœ(2e„Ê¡ÏÊNP¤Ê)’g%„ÊJœ¡2!“™’†�IÉÈ„ÊY&’t&S$³,¤é†…'% IC% ¦™”8“ÿøÉœ@ÿÿµÆP!9BR‡™“ÎPðå”$ò…'3% ”šdˆp§&†NfaI”ÃÌág2’eB„¡’†O”)™ÌСÊ”¡œ"9’…&i)Ï"(fg?C'ÌÌ™9œü°ˆ@¤ÌÌ¡œ™C8D2p¡Îfs9œÏ$Iœ°ù”…2†s rP<“9))"˜xL¤Ì¡Ì.I¡�‰˜RR†r„ô œôÌÊ’” JH|¤ùgÓ0¤¦e áLÊI4Ÿ”Îç–ÉL,"8r™)’™œ)3I¥ ¦Â!™…“3„@°å$ÊL"ÉB’ŸB„ÒI¡BR‡�‰™“Bae2S’…2O …(M ”š™aNfe…% r“)%$¦)(ú¤)(d”™ó"y2†…'¡’†L¡“˜\žRe'”(p¡fS „¡¤ÌèfP)™(hd¤äC‡¡ÊfRdBe ”ÉòÂ’‡)4(g0ˆd§)<Â!„I<3’…&yB“œÐ¤Ê“ÉèfPç%2R�ÌòÊáBÉ™”ŸÐÂÃý&…&t�0òtÉNL¡Ì¦r‡˜RS aä:Ï¡’… Ìœ3C9C9$C…3$C”„ˆ™Ìó dÍ'L<”)2™œå$¦IB�æfrD)ffg% !JCL9”3% LÄP¦NM0òP¡IœÉfL¡Ìç9C™™C9œÉÃäÌÌ”ÌÌ”) "™™’”š™¦˜g(sò’P¤,Ê™43ŸC'™Îg3™I”™L„LŸ)™:ž, ™I¥œ3C')’s$@¤¡I)(S%2XD$Cœ"B”9œ¡œœÏ9C 9ž~Y¡C˜S… Ð3�§$¹œ)“™™œÎPÎgå2J“)(r„¡C“2e%œ2™†…%™")œ¡ÌÌÉB’g fg2’rS2�áaœårD)3‘„B„ˆPÊ™C”„Cœ2““4ÉLÌÌæyÊÉOÐááC38R†rd¡’…'8D9ÌæS!°"dèr’…&2e%PÊB‡“™2 P¤ÂžS…9ÊNPСə)˜Rf’…&Rr!C”(Rri…2s2RP¡ÌÓRtšaä¡I(p RfP"9Ì‘ ”)(RO% 2D9™ÌÌÌÌ¡L™@ç)œË3”3“™á,(hRC (žJP”¡=ÉäÓ åS3œå æe2hPç (d¡’“"�r!3ÎRg(L¤ô̦B”“ÿ)(ICý’’‡…&|¡C“™ÊÂä/”™C“(s …|ÐÉü°¤äB| (Iò…&r†�)™9™™)?”ÌÎ}“‡3”<<’…!BÉ”3Ây™”9”ÎdI'”™d¡¤¥ Ê9BrPˆ„BO’ F,ý ”ÃÌ9’Ê“2rS3%%%% IB�¥�fP,:R†B%…�JI”3%‡3(g0³3™")’™:JfP"\¡IŸ2’fs9™‡(̙ʔ"IæD) ™>P¤(RrR�¥!BÂ’…$”(JPç¡IBÌÌÌ)9™™™™)(r“Òçô'ü¦aðô%Ô̔32P)3ÏŸ(y…2p¡Ãœ)I<9”9™™™)™Âœ(S3™™™)’˜S&D&D3„I”Ÿ)9I”ÈD˜ÄÇÿøÉ‰@µÆè!339œÊað§ dóÎfaÊ!�s LÐÉB‡ N“L<”)8g?Ò…ÎP¦L¦JP”¡4(JBa&P¦Lä@Í °¦fM çÿ¡Í L¤¡”38Pæ…&RS‡˜g=De É”„I”3…0¦NJJHD)9‡’Y@¤¡™å2P¡áäœÿ)(L¤”“å9ÒzM0å Ì,Ϥ(X&xD™”4 J)9’™’„@ááe'I”” JÉå2|¤¡(p¦NP¤Â!Â’’…P¤ÊM Jfd¤äC'30§!a”Ù”8D8D)(Dœ¡)™†R NÏ)>èr„¡’�L™@ÎL¡Éæs0¦aIB‡“ˆL¤¡™™‡’áB˜hD $ð¡I”Ïœ¡™)™’ P¤ÂŸË 9ÎRg33338S3'333$C'%'IÒP¤ðä@òdC338D4(Y3”% “2D(JJBP²…&fffp³ p¦e J“2Pä@å%(OPÌÌ“ÉJ™)’™Ê̤”™IÊd‘…3 fg3™ÌÊ¡œÌÉL””ÉLɦ“å2t °”ÈDÉ32S&’†„C™ò™9L(D% ™I9„C%'(rPÎe&S'¡BR�ˆs:œ)’Xe&r’e!¦JaL™IL–g9C„C'2S dä¦yùL<…2hfp‰3IÒt(d¥ èÉÌ”'C &RM% s)2™(”<¡Î¤Ÿ 4ÉLÌ¡š<ÉÐÊLˆL¤¤¦g dÊ™“IB“†p¦N‡"8e Ì™B‡3ÿèp‰(æJB�‰“™™’!Â!Iœ¡ÌùLÌå!9ærS%2S9’’†xs¤ô32|¦NPæRz9Êdé;&ɦ¤¡LÌÏ’’�ÌÊdèr†fL¤ÊfS3™ùNÌÌÌÌç¡ÎD’RhP”ò™:Ô93™Â™9™ÊNS$ГBe$¡H_üó9CÌæ’…&)“òœé(Re0§$ D”)ÌÊÉ”332S<ò…d¡É™4ŸèäŸ)“þ’…&RzJ¡C… ‘R…PÌÉ”™Ê(SPˆÉI„”))˜RP¤¥ ä”ÉLæRIILÂ…!O¡= ý&”'˜S$òS”™Ê™(S0¤Â‡ (s,¡Ê2fr’†fs¡Iš™Â!Îd¦M0òP¡ÌФ"!JIpÊNfs<¡aš,"Ê¡“æRe‡(Nd¦fJd§ 3™C%% B‡ =%RP¦g„¡äÌÉ”‘ æOš?ô(JÄ@°ÊM0ËHD  R š™ÏI‘ Ð)HR’˜Rf“C„I…)$¡ÏI¡N¤™I”” Na¡4(9B�ˆž¡43™žyC@¤Í äˆd§Ð¡Ìÿ)“ y'3”(s39™…2s L¡”™IB…!BÎYô2r‡3”3“3%9Ÿ””2zÎ�I’�ˆd¦ˆgÿB’S!IùL9œÌÊ̤”,>�`A“)%8r!)ô2„Ê|ùBÀˆrdˆd¥$å B– J™’™™æyÊ y‡(dÐÉBLæK32P¤ç)”%�èf‡)’™))(RLçÐÉBe&†y™œÌ˜e&)2’’†‡))(sÒzaòî’ÿøÉŽ@ÿÿµÆÈ!å” 0¥ B’�IBÊÐ" XAP¡2˜y…™L””33 Re BœÉL)’”)8PáLÌÌÎdˆað§2P¡’”% Có”3™Îd¤¤¡Í'I¤–P<ÃB†…32‡(PÎå&S3<9 0ærS%0¡IB™…… Ÿ”Ì” NdÐ)�ˆd"LΔ)3Cœ¤ f†r„¡IIBÉœáá‘ 43…2JL¦OC”š2S”ÌÊdæfg8Y’!™…2Pˆg„ÐÉB“‡‡%gþ~ÿ”ÈDÌ)Ì"pÞ Y…È\’Ê… Ð)(“ÃÉ40Јp¤¡IBœ…™™Ã”2�džáe ù¡&„…�òi(Rp¤¡aNH†fNaæg”9…(pˆ…™Ìæyù¡BxPæg2…!9Ìó$C%(‘’‡&p¡I™Êœ4¡”ÉÉ32P°ˆJs3%2i…2hs>RPÏ0¤ÊJžg(y2Â!<ôš2†p¥$B‡2fJfP¤ÌÌ”,)"&fsCB“Ì‘0øP²N„¡Iša)†Re3ÿ¡…˜Sž… Ðô”šd¡Ê’‡˜y(RIr8S39ÎRr…�ä̇É&PÉáË JfPç†�áLš¤"ÃB’œÏ™”&D˜D8e&’†…% H�)I”Ìæ‡ p¦g ‡PæfPÉÔ9IL”ÉIB“)’…&zB„¦OÍ!))(Y2„È„Êfr‡(L‰2’’ Rg ¤È„ó2“’M ”<�2P¡Ì–P,2‡ fPÎsÐÎPÎe™JË…8RP¡Ì¤ˆP§(faÌ,™C˜S… 3™™(s)…(JfRfK0§„„³%)‡Â™2†s<¡ÉÌæJ9”ÌÉL“†pˆR¤ü¦N‡"(r‡‡)˜Y0ˆdÒIfrS3<å&y™…&S32†g�NICŸÈ�¡BPÊaòg2†rPÏP)’”<”)”™LÜÍ…&fPç rap’Èr‡)(hP”å2PÉåLÌÌ"L‘ @‚œ¦L¤Ë J™(™(g&e ˜s%% ÊaðÍ ÏC”ž‡(S33'% J,8RP))ž†sB�f¦ÊL°¦OžP¤”)39CC”„B“9C„C™LžS8P‰ ç(g&PæRJa̤Í™”“™˜S2P°¤³330ˆdæO…8hR9C)&p°") PÎÌÎRe3�2S2“"…&g 3Êp§'(g0ˆLÊ… C$¡C…9C”2Pç)9œÌÌÌÌÊÊaÏ)™ÊHPáNdI„IC)2’’!ÉB’g�LÉœ3’œôÂ’…3' (J3CB‡&ffe$ðÊB……”<3… È�)èdˆ%% ”$ˆdˆR) d¦H�HYœÊaÎP¦aC33…8P°Ë f!Jdˆœ“Ã9ùC8D9ÎdˆL"d”Τ",,"ÎP¤ D™�IC’!BSœ¤¡=™“% ”ÌÎr“œ¤"Lç3ÌüÐÉCš™C””ÌÌÌÌÂÂ’!(S…9™Ìå ”’�IžP¤¥ ðΤ%0”) RSúÐááC”2“(S$¡H|3IB™’™"Í æD’|¤že'ý0øhD!0‰ s™™)(Re39”ÃL§�aBÂÊ’�á¡NÌÌæp¤ÊN™6‡CÿøÉ‡@µÆØ! (e&J2„"d¤¤¡L)�Ð,Ê)�ˆXRR~RNdˆNaÏþ‡9Éœ¤že$¡IÌ”) 2RD JæRO3” dÌè™Cœ²‡™)“IÐÉóç”) PÌÎL¤’˜Rs 0³ JI„C%9O&™)48YCÉB‡'’„HP²fH‡9Ió PÒO@³4(rO”œ¤Â&O P“LùI”(RPô&˜0¦g$¥J…)%2hd Rd¡I”$¤’!2 s‡˜y‡˜xffN†J†hNRP4åŸÓ…933&˜Re!äËɤô9C”9é†hd¡…’~S'9C8D%8DÙ32RRD NL¡”™¦J B$)ÊaN‡4ÉrD) ÉB†… Jœ(s4ÉfáNs̳)HP¡CB‡(sB‡'(På d§(Sd”áfP¤)HS3%3%%P¦frJd¤¡IB’…“9C)3ÿI)BJd¥0¥ ”Ìå ÌùLžPæÉÌÌÊaNLÉþ…&S39""ÎffPùB™™2 s4'BJaIš"(dÒzJœ”¤(fPæP°¡aB“=” ̡̜Ê% NRO2‡Â™™?@§ 9”9é(PСI”<šd¦r…“)(RS3”)3”32rS&’™,ÉCIÓ ¤™Ê¡I”æy”™IÿùC™œå¦K‡ÉIL”ÌÎPСä,¤ y™:)“)˜S&e$ùȆJ|¡aÿúaL“2z8s)&PáÌ¡œ)™’!’™)™™Be'"I432� FáL™Iç"Ì¡œ¡Êd§ $ˆR"LŸ)…ÈS3%™”8\¡IL¦™)…% 8Y(pˆRNIL%RbÏœÎd°¡¡ÿ”” Nd¡C“8e2P�!BÉœ)9CÉù)<2ÎS'ô(g&sÒtš¡áœèRp§'ÊÌç(ry…’S3Ÿ?(Y3”ÉJ“˜y’!žC% ‡<¦f™Ïþ’†„Bg%2Y’™†…%39’!“™)(dùLÌŸ”ÌÎPæ‡4)0ˆp Y� áB!3'3œá¤þ�N™™˜S<� ”ÉК¡äÐå%2„æJfp§ fd¦J@°¡NtÌÊL¤”ÈD™Â™œü¤Ì””)(S“(pˆsú¡”%3"òs(d¡LÉðÒ„ÐÉL”ÌÂ!HSÿþY”ÌÉBP,™ÏÐÍ0°ˆÉB™@³'33 dÈ�Êd¥!BÂ’!(D%&IˆdÊd§0°¡ÊJf™¡ÏB|ˆL¡3%… °¤Ë%9ÎR ÊÌ)™žS'Êp¥$çü¦fLˆLÐ,(pˆrfO 3œ¤Êa̤”É(Rs)8S“9†… OCž“"a”…48S2J"™4Ìå')“”2s3ÌÌ8S” (ÊfffLÊI”˜D8s%&…&S$Bd@¤¡IL”É)(S9š¥$å&RLÎPÎd‰0²ff|Êa™œ"™3(™Éé4<„He˜S2e%2S&’… LΓ¤¡LÂÂ……39IBP, s'ò™%!æa¡’�aLÌÂÂ!ÉÌ””Ìχ fg p¡IÌ)Éže&R~hD(L¡œ))“LÌ,Â!¡šy2k»ÿøÉ€@ÿþµÆh aœœÌÉB�¡HP¡Ê¡™™œôž…9IÏ æg332R†re ”¡É"Hy™ÊOèg?¡œò“(PÐ"LÎfaL™L2Àˆh&rÂ’„ÿþe!¤-”'"9L”ÃÌÌ)‡3¡™Â’„ÊfO”“ÉNäùó9œ§)™™…8S3%2tÃ)“Ì生)‡˜e&39C3%É9”3’Y‡)(hRP¦NaB�¡I(s)œ¡C”(|4ÉI¡)ÿèaf} 礗'IICšaò†hg™ð³3P”(y9™”’…&J˜Y„L2“9fSfe ”(J™ÏIèdèN†r™œ”ÉIB!'%™2†P¡ÉÂ…$¦M’�áBPçL”Ê…0¤¡O'BP"B„C% )�‰2…P¡¡C”�0"J”3ŸB‡3C9”¡<¡Cœ(y™Ê9<šaÏùæs3(g2‡9)Ü)™œé= @¤æe$æD2P¦IC˜hD% JJ2“ ™™(P”"% ”’™)™™Â!™™(RO&’… dòg9C% N9'Ês‘&i’™)’™)(XS0°¡L”"̦Oÿþ†eaL’‡%&He$¦ffJ%&r“ç(s9CÌÎPÎS$@ˆJ,’˜PàA B™’†Oʦdä@¤¡B“"BœÊL*"B™„C<…(S!|¤ÿèPÎLÌ¡œ”2S)“úç)ÔÂy„BP „¡B“ÉL‘„ˆPòS™™"3¡HPСäåš¡�‚™áLžI2„¡aI@°ô2’„Bg ÌÌ(Ráae á™HYBS0Ò„)“IC@) dô™fR�Ì”2R†fdð²�ä’!„²hP²äÌÎe2†Jr“Ê™)% B dáfe%™ÃЙI„C…(sÊœ"œ’äˆP”Â…‡3”9™œ”)2™)™’!Â$"&LÉùL“”’P)(PæffJf¤(D†R¤ž<ÃB†˜y…s„šd³8R„Ê“B‡2…�¨‘Ì”¤žP¤ÊO9À°¡Î†sC”„C… Ê44,,"2“¡I˜„ÊJfså3 J2S39ÂÉ”9œÎg(Rs”,Ï(rs„C’^SŸ”̡ aN!@°ç(O…)33™”8Pð� ç)0¤ä¡I”<”Ìßèr’’…&hRrS&†fg(hr„¡™C)�³$C2“ ̦”&†xe!Ì)’œ"LÿȆJPÎC”””(s4ž’‡"ˆa¦JfM0”2P)Â�IO”ÃOC”)9…3$¤™“32S&!“œ„I„C38Y”"(r’…“9ÎdˆL¤é‡’™"ÊC:B‡&dœÉá<“Ñ…”2PÉC'Ê™1 ”ÌÌ)(Rs332S’!“ÃÌ)2……8S%3(s?)™Í Na¤é4(ry)’Ì<ÉLÎsœ,™™™…&Ðæ…&S0¤¡CI…“9™Â“˜y(RR�ˆX B!(D%(r�Ê% L¡)Î&%Ì“ä‰À‰(R|¤¡0‰2e!Ð"BœÌÌÌšN†só8P§ p°ˆJH„¡aNÉ”æPáœÎPó'þ†p¦OÊJ(PáB“,Îe$üüå$¡IžP¡I…3™”8D32rS$C0êàÿøÉ­@µÆà!™”’S NaLÉ”””2P¤ú愞ffJffR¡“™)’” °“C9¦M% L¤¡Êô8D4(y:”3˜D9)(… dä¡IÌ”ç,"†PÃáèffd”™ÌæÌ̤Â!Â!ÉB“?¡œÊL¤œ¤(D�¤òyI@¤"%2ä,¡Ïò“4r††S <§2”‡C9IB˜s>‡‡&PÍIÓ �L™ÌÌÉC@ˆJaN¡œ<¦OÊI"%†NJJfd¦aœÊdô J„I2„Ð)ÙÌÌÌÌ¡IÌŸ?”Ì"ÉB„ÎI RPÐÏ 2D2S$C%2D&D'2†rs9…9?”ÌŸ)…8PÌÉžg9þ‡(frP‰ áLÌšL‚H�¥&S2„¡”(i’™œÊ™C™å L̤’&INJRBÊáÏC”)2“ÐÌ¡ÉBR�²’…'0§ s“?þe$.Oò™:%<°¤¡= ó@¡"gÊdùNt8D‡¤)Ê8r’�¥%% Ì)œ(S&SR B$2!“™”9‡3LÎd¦B$ÂÊfp¡¡B™)œ¡¡9“9žP§ 38P,¡LÌœÃL”ÌÎPæg(s™ÌÿÐÉC9B…% Jaʇ †™†RIL)“™…8S…3’DÉò™3”% JJáB$2„óúJfp§&r‡% B”’˜S‡å9Ó%$@ЈJPÎ L”šLˆp¡ÊJ™C2e39IB™)™’™4ÃÉLÊÊ2f} ”3(s4ž“èd¡’„ÊO)™™œý æ… �ˆO0òNg”)0ˆP”Ï„Lœ™™™™˜P¤Ï!32Ri(Rs% !Iœ3ž„ÐÉC””)2†Ra&RRD 2S'C 3B’‡"¡9@ˆs(p‚!N¤¡L„@°§”ɔÙ̡œœ¦g†rN�Iå0Í …'(På ó”%™")™œå&s„@°¤þ†Re&…!C”�$ˆd¡Êœ)™™œ¦eæH’aá‘&s™”9ùLœË æffJp¡I™¡œ‘ žP²e2S9@²…33�2På ¡BD9L))’™‡“B‡3B“):)<§†rs"„B™É)“B‡2˜S…9™™)˜RgC”)“œ"(D%&PåÌ™gÒP¤šœ"…&†J(p¤¡2$…Ã90¦(S I¦f!JND H�CœÊaædÐÉC”)“)=0¦Iæe$󔜈J”3(p RgúJÎaL™IBÂ…’R†fJœ)&dÊ9’‡3œ¡ær‡(g Ê™“L<”ÌÉL”‘ ”„BP‰'>�IB‡’|¡¤¡aÿС–IÊS!L�‘„ˆD2R†p¦aI”ÃɦI<”,(sȆJ}’…†Y2’JP2D)2™4)(S' ¡œ=Ì"Í3™Ì‘“™Â D…„Ê“"(d¡œé‡ÉФ2Â…&e Iá9(p‰ “„C˜Y@²e9Iˆdä¦J”3Ÿ9I@#0ÿ‘LÌÌÌÌœ¤ô 3èg(Rf“"aäæs”™C”P,94�fNRP)3(O3ÊÊÊ”2R†JaäÒ„¥% Òzd¦På™ÉL–fs9)™™BdBNz"= ¡Â!'(Pžt(XpˆJ@‚¿ÿøÉ ª@µÆ� g™Âœ(Y%„BP‰% LÊ“(r’…2J™””9C”9Ièg(RP¤áI@³?ä@æNg)'œ)’hd¤þ†g�M!) RPˆ¤äBe'L‘É4𙡙@¤¡Bz¡L9šaLœÌ¡’‡†…2†pé%33„BP°¡I™B’”)™4ž“¦¡C™¤¡aO9C… Nd§™™™”<>dæffJ‡ô3’™™ä¡LÉNaЙ9††M!šäHICɦH†Jd¦fg$B“:ò™“æRg)2“9By)CÉ)’YРD™™IÓ†x !NC…$C9œÏ= IèJ%(r‡(e&P¦Ng9I”ÉÎs–9™œ¡C3d¡Ìú2’…%’…… dæ™IIINáfK33339B’‡2XrÂ…2rd@¡¡Ã””ÉL”š4(S2s s3339’!œÏ(Re ”9ILÌÌ)3ü§:9� =ÉÊœŸ>e$ó)3”œ²„¡C38P°§å8XD $ÊNPС̤¡C9ž… É”Ÿò™?СÌú"s&På ÎáNÉ”) ’t3…”8D2R�fS%32D2S9Ê™I)’„ÊB!C)3’Pæe$¡IOB„æL¦r’!ÉC“9™˜y4Îg30¦L¤¡Î˜y… ”)œÎg3) hÌ4ÃÌ”"C"I”“)&g3”)(RP9™Îá¦H�Ìô3Ô42PœÊaÊ&JIÊœ,"ÌáC…C–çùʆ’fJÊaIœ¤ÊdŸ2’�IÉý ffa†LæH†p‡<ÊI"9B™œ"„Be å IB’…$C'(d¥B!·(sB‡“"(Pæò“9Ìó™ÌÎPæPäÎffM0òS$B“ÏIé= ™C’‡3”’„@å 8yIš33&@Éažç)3”™B“%2t3”9ò˜e%! D9Êg‡' J32†Jd¦Jpˆs')'BdC'2e&$Î)’™˜D8YùÊIò™I<”Ì”ÈD˜S2”ÂY„BP¡äô…9,"…2e ¦¡BS…%3(JfdˆP”"(g&†L¦Id¡f'B�ú%?èfP”“2†…g(g&d¤¡ÊÉäÙ…9œ¤ô dÌÊI¡†” RaCœ§=30ˆd¡LÂÂ’“L>JR¡áÊåB”�³3”)œÂ$Â!œ(fRe339…2e$@¤¤ÂÂ…'% J™¡™Â!HR‡:aNe Lü¡I…3 ¡š” :4 P™@æS8SœˆPæpòP¤ÊJœÉI2RP¤æfxÐЧ'(PÍ ó”8D’†�aI8P¤ÊJÿB~faÍ !BS”Ìå% ')ÀŒ’YÊp¡¦S0¤Ì¤Êfe áùLÎhS9™”&D…)…!Jdÿ)’‡‡@³))“L)ÉLÎt(rfJ%œÌΡ’…%% L¤¡I”ÉÉáNPáær“”9™˜RaáC9”Ì� áI”)†Xf“‘ œ¦fsÿÐòPˆ)¡Cœ(J|ù”8RD%(y<¦dç30ÒP²adšaL%Ã<ŸC'å%Â…†C%))™)"™ÎPæK˜D˜YC˜D8P§B@­ýÿøy CÔ@µÇ(©i*”´¥¥-*ZUd«(´¥-IKDÊJYeDÂÒÊRË*YJ”¨µ¢©KQT¢ÒÉ•)ZXš,µ%,©(¹)QjJZ”©IjRL¨šRÒªT²¥)K(­%rWJV*X©bÊ‹R–T¢ä¢å)R‹JVT¬´¥©J–RÒKQj‹R•µ*KRZÉU%©-EI‹E­*¬©U’T¤˜š-,©Jª\²Ub¥‹KJZ-eKZJÔ––¤©¤‰ªER‹‹I”–´L´ZÊR¥©–Tµ,–RRÔ’Ò•-*²Ò–•YJ‰”¥%“%JK%T©eIeJR¥%–”\´²©,´²Ô¥%©.-,¸²Ô•”´«J\YZ¤ÑeJª¬¥JªURÕ*,¤²•,´¨µ%I2’Ô¥)--IjR’Ô–YQKR#)-U•*©2•Ee¤Ée¥+RZ¨µIJ¢eJK*Y*²ÒU%eJªªª¬¨š,–+,©)J‹TZ¥)e%”¬¨šYRËRT¤´«,¬µ*&I‰”¨¥ÉZ¢eeKRU*É+)JZJ¢Ê–TªÑk*R´²µ)R¢å*ZX¨šQ5"êT²Ê”¤ÉdÑKJYQ4¥R©eJT²¤¥¥-RZÒU(¸­JRL¤©EKK*’­,©ieRZ’Ô¥)R•-%R•*Yqbhµ”´•IZ’Õ)R¥–”¥©)2’–)&II’ɢʕ&QYKR”©U•,¥J«)j*Yh²¥V•¨µ%IeDÊRR¥JªUTµ)QiUJ¬’Ô”¥¤“IjJL¤µ¥¥¥•+)Q2”¨˜ª¢É•Y*¥e)iEÉe¢©JR¥)J‰•**R–’ªUU–\¤©eIJQieÊRÒR”¢Ô\YrTL©JRÔT¥”¨˜´²²Ò¥(™(µ\Z”¥KR©+K-%K%”–”™iIeIIeJÊ¢•)j•V¢–”µJ-J²U”©UK.)T²¥UU”–T\²´µEÄÅ¥R•,ªJÒ¬¥J´«J´¬´±kE,¥%-)UK-*IU)U*LZYUKJ”©R•JT¥)&J–*TT«QK)--QrÊ–R’–R¥,¸¥ÉU,©JZJ©eÅ‹R¤\¢âbÑ2¢eE©E¥*²’Ê•ZYRÒ¬¥”¬«,²T”¥)R‹’Z”R¨¥RZZZ”©e))UeK*Š.J-JK&’”¥¬Z¢¥¥*T\L©KR‹”Z¢eEe%KJ––-QKIU+KTªË*RËK,©JZ’Z’«)*T¥JZKRVJLZQ4YyU¥VYIjRÑe©)j,´¥JR–’–”\”¥)IjKR”¥*R¥)JR”¤µ(µEdÉdÉT¢Õ%ZJ¢–’¥–”µ%©--Dµ%©e*Qr•”¬¥K)JŠ–”¥”––\&T’«*-IR”¥JU*Yh¥¨€q¦beetbox-beets-00724b7/test/rsrc/unparseable.ogg0000664000175000017500000002056315253035401021010 0ustar pieterpieterOggSþ–ç=݃[vorbisD¬€»€»€»¸OggSþ–ç=Ò»ÃAÿÿÿÿÿÿÿÿÿÿÿÿÿ2vorbisXiph.Org libVorbis I 20050304DATE=Oct 3, 1995vorbisBCVcT)F™RÒJ‰s”1F™b’J‰¥„BH�sS©9לk¬¹µ „SP)™RŽRic�)™RKI%t:'�c[IÁÖ˜k‹A¶„ šRL)Ä”RŠBSŒ)Å”RJB%t:æSŽJ(A¸œs«µ––c‹©t’Jç$dLBH)…’J¥SNBH5–ÖR)sRRjAè „B¶ „ ‚Ð�UÀ@² PСЄ†¬2 (Žâ(Ž#9’cI² ÀpI‘ɱ$KÒ,KÓDQU}Õ6UUöu]×u]×u 4d@H§™¥  d Y F(ÂBCVb(9ˆ&´æ|sŽƒf9h*Åætp"ÕæIn*ææœsÎ9'›sÆ8çœsŠrf1h&´æœsƒf)h&´æœsžÄæAkª´æœsÆ9§ƒqFçœsš´æAj6Öæœs´¦9j.Åæœs"åæIm.ÕæœsÎ9çœsÎ9çœsª§spN8çœs¢öæZnBçœs>§{sB8çœsÎ9çœsÎ9çœs‚Ð�UA6†q§ HŸ£�EˆiȤÝ£Ã$h r ©G££‘Rê ”TÆI)� 4d!„RH!…RH!…Rˆ!†bÈ)§œ‚ *©¤¢Š2Ê,³Ì2Ë,³Ì2ë°³Î:ì0ÄC ­´KMµÕXc­¹çœkÒZi­µÖJ)¥”RJ) Y€d�AF!…Rˆ!¦œrÊ)¨ BCV€<ÉsDGtDGtDGtDGtDÇsUõ}Sv…áteß×…ßYn]8–Ñu}a•máXeY9~áX–Ý÷•et]_XmÙVY†_ø�åö}ãxu]nÝç̺ï Çï¤ûÊÓÕmc™}ÝYf_wŽá:¿ð㩪¯›®+ §, ¿íëÆ³û¾²Œ®ëûª, ¿*Û±ë¾óü¾°,£ìúÂj˰ڶ1ܾn,¿pËkëÊ1ë¾Q¶u|_x Ãótu]yf]ÇöutãG8~Ê€€Ê@¡!+€8�$‰¢dY¢(Y–(Š¦èº¢hº®¤i¦©ižiZšgš¦iª²)š®,išiZžfšš§™¦hš®kš¦¬Š¦)˦jʲiš²ìº²m»®lÛ¢iʲiš²lš¦,»²«Û®ì꺤Y¦©yžijžgš¦jʲiš®«yžjzžhªž(ªªjªª­ªª,[žgššè©¦'Šªjª¦­šª*˦ªÚ²iª¶lªªm»ªìú²mëºiª²mª¦-›ªjÛ®ìê²,Ûº/išijžgššç™¦iš²lšª+[ž§šž(ªªæ‰¦jªª,›¦ªÊ–癪'Šªê‰žkšª*˦jÚªiš¶lªª-›¦*Ë®mû¾ëʲnªªl›ªjë¦jʲl˾ïʪ)˦ªÚ²iª²-Û²ï˲¬û¢iʲiª²mªª.˲m³lûºhš²mª¦-›ª*Û²-ûº,ÛºïÊ®o«ª¬ë²-ûºîú®pëº0¼²lûª¬úº+Ûºoë2Ûö}DÓ”eS5mÛTUYveÙöeÛö}Ñ4m[UU[6MÕ¶eYö}Y¶ma4MÙ6UUÖMÕ´mY–ma¶eáveÙ·e[öuוu_×}ã×eÝæº²í˲­ûª«ú¶îûÂpë®ð p0¡ ²ˆŒaŒ1�RÎ9¡QÊ9ç dÎA!•Ì9!”’9¡””2ç ”’R¡””Z !””Rk8Ø )±8@¡!+€TƒãX–癢jÚ²cIž'Šª©ª¶íH–牢iªªm[ž'Ц©ª®ëëšç‰¢iªªëêºhš¦©ª®ëºº.š¢©ªªëº²®›¦ªª®+»²ì릪ªªëÊ®,ûªº®+˲më°ª®ëʲlÛ¶oܺ®ë¾ïû‘­ëº.üÂ1 Gà @6¬ŽpR4XhÈJ €0!ƒB!„�RJ!¥”0à`B(4dE'C)¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RH)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ©¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)•RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”R �Šp�z0¡ ²HŒQJ)Æœƒ1æcÐI()bÌ9Æ”’Rå„Ri-·Ê9!¤ÔRm™sRZ‹1æ3礤[Í9‡RR‹±æškVk®5çZZ«5לs͹´k®9לsË1לsÎ9çsÎ9çœsÎà48€ذ:ÂIÑX`¡!+€T¥sÎ9èRŒ9ç„"…sÎ9!TŒ9çtB¨sÌ9!„�9ç„B!s:è „B„B¡”ÎA!„J(!„B!„:!„B!„B!„RJ!„B ¡”P`�@€ «#œ�²€– R΄AŽA� AÊQ3 BL9Ñ™bNj3S�9�tjAÙ^2 € À (øBˆ1AˆÌ …U°À  æÀD„D�˜ H»¸€.\ÐÅ]BB‚X@ 88á†'Þð„œ STê àà ""š«°¸ÀÈÐØàèðø8>€ˆˆæ*,.02468:<€€€@€€OggS@–þ–ç=ý‚å'02310276;:?CCBl…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹¬Ø%ô B8FkF#ëœzÊýýžåJI`Ÿ76BU5À: š†îK.Þ[/IÀ´˜˜€Ž€ ~ÊýýžåJ¼çÛJÙ@!TÕ€ €z wPˆ{@Û‚š_,ß5ðè@ 4>ªýÿüå žík¥°@!TUè40ÑMtô™àÉÆ+ÚÙÁ…WÇуàÐ>ªýÿüšäâvy¨…PU¡ô…|G×�OӱЂ††�ÊpBÀ&€>ªýÿüšäîô4ª…PU'Ð@$¸O}�Ç%åMÒ;†:€ žä>ªýÿüšäÒ´ð&”ªÊ* @t𨴯ùçaï¥)t (4 ƒ˜šýÿOre1éM0BU 1>ÞY(¥ÚsYÀ&-RJgè¡ÕMkòØÀ‚VšýÿOr¥2ØåIØUUÅ@EO5š‚nE~IôÆÓ´JÊqØ)d¢U)°$ @šýÿOr¥28åMèªÊj ÌY�¬"æeç…d×Ôdþ‘òcw¢ ±“¦‘€d :šýÿOr¥`°Û›¸TU:Ì]¹¤¿\Ïô³\ÏÒ{QFH4¬T05Þyýök”‹2¸ÛÛXaE…P + &EÒæ^ ô#©”¶&Ú!ir}Ï””Ωaku¨“)lY �‚&˜ HÞyýök”‹2˜íMP*jT¦Þ1{Ã�1^_Y•¢~vçt×ZŸ}¹.ó­¡£ª9“5\1á)èàÁ_#ÞyýÿþåR Ny“B1ê,˜r(¶Øò³4ptmp sR›¦£L/g9‚èÞ?®Í0—M)°”,ZýÎu¹ƒ‘Þ8 4´X‰ h©u À÷ßÒ‹ö~>S£Èü†ý$=cr¦Èß7²ü¼öŽ¥ÏÃŒóù0ƒÊ«®b¥*¯ß·þQ�ÿŠá¨Y4®#öO¤Å± Š«=¡ P{údX]ÎÔýÎ59 £¼ „f)6ðÖ”³A`fœ“€½^�Ä!ƒ<©¬˜i0/d¥·?/Ôh³=é«m¤ò¶Þ­™ž��wÛÕZ:Ý–ÿ‰�^®¦×Ö‘&uVwû’CÅ_Åjð-˜mŒýÎu9 %½ Ð"++IÀ@âÊAGÕ�rý5]óo”X€¯/sãÎ�\ú çHÇ‘ÙqoÅóÈÐ3ú.+¼ð¬qÖ\E�¬SF’¿1R-à"ç ÜI¦ÏlÂjÂɘÌìæˆýÎwÙ4-= Ĥ¼ÌdÀ¢ÐIà,1æ8‘qü]âj­_è÷⥧Թéô''ïsçõu|‰ìwûæ¹ÅÇë�³Îå‹�/ó¡<:�0ÑÛå$¡Í½'—3Œˆí®�ý ýÎu9q­< B¡¡ËÂÉg�Pà€~57kg§P¿d´]�ÙÛü¹œÎo¿’_Ú¹Js)êã5÷Òä¤Åp–ô•õÚc\^;Ç¥QåtFôbˆ[D®áì §­“ýÎ5¹ƒVÞh’ʦ¡°@vv¿´ÄN˜¾d ¦²²Ki*¯u67[˜`&· 'nV‡§¯‹“ËÈcºt“Ÿq’C>-VþFŸÄ¼VÙ ]êïtGNÊy49ªéaœÙMãýÎ5¹ƒä�¡Xd‰‘\%`8�'\àÁÁû5ô�7‰M?/'x‘,ׯ×}Y¿Ž½nmcfFU)¸¸ð“‡0ÙëÞ¾ÕÑøÚ��·•êP[©+T²ûë¼ý2š\ÍüÓSœ ÂG.W¹èX©;·åUFÀhkôo†FØ/÷àÂu cÊ:ýÎ7Ùƒ–Þ8€˜š• ›0Ød7•\´×vÎ}ií½E«MÝ M3‹Š"äðºÏ~µ½b³¶#Ah©'òR‚ÑÖ&y,]~�MG“-9¶#8…þùäë¼�#s/yýÎ7Ù8ƒQ¾1ˆ•Ö%ˆ8€iup;š¤_I5…ÀÖÿ?»ØÄ&òÒµädu¡n±{½ï…é!‰Ÿ»:•¬Ï…úzÅU.25žBÉ–+Êèq0ïîQ®*/CUë&^ܱé-ýÎ59q#} „&å68ZÀ€ôлt3ü´WÜ™ohm™äP»-¨Y?Ç{ž°êŽLXø8&MöØ f%ªO©›÷NÉ”‰Íͯ®b¢ì½›ìÎÈPw¡ëWI;–ýÎwÙ(ƒ–ž„*hRdÁPL�Kºá?7œ�I—»B��Á¦Ñ|_O&±arúäºvQà$¹k×°d­Áå²l­Lc/["°R#lcú,èVÀÝ�Š…«äàHïbz¬Û{8˜TýÎ7Ù8ƒQÞ1ˆÉJQ3=HÐi—� ‚©æÊì•ä¸óM6¿ÝRmöµ|fê «ö’ôÑZ*Ìü(NbÎÑÙ&ç²ýÎu¹ƒ–ž@-jIÁ…&&èh‹o\ˆœ‰[¢ÆüJx2ÝÏÚ ^Cí7^:«YGcF¦òO}žÝºž‡ƒž�™‰°±<É~¾¬2Pâü"SÔÞ‰íõªÀö™!Gæ&ÛóS’‰�ÎI…¨ýÎu¹8ƒQÞ(BÌR¬H¦Ð‡YB,ƒ’²-oÅx3CT§XÈèòßÑ| éÈÓùÆûѳ^^ª„^‰)5=‚%G½pïb€{fy](€>(Ö÷:;ubjÙ:kGG:OggSD¬þ–ç=‡¿²¬‹‹‹‹‹‹ýÎ59 %½ ‚”. :>�þè]µ¤?÷TãÌxL€çsÔ˜žM›PÏXšÁ„—+q!^#§ÃaâèÑ|S«ã.�„™ãµ•«Q®%(Îsnå¶©lõ]”N-{~ýÎwÙ8ƒ™ž0B“b…qÄñ–X9vñ)l}¬Å¼�b‘Id=!û…t,W¢7Åæÿ9±¸õñ­Ûÿâ® Rñˆçƒfƒ©ÄÀoé<ïËÓ—·§¾UÚe±”׫üpõ0Úé[(wÉÎ"…ýÎu¹8ƒ–Þ„2h–¢"hrðÈ)=|éP›Û"ýr:Iò"q�ö°Ì˜è¹¨š¯à޾Rß"à€"«•uÞ½‰ þ¹Ú‡¿š.øAsñ©Ïˆnµïn7…£'òèeŽ~ ýÎu¹ƒÞ0B Í c@2 °8èä>h»ï_6ƒzyu—YÆü|$Ô•»¹Žëö¬ÊÀÅ…÷ñSìÙ n'E²0!¸¶²ö>~v3üayè™zŸ›9óMÔk ¦1×5„éW7ñ#ÞežÈiýÎwÙ8ƒ‘ž1h–bÞFh‚¦zmœòp4<¯å²é*é´ ´ÚäœÉ"N¨„ªñ|oâSðjl’ÌôøœxŽMqIß–Š'S´Î—WøKw®²:&U0TÌn;�‘bbž ÆPÈeýί² 8P‹<Üà0P8�Ó¹­j xz}]�Übeetbox-beets-00724b7/test/rsrc/image-2x3.tiff0000664000175000017500000000031615253035401020351 0ustar pieterpieterII* ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ƶ¾(HHbeetbox-beets-00724b7/test/rsrc/full.wv0000664000175000017500000003254015253035401017327 0ustar pieterpieterwvpk 2D¬D¬¼â¶é!RIFF¬XWAVEfmt D¬ˆXdataˆXBWWGVHCÏßïë –eŠÙÀt@¥¬ ‘ɦfÞ1/°¤% ˜k^‹�™«\Á¥”Eãž7h… <–°ÍeÀD*ƒb=p™bE‘ÎÁ¨¸‰±I(€šxÀ‰À(N%ªT£´°TéæÂé6™r¬‰�Sˆ(Ð`xtÔMI)gÙxL¨Up M ”¾¡hŒ˜`pH /Bš×`0â@ 7K6ePÉ=J8(p²Íü†Bd h s�r`ÁMybáhÎn2÷T £�ð6Á�:ªû�rÇ`…ŠÆŽ’Ñ%"39>JL9Æ uì)<ÚL;=&B8GAáøkÙFhF”›;n@+A¬P`ÃH›AŠFÖ$FlŠf¾÷À} f©S›áDœ4/°Q¬RÀ+žÓÒ"(â°¤ � WéÄÜ÷´),²0±µÐMP„Þ·$Ë„ÇÄÁqŽÒ�Fàd-À×?©µfs�h"¤ aXjªŒ`²<½†Ã•°9Œy1xŽÁ‡êrVœu°<Õ.™î¤¢Ü>¢q±Ä-8np#á8ŒÜ¹âC#yT†1=Æ �ÔÚ@ÈÅNòc$ŵ’Álrc U¢«‰ $¸O–JªFQ ó&³Qd™ˆŽ4/ z @jQ g(l ÆÖ4ƒ3ùJ�~ñfИŒ1¦Š%€˜¤ÃhfTÔàôN¸àc“8HàLaD R+‡9QˆT~„ºDÃŒ2:Q›IPvjŽñÁë atÚX�Ö!HªFÜ °†ÃË)Ì15ÕqK P |–MáØI=�ŠÁJ`�Õ±êíÃ+D™™X­ƒÐƒC=�2™7TŽƒJ3)‹cðáDÍ,É"¤ÇñQ'#z¸PúDü—‰6ø RYÎ;ÐŽB¨¤4Ž']'�T ¬À‚D3@ˆ…ÖœX J|påS ‰ š�‹Db2Æñ|! xg¾pÈæš½=¢^jc'ɸeÜ`ä&À©Ð DP+ÔÈàˆÆŽñXÈÜ% ™jªY–ôjX†ì�j‘l¡:dÙ’Û[µ>4& Àá>Ä� ĉÒNЃøáhŒå¥€,d N¢³q<^@b…>Ög¾ÁÓŠQÏ:X-è`“Fø¡AØ\�¸~¢µfs� µI”Å’Å óˆNŠãÊñ¢'v‚nBà„ž¹ÃøP.”ãA9؇2Êic"Y è�Œ4FXžªa!�ŒP§"øøcb¢ã(ð’¾A6fȈùÍÈÏ@q*.¨`¯[k�j®Ò ³€‘�c¨YÊñ+ìx„j‚áX‰¾B$ìâ\R+ÈD× R‡€fÑD6ØT³,é"l,ÀRÂ’éŽW€PxS="=i t 7©åT3A˜—0`d„ÜÃ�ÄQ0$Ž2îH;-îÁ�b5Ñ`´ ÈG˜N4�ÁÓCO†P–°¬ì†M! ¤ YpJ…ƒ”ŒD  m€Ø¼,x ´1.Â0 MÆÈÃÊ•DÔœ€´Ñz")6÷Á± P,®hôÀFÕ\Ò�š–t?Š‹F¦‘6²ŽxAkF—X˜äjM P#Þå¨X`dI4Œ=�ø(£ 9» 0óå·�Xš€—tì`¶h AÀÌÙØ#G€¤ÖO†Ö 4šÃó% ÁNvº¨%„N ZD3”¡-97 .!í¢ÎäÄ÷iA”‘ŒÔ X‰à;#QÀ&܄쓭:LtnT‹ àhé¤mP¬„IÁ(ÍK Ђ¤Å-Z¶GO‚d‚7ŒP@g�Y=˜ž (‘¹‚p%l!HLJ|ÂʤƒfédÎÃA�8>@k0'-?c¬ƒÍ‘ Ž‹, f Î¥“ „d³Ã’jØ)2q ¡‘…ej0§ÈhAPë©®=a–Œ2`©…Pò\wç�ñP0Uʼ¡P!à˜gÊòÀ± €§¶X~œ˜µ¨¹äl8ºH,f³ü:‹¬àL;ÆÔ¹$vÂCHª@x?V  Sí0û#"³:X3¼� ó’àˆVŸàÆCEÁÀ4:bqL$`<¦¦„?L5/•ieââ8{`hòbXs¤á`€©…+CÀ”T€Ú2¿ÆR(™º¦šj”ƒÇ*™x„yXòŽ­ #Mb‹p8‘‚E5Àcº¨ã@#+�Q�RèHH>º@áÒ@4ƒ¼£ޤ“ÅÙQ�%óRH®°ôpS�*-¦ñ—h ØÀHä Ï5Ê6Ø9; LT>•$FŽ5hYdaÀ”â2CyìÇGÉ0‘A®A>A#•©õÁ:`@=c“.Tx™1 ;dX%‘ >�âÆFEæN€–²@H‰ÈÌ�Á™ØÁ­Á `æÊÜà@òX% ³ÃX€‹òŒ©b €Xê ÙÜ™š AfS(ë1ú…‘ÙŒ  £™€g�fò…YDËx aP¤J4@"h„B¹ ó2Ã/ È‰ŠŒá�æÊ| ­� ŽÓÈ Ç†m*ˆñ46Í—ªÇžðÍ åx‘¡ Ô´�Gp#áx/Ôbã[€ 4¸@@ -æ$°TF9n€‰g²˜Ö x�XöêŒ�¡Âš¹Z³ Ël a#©*èhêT¨yAÙ#ŠqÁÓYO°ŽpHdJÓNbÁZ‚zºñŒiʧe“Ê«ÇÐ¥2Ö™„£`Ò×|Ò•%‚I°ˆ‰™'(‡ ˜F†*’ÊTó�Ö¬ŽòHƒ+ZÁA” &À˜ K^ n( I†�ŒkŒ`ƒèÐ8°ÜÀÈ#‰tˆ2ÇÂ%ãùaÞit�¹ˆA’AAU¨fýÆe"„±8Ôä²NT² ‹FÑc=•ÊÛpJCƒÊ°¢‘Âø .A<Æ&&ŽÆÌÀ£�Y:ÇM‘‘€‰Àžõ1yfK,(�$£Ê á<àÕÀ˜ kʔ߄‰Zk$AÍ’?AÌK@A˜ÇÑ3%f6” HS£µ)ÇkÀ °ä g;Dµ{”‡ÄÁåÐ8Ò@$p ÉÑ�$ £VÜMÀ<Õ-" S‰; G4M¤g=AsMzMæEe.¡� 0zˆbeÔi¬;óöá¡dî� ÐD °Åå´L¸à0F X9• ýR£Âw±‡¨â—) Ù1& ØyˆØWr”ešmŒ6³MÔ,¤ç¾È´ΡW‰Å²§²rÀLd“zê¥ã�²y1B6o' Ê‹—޳Q–À*KÐ"04EÄ´1qù¸¡ÛAš@�õA›í0ˆ¦î©†ì®K`%(·5'‡›ž¢\ÓåPgý›˜±&´™’€R@3 N•Âu4Fáøø¨xA ‘kFð(;šã×ðĘKJÔÀ4£Ž“GÒ8 DHŒ�Ó ccͰ ±2ÁÂú¥Ábœ…=];p™PÓepj@� ˆRâÈóH)Lö Éu¦«sɼÄhB6°0fŒI)VæÞ2HÉL’`�p| £%3„JÁXTƒ€òÕá×x´£Ä¼ Ú”3É Ù@ôÃ"GȤ j„6M ¡(^kFá1yf�gà´L´d:*ã%¨Ý€=XÄòÖMAæÆ‡ó …l¨Š*E ™J�ìØÀ@qD¦»á†#PZ#ÊÆDGXœi €/Í7šKÉ�–�tAÑ b�ÚS@t\P9˜n ѡ°k1V(Tr18��°�DŽt”ƒ�%€‘i2E&¬Çü†(œˆ†s±Ï°Ê­€>â–à…‘4¹F “DÍ/ÞûP ´Çä±â̵#EX2yÌ•Dd”%3L øOÍÑx… {Äp Xçø‹PAj¶æè"Ô©‚ŽKN4uª @X6Å'Rp ”T„é�˜ Z€XŠàÜ  K`‡ŠF&­D†!¼CI‰ ÖŒGt„F6¡ÀuªÃ9À@2›ƒ�„FرÅ@b¸ÆdA&¸Nu�”$c1Ù˜S„,W ªsâÕ¡�r7@²°ÂGÃp4�ø€<€‰šÌMˆ5E`\Xd€Ø£$å1¸ÃD­5’ p¼ˆƒ,Oìá:6☡'†‡”*/Š"Ì3ó�€P¡^´%Èe"‹­h"uC‰iÍ ež’ÖF=ÆÊ¸ÄH¤ã!„KÈ_²uH$Í¥ÔZ 3ø0HøqZœ6Š�”Iü  \�'V rePN¥†fã%$R‚ñ-s‡p�±ž˜8„»`ÎÐ=¢©0_4¢h¤ˆcýETØ‹ÌAŒ¹´�ÚP™_À€š/1£Á- D5¥–Ž€™2/¡ÙÐR@ç!àG'ÄxâbÍ�<Ë%È1–Á8l8pzp€ Ì*Ñ�³Œ1q‘PŽ• Å 9Ö¡A¤Ê•¹‚Dƒ(P¼¾ A �H¢W„ã"Š%"GÄÙ‰xi‰ÇhûdN•�õã¯?T@³ld A›Êšå\‘a 0i�4ѱ.B>Ëbî3sx8ÃI¿ 8\ “wÀ;Š !åF «‰—:x�SSJjñÕÜO…”!È�2îPy0„WãÑX $Ó@†¯7RjèŸ;À|á#e®¢T¬²ú@ƒ‰j*/€‰�aºaáD l²ÇºÐ8ZÆÚ5SYx„x4ŒˆRI—ÉlÁâ"kƒFhÍ×"ÙDC©R{4‘ìC±€‰Rdxf=R"ÆTÒ f �2†ãCmˆp›daa#¥£‹ˆ£qL6àå‹5z”AR 09Á­Às‚} d£©dbAÌWæÒ�ãín¢¬–ŒÊ3±bGÂ1/tA�q4ŽhŠä;#º§rÑk.9æ.(€´ÐpÐXØbëá7Õ¸³k¬9šñÑ:‚ŽX|r¸tÄ¡Âü@¬`Á¡K€Ñ®q–„ „+¦{Â%ðrŒC–%Çî\r e‚aF²Ã(K' K ‹=–D#§B÷è-Å“�’𢂦À½¢ÊB.Êq¡Hd9ä�Œ.ßÈŽÊ…0pfa²!‡{XTt0¡k!BJî�näW6¥• W€ÙHÔNâ °�IAËT‚F&Ë¡Â4ó‹ò©�¤©B´Ó T¬ì¤6]iq#l ²„›–HO„@¢Ñ‡QFËcwð¨2—ÌÙø’H@-Ñ:Šð a#B‹ì¤R¾#@ÕàÉ�«C…Ögâbâhbä,æ¤`“aaC¹*b \B«(n@S a2Rh&—FÌ’C2eÞ€°P¨ðx*”%�ýcXd`F“…– àoRzͤOt(GcPÛ7HDÈžÐèý„¼OLÖñÒʈŽb(D kIâ �D…—Sb2ÉÀFdÎC/RæH<BÁD8`Œ›êÃ5@§ÅG`€ïi™jªã�vëŒKL>Ô– Ãr°Á|Á’n06"¸“ ”ã5 Qþ%PêaØSO ”aYb‰ÍÕ!yžn„,\j¥Åäd�«K°ƒ!AQJÓ37c-T)'–ƒÄS(Œ …ds¦L]³Äq4Ê€÷1t45²z€ŠÎ|àºp´Á5/ UBcŒ•ÁB;@雀U$…»àˆÒÌ/!TéŽü Sð—â!TâfÄ¢¦{p�tN@Gb²�eÂFaއ€ÇY‚ö0™ºN=©z°2Ê`Ù§0Iñ $£éø’H…£%žQÃ_ |˜+àPÖtM5å¸Aäè�7âã—"e(àP"æ¦tìΕ¹ fh˜[€c-�0+›)P,ãTÎV8\:2,U`�}@¢™¦æN¼ ‘Jad"TÓžtC Ì×€€UëO\€€3‘‡Ð‰2ó°�´ÆÅ'8Ó:Š ôa£!‡%¿,ƒ —^(±t<ÃPy8‡$•$° (©ÆÐPXRsêØ‘[D^¥‚1ƒ%FT6ÒF˜f¨.IA‹¹a`F<×\j´Ì[#ž�&æ“<}0‚ b¢˜E²À( ±žõ°f)OuÄGž*¶îó¬añ ¢c. (¿(˜µä ñ‘¹Y&h‘‡R 3_=Çí§ð).>Ú@«hÐ�›/qŽ…9Å�Èà´‚úÆkw`¦�qX`Á’á>ŒO y@T$Å¡I‰#…qfád(è¡x�qɉ€LÄ€‘–L´6£‡¥€ S{„‚Æš°Bæ©Á¼8ÎÑŒ)`)0RÌ­AÒN5K5µCÍ5Õ©Ò© €™jÈœ¯%‚:õAÖ:âB8$Â%\’8„J*IM‘&Ч%C¼¥í¨ž¼˜ ühscQáò#\B)êƒ4Z|Iò�–˜` Ðé† ­è`¨9’ËiPé0•bL$Á)RÙpBL‰º<ÌÃHá2zÄc‘€M&3úàuÐ… u¬1:.<ЂÐt zQ—åCj²>À7Yzæ$ ‘a€‰¤¨B;ǃ„8àì!™hª©)Ë ÈÆ7ÄŠ% Kf?È\ÃÅêAÙÂϵnÁÔ,7X È\MÙ =o“¥µº ÙIK€•ÁÚzE¥q ³9H…ŠEàH¡æ P^”Έ¦È ™©ž˜šh,¬’ÃÀžú �Ù–ñ0ÚHyêb¢R!5 ïq ïÙhâ‚4ÐaÅ\9AƒÀÒV€MY‡C9¨H–Ø0nŠ!0YÈ z°´4ÈI3*�˜V , b¬8þ�…DÐ#�¡”RH' ¦4µà†<9r<Æ©ÁM!‡ß&IX8""3�1S 7W'‡d²OGÐ ¯ÂgÇ﵈ª10ÖÄQ¡Ëô‰b„ÂN5¥c•�‰ê¨ ŽnÂ"&�逥”ŽIeæ-Ñ5_˜¦Ñ“˜Ï%jºgª<ŽYÂdl@gáç”IOkÁB±gÌPÁ aQvÚÍTr $ÁËKplFcÌ2¸4Ò™bs±½0ѨÒY “g @R©‘Þ�”ì#Jsªƒ&f7=\Øè¤o¦S{ E¦@@sòœTaadP”�;.×°Å`  ‘!ãÑ@‰gh�E%"6š6@šG‚p@ö`–‘82y E•Ìœ'Ö–¡” Hf¶a â‘BcSdÞ#Å'[ª%%nP'€h¼cºX Õ½20–4À¨F#IÀQ¬$š z(ªØ�Ånˆ&p¸.PÃK aÑÃ�],Æ¢As6ÿ(r2Zh§� t*Ì¥ˆ™^Ã`Fž|)¥%1¸U™À=4 ;8dx¬¡ÜZ3‹EX<|RaáEÑ�RŽ/IÙeIá°ùå«a,¥”͈a(‰×�HÚÙPÆ=Ô­³v8�B¢ÖTŽO² �‰À\(/…/BÆfˆEp,1ðÈ W±È JÕl�¡^ŠïŽBL% A£¥00üqÀÎÕp)€N}3‡sC�kÂÊ@‚ ¼Æ°µ ¸60`q‰‡²E=ô|€ X&ì°Ò‘Š[Eø2…›ÓÁ#ÃFuÌIu$.¥^,]<5šK  Qbã�ð—uxM$Ý~�)ÏFÃLÑ&ù…•Dùi_ib0Ó; –0¨Sti(ÚÙ€J\‹®²”É™¾uÀ¢‘)…�#A¤�PHdbÔ´{ 6lÂK¦³ã3RI…;G Xc¤E ¾K*§d°n¦èȨ�7T*ã‚Æ%�¬ÅkŒ>' åÅF¦£öA @¢ÁÚ(ùI· ìŠàyGùeD‰ �©ŽFIž®€¼7˜ÈoI\ƉͽŠÙ( Î;4Ð+BñEX0yàFsÅ1RPaéPjºYplžh,7‡æè$Ä#ˆ¶åSÂïP…| {\u†¶Pä6¥‰ÖPa40óµã ˆ(ËB$ˆ:½9¼ÎÁI4‰Pƒå°4�„yahâ€ô`ZÀÔúð2ÒÁ¨âQÜ�ø½Æ¸²‘Š (dOQ…tÍ•DeC>�éH*5Ú0ž´Æ P±ÕBƒ;@S8l^–à „£€péêx²„ÖJ.±Ð"¸ÇGQŠÍ›"&ƒgdÒ¼›In0ÚE‘èE×Â/lÂ#,0â¥aZì‡A ™9� Xó¬Ii;ˆô—ˆÇ` ÄàÐ… a^àÕ „æ»1Îè3Ó@-�˜2ÙQfy‘u(gÐ02l¡Ͱ|�f´Ì,M¦i4®8;ŽH4ŠÃ`&ÆÔñ¤DÜÉå €X·`"¼ÁÍ©§`ì4¤è¬·"ê‡/» ¢èñ= ‚Ž8à ·˜m S+3k")KØseJ�WåÑ�1AYd&� :˜©v Jij*If)§:�@ò„K5‰‚rœeÙˆ Zƒì!&J“SÍ'`6Ö+À „‚°6Øt�ùŠBïÓ÷ ñ\¨™`ÌZe‰tZŽ�Gˆ/M�*B•«Ã=¸ŠŽJ‚Ä`ÔÀRH š‰Æ¸‰9†rõ@Ááö„üXa‘ŽyÌ<¢’f~˜ß Ïh;A‰­V µh¨-Ÿ¡<¨Aêð…##Hœ(Ö03€§Ó’ZFŒý -Hiwè²óQö‰nZC»cÍSŠ,AŒíœ7ƒ¾ à¢è N!ò¸~ÔŠãh(s€Ä L²1ŽÑ‘ƒ8sÝi±pVå…@X2¤17/ž—˜Qˤ;e¥Cp ¸”%40Œ6”uAšÁ2gyä�ÅÄì1û, p ÌÑ'6�ð6côŒ/#€ZŸdŠò’,® D£p$�ɲ$"TЬ ô–Í%HÑ'©M˜]b Ç âùãDòA4`1×(âT24H9 ñ‘Ã:Q13(/’‚wú P3žcAp‡" ók™ì ÉÁJnÆ%Ø`\r´WµÖCZá’he¨ákR  Ä‹3Ób¾p>ÆHÖô-éŸÐ‚7¸2}IÊ=M™i\D²uX’ZàpÝ®¡N•±# ´Óœ(·€Kµp$�4ûAF0‘£«ög„ ¼�8®‚Ña[:*äF‘5V±Âw"dF$Rj€¥„�Ȥp#ñób�/<Û3BÄR`Âà€˜Ë&CÂÓ+Ä�ª¼4bÆêB¡Y q®3—ŒÐ2ci@‚MÑiç´ÍDgšÊšÔ~HS!)7—€E8õARJ‡ÑÄh€r¬˜:Ħè”#>ÇšBµW&}è0tàŽ‹>Å ,—–ȳûO€%莴€c(eS$(@­ŽF˜�O²hì %tD41ëƒuÄ¡I‹ÀÎ0¦Fć%,@D&4fÊTæš!Þ�C€¨†$âlîÌ´`Ž5%R¡bTs}æu ªP8ûAõ‰qL˜nžJ�(‡$’y³Ù@˜C§;n˜’j³t±·€ÆÀ� M4@ Δ›ô<Ý …*ÃqY ­h×À\jÂ�hxm= ¼¢'ÎjôÇȈ u±÷àìÒ É`8 Œ¸tlyÞqpÀ¼äXH1ó ‡ÕÑpG T–�…©9Áx©Ø$€(ÀT”à $ÈFÇ”ãkD-Â2Ñ· P»s5Q‚Ó×DsGB4x óâÀxpU8 P¾½ÜCa¦ši‡çÍ!06Úð@ù +‰Ã�ÐÃ@¢Å ø0?ì× ”T#:'·BXÁ58KOëõô&lŽQ+`ެ¨‰ FàX ‰“¡%ê˜îÁûˆƒÉÔV`‰TÉì*R¾‘¬aŽ�¾(R$Ë@6¬À!5ÖæÎ\9N�k pª` ¸È6|FMyˆZ4Ë©Y²ð ‘©Qr¼§‰W3{¨¥�µ&ÀŒ �@öè�†°M…ãdvØÔÌ;©bÝ óÔZL±lN+á6À •h£9@—-óˆ±õ£Ûƒ+�ì·‚D¶Êh€Ü4™<:æjœ¡5 £\I\}T "€Ére.hŒÐh°`3.f#þY&ÅÎ�¤DáTkHL@ Ò0 hNm’¢¸@`gj2P!=XãLCÀrgÆÀ|»d’H =ÄÊ0Щ2«¡Ø€˜– Äcº'uÒa4 @ E£ÌAÄš�Ð=½3à4.Ö‡;㊠O�#20J´§íÇE„&hŽC÷‰;ÑñºÐ-!n Ý#z^u½ P^jf�V€DsHD„ l4(4Õ©&ÄGĉ¨5ÎŽ=- & < § �A㬄EgẌ‚EÃÇQÂ<#-…3H�lc0­�O¦™;j�0/Bi´ÌKzHJŒ&ãh26`'ãðZ™FHÄ3W<(Õ�ce¨Í@ÊÐg^‰†�GÜ<"ÜÄ¡%ÞZQꔇE ;hdà™ˆGƒ,!רŒ1· È9OmŽï„ýHDÔcExΡ]¬4àÀ£!ŸÙ$€”jªL ,­çY0AfM$…Š ¬§Äã4Z�—$ ªÄ¥a#aÀNu�Š (¢‡ÜѦi:Ôy”Œî\ú´r„/E60®‹$4â‹ÀãÔ>¼>£D‚àF`z6%æù R¤Ù�Gs|¨Â]0h”u(”—Z.Íø0“dƤ3R9t¸ &´"y ‰ZƒH&• ¦®£ñÐá‘5§šJE=¸‚YÂK¡`^tt?%yà°8ˆð]Y4È9î «ç†œ>ȱaNð~$ûa¬h ”l”Œ˜ —ˆ€ D†°èYEpÜn"âDA6=X®€Ø9^š™ŽÁ±��v*›²�8Ù † í©€t'5Wg¶8Ńú‰šGÃ\û�¢‚(%öÁÕB­oÌa<Œd�‘ó† /‹ª,5W†â‚€B/Žè�•=úТ 9ÖŒ¬±¾@Qš>Tâ óaPœ•° iƒ1Ò, ÉËsŠ„ɺ (X84ÆCiÚcpò‚•¨$<&…¦+¡\"@±.iÑ8ˆ5‘è�5W§a2 ¢�ƒ[B£ñ0ÐË­Sr ,Oh‘9@•h ',A@≃pN‘£ý´'YMö œ(¡,±^Äã�ð]Ð(@M…—ØÅ(@Z� €ëXiƒ™Báx„‡e*W‚”¡š«3žÝOs"YÈ O¾hž‚E!e8…PÆÆOY0Ñi±`6I@¼#ò53dÐ]SÊ¡R.:“žì?b•fG¸ƒRÚ¹0W¬Ì•pC¡D8¢Ô„¤æJ¸aÐTGsLЂ8ª×\c切¬˜k”hB"),ÒÐ�0Døkb( ©[>¼B¨¦}ðµÝ€ ™ÇØ–óÂq+ð „h€4ÈótK ÁE8\B•DKQx‚š(#€6e "¥KæƒcpæÔi –˜6ô”$¬8žÂÃö�ÇA†Ê 2 ˆSÅÞOÚƒ†Jt=D%Œ‡iMª‰pœF?„�S#%‚B˜_~¢‰&Ù’` ï °Ãʉ²©tØP´CöPo€ÀO` ZóÅg‚dB,HТ{†Ês÷ñª8Gbá(�ðºRD*kx�ŽŽyq°æã+�€¨5ÈÔšc2U†\‘£1,òRd£,ìDaîŽ£Åæ aëP±‚¡UŒ^Á3d‰KÑÔ¸KJ(�¨BäY'ö•8TØØ¬™»rÀÁ*G@‰F  M‡*¼ÇÀÌ•¡ð•¹Àq�<0zò Ñ�a¨l4æ ©²è:ºÄ©2)82NMIžŠ8i°ðsC0*µ`šó`©2nBÑø�5 °ô‚f(c¨pÊÕ�„œð"åÒ´e†×8 {ꃌ[„ÅDДr†Iä¬1j6@êl¡…[†gÂ:ÁÆŠP³¼0WG#‚h<Œ â©!qú‘!Pgé£cÈ*¤äغ¦æ�´˜È0ëHG H$OŒ�7ôd%˜‰Ä#2¥±!´Ø‚­ h᪠—„à5&Ì|6p àÀH5—‚‘’ (Nâ€$ü‚pìÜ ‚è*FBÃÃh%¦�u°L80™LŽ,«Pì¹Rä67CDæ #{´}œ\­fŒUlM`=`A™â0C‘øÐÊARK#�‰�p ò €ìhޏ5ð‰tjñM�‡*Øœy1¤YÆ?@‘�’§X0ÕÏ‘¬¸)M–€\§($‘SM…q‚YE1µ º§Œ!£#-S­ƒE,½2„£i¦Áh¢PqEBR)� ò²h â‚Ê%ƒ0‰ˆ7U‚²©<œƒÇ°§‘C2¤(¥P³ñ4*\:º`é�—eRAšø˜o ’jÆ/¤�²µ .� ÖÌ=¸X˜—M€<ÈšÕHƒX Á±:–K eÆkÂd€ â5ÅGcl —æÐL tÀ†Jô:àYCÑ.¤ã  &iT£1(z¢Œ�«C¨ñžê HËÄ­´$ %€ˆœ7„ðkc—Äj #îT™ x‰“ÝDpLŒ ¥@Ïtbäl^ /0Ç@Õ�ç!�h𨺣‹RÎi“èp ¼0ư*ÀÄúð22€³… ¨iM!¨Q ¯�f•°Æ‘޲HèâHYÀãÉ�Ce¢1 6!™>5ˆE0a“L ÀiA,`¹ �¨’³>0t 7W¦%è€l€*9…*aÁ�ˆä�{�í2lÌ™qöB ¼È¸Ñ,<"Ãre\!°Û/�pQØPÄV˜pØ’Ì!N)Væê”dˆT�.“.AìÁKÂŒ£€dÁq±¥ÁIê8ã ¦ÐTOëðN§~j‰#Œ&ôØ�Nc’Ê$RC–û¡�ã�@I�ÉA Òã7&5WFĉã’aØHcóÄé§êà !Æ+Pœ›J>P,AÏ„¦.U¢J"14¡q3R¬§”R1J‘ ¡9np …9 D l¤Œ<ÂÈO>œ’qVƒˆâ�Ñ… ‡+Á-'´<Ѐv3DH Òt� h²^€fOëjæµRš�y,)UöQ?âg�)À©£DP\L!Á28Q pe `Nêq€&�Dc,b¨Â¡ÔÑ¡TQkèÀR ó"(H8¨2d:b¹b°,‹d h< \Re¦¢Z ºiÖ¾Ähq'°Œ)�i^U°Ø˜¯š—"Ÿ æ‡öQ àÄî\ [‡YN%Ša �[NXc–U f”S%Ô3ª©ÅC×ñì8 h‡¦šÖ�¦jx À&Tƒ‘BÅÎc:\B>eX$‰õ¡kO�ax”ªXÁ‘a`¸ªÂ R”c}†½¦©m(³ Q@4g‘øØ(a=¢‡…�ŒãP î°ÔT覚)ó¦ èƒe€lŒ%Oì$¤èÁÌÎAçctÖ@TcQA<=úN)I~*ƒ¿N:œŠ#(­2lP‹Œá ’›'´ÇX€LÇi G ·†Ä Y¸ ¯1µ3™@¥_$ŸJÀØÈàóh¦ZG@&Bd ¹š8=S"b€`Ø8;¢ÉÌ,ÕÔ5Õ¤ÃaeVG'Äš�,th`Û ApaájÀŽUN…�=zÇ5Ê7¸¥=¥¸“8ÔCC‰�hÙ¦8DnS"Ú<ž(d}¸”©½Ôh?€`ƒ!š øa/„Ðä{'ˆI‚ñ)0°£}Æ�$¬gö…÷XÐ!VPÀ“DžW?Eaþf°ÃĘ&vK,LìN…zP"·!2Rñ�<Ç‹8 †`J±Ê%Må™Õ ò¼L`q޲Lµ ²B@gHÊ3d%ë>p¢l„/C Y^ ¥JB9pL$ÌeAƤÇ$�± ™ƒÅ",zÉ‘M u$‰ Ï�ù ‚ßxL6ð�‚ŽÆ òBj®Br2D­”ÔA�úÑŠÒXJ˜Ì‹*F#/XpDhi¥™¯6©à�¹t„È nZ4C<@J€C‡”¹š¸>Å*TJ×±>؃ÜdGsØV@¶™Öì 4Ecƒ 6û=Z A–Ø óÄ5åæMA�T`”ZÀSå Ž 6ŸPó ý :w‹C!�’Ù×lG^@Êñ~z$4¼^ÁЧtj2e"O¡kÂÇÍAʃnDÚM(…SX^ ÆÂ, -Æ ‰ Zk ø«cû;†e $‡GëT.èæ¡¨  Sh ¾Š‡†Áq‚�FO€ÂHâ,/€hÃ3o ¶ ò:àK#@ki ¤�b� $3�ÈÀÚ™óÒL5õ¤Dü<5Çþ k„'KNÆé ™ 3öàd†ÕT³”±Šœr–¸ÃÁJšÌŽqÚa (%«Ñ¡€-–ÆKò0™ÿAPETAGEXРbpm6disc4part4discc5trackc3date2001year2001titlefulldisctotal5track02/03discnumber4totaldiscs5tracktotal3compilation1totaltracks3 albumthe album genrethe genre labelthe label artistthe artist lyricsthe lyrics publisherthe label commentthe comments composerthe composer groupingthe grouping$musicbrainz_albumid9e873859-8aa4-4790-b985-5a953e8ef628$musicbrainz_trackid8b882575-08a5-4452-a7a7-cbb8a1531f9e$musicbrainz_artistid7cf0ea9d-86b9-4dad-ba9e-2355a64899ea$musicbrainz_releasetrackidc29f3a57-b439-46fd-a2e2-93776b1371e0APETAGEXЀbeetbox-beets-00724b7/test/rsrc/min.m4a0000664000175000017500000001334615253035401017200 0ustar pieterpieter ftypM4A M4A mp42isom ŠmoovlmvhdÄLé_ÄLï¬D¸@�trak\tkhdÄLé_ÄLï¸@mdia mdhdÄLé_ÄLï¬D¸UÄ"hdlrsounÓminfsmhd$dinfdref url —stblgstsdWmp4a¬D3esds€€€"€€€@xú€€€€€€stts.(stscÌstsz.22""'-+1/+&0''&%)(-,*).)(*%)-4&6.*,$,3/'& stcoÆé •udta �meta"hdlrmdirappl°ilst©namdatamincpildatapgapdatatmpodata6©too.dataiTunes v7.6.2, QuickTime 7.4.5¼----meancom.apple.iTunesnameiTunSMPB„data 00000000 00000840 0000037C 000000000000AC44 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000¢----meancom.apple.iTunesnameiTunNORMjdata 00000000 00000000 00000000 00000000 00000228 00000000 00000008 00000000 00000187 00000000\freefree(mdatЃì\«11;Ä<Àøƒ¤4„ `I�fàe—^àï�P0#Ü·›�Áb˜Ä»VOØÙ(*¾J€q8òƒ„q©-@>Ťè[-3þ!‹rtg¼¼(ι¶q]b¥¸úƒÄPEÙ€€ ª°DãÙ‘>JUl3ËA$Ö)i)ƒÀúƒÄA#�€+:3ï`Xa¶™˜ÉùQ;«À±˜ˆèàöƒ¢" „Î Ž× óf{q wZ“Ä 3z¿f#)NÙq'øƒ¢" „kËr½ÙÖ£ g�§ý'”ê )y*¦˜Úö»,°Îµx¡úƒ¢" „r †BXVFìì7nhϦNž|z%ôe0Ue®«Œ œöƒ‚B„_`9åo¢ðJ­Dz0¯)òøáÛ1F8‘ú·åÉ>7t·#‹Uàøƒ¤4#ŒXÛõÞ™¾áàÒ`¸Ž‚Þ×xT†aGˆ~fäHv<ý¶ÁÀúƒÄ`? &ˆ×63Дl:äGàë’ 莵š„ÇÓëåN‚àúƒ¢R#Aש9Ï<³ÔiÇ%Öøê¦—µŠÍÎê®yfžÎôƒ‚T„ `®!�I}uhnV$?‹+ä¡(Z«„Á�¡Üta¥Vi±+±l‰8úƒÄ3#P�0¼ñ•T`’3¹èžÓ#?}¥ÕõÚ»ìÔ‹€úƒ¤Q#Hl`µˆÁ½¥ËK§)Q)E‚ñõ>O²Âô¯SÔ¦úƒÆ"#P ÛdpËŸ¿Û2é­~sÛÈÓï�'Pîì=Í&ü!úƒÄPG<Ž0NÝÍ�Eø™_ƒõ'1…:õ˜‹å\øƒ¢ ˆ,l ƒq¼Ôº<�¬>èðÍ&ïÞ¦J3}•]dQ€€8úƒ¢`F  8I+–¶:aá–;0¥Ç>m>;ßM¾íÛ�Ÿ× ¥/gøƒ¤p>€ÞbSci›”¤L z:~H�5ƒM3©'°A+è&„f ‡Ö(pöƒ‚0!dÀ¢’¯:%¢C°9B³î+]þ3Z†¹ècJr†Â¶�öƒ¤`E€�a,]µ)\BiwÈ,yç@úD¸ù�ü'ħ¥¨Üøƒ¢ ˆÐÀ€0qóà=bžmBÅAwùH°×! šDSª� 8öƒ‚5 !`Â4†§å^ñíª^:$9µÏ…gs`M%…ÊZZtª^U£Y(o€úƒ¢"ˆ¤09œ’#NÑ·#̬zÚW›;t A-1dyß”3¤^ àúƒ¢" "ìFâwì¼ú„,µ¸rŠþ¬js%”ŸÒísÙfžep=¼øƒ¤`G €@ÀãÒ5?à¼`•Ø�ÉÍM²ÈöÆýYB^×;C€øƒ¢`BÈ ÆãiRø—‡iéŽ6ˆ0 9ü¾åÓvë…(ÜÿÿGYJ´…=˜¢oçlÇWøƒ¤3 BÐ3ÜQhLÖÆ$/ê‡b<÷~³µ8ëûÛΚS�­n*jõXeÅ×7’#àôƒ‚"(„@Ø Ad¨*Â`óÙ'ሬÁ®co·>Vûça &µ% øƒ¤`F‚ ¢±äßxã}¸<ëÊüfP[2ÚqXä.Š'Iµpúƒ¢" „¤*ÓØšÖ'êŠÇÉR™z[oÝÓ¬ía‚„¾”XÇS2p'ÀøƒÆ2! éZðÞx²µ¾ùìú$©¿Vn´%j(óVÀöƒ¤`F‚�€öŽ�F†@›c}}ðCÂ2>Û<ÆçO5£!¹QÞ/grD�ðúƒ¤aBàô‡2‰´S(^®Z�dð{¦P�¤Ÿ~‰ÙÛ˜¦‘6 Sºœöƒ¢ „,`¼-1wNÞAÀÍ”XPKh¡wKÛ#0R¬Y±X�-Àøƒ¢`E� "ÅImq¤>w¢È1s5{!ÁXº[¯/æÛ?ÓG�¥xøƒ¢2"%€Xä  aÔž®ŽæÏû©ÆÏç¿÷º�r¯˜LaÀƒì\ªRi"?pƒì\¬ „ô@À\beetbox-beets-00724b7/test/rsrc/full.mp30000664000175000017500000003102415253035401017366 0ustar pieterpieterID34TIT2fullTPE1 the artistTRCK2/3TALB the albumTPOS4/5TDRC2001TCON the genreTBPM6TCMP1TPUB the labelTCOMthe composerTIT1the groupingTENCiTunes v7.6.2COMMengiTunPGAP0USLTengthe lyricsCOMMengthe commentsTPE2the album artistTXXX;MusicBrainz Album Id9e873859-8aa4-4790-b985-5a953e8ef628UFID;http://musicbrainz.org8b882575-08a5-4452-a7a7-cbb8a1531f9eTXXX<MusicBrainz Artist Id7cf0ea9d-86b9-4dad-ba9e-2355a64899eaTXXXCMusicBrainz Release Track Idc29f3a57-b439-46fd-a2e2-93776b1371e0COMMhengiTunNORM 80000000 00000000 00000000 00000000 00000224 00000000 00000008 00000000 000003AC 00000000COMMengiTunSMPB 00000000 00000210 00000A2C 000000000000AC44 00000000 000021AC 00000000 00000000 00000000 00000000 00000000 00000000ÿû`À F=íÉ‘A#ô‰¹ÿÿÿÿF0ÃßÿC ÿ_ùïÿÿÿÿóÏ£)çÚa”2ùŠz<‚žyõ=xù=O `ÐÊÇ�  ¥à�Æyé>`øÜá ÐÀXè" z)ãBœ"À$)‚ �A„ ÿÿÿÿÿøÿ×?ÿûÿÿÿÿþ¾Ývb£×B�¬¦ ³4Àã°²+¸µÂ¤Ír¹Á�ÔR°Ä%;�îR£Q[ÿÿÿïÖÜîÿ³¾Ú7UW6dTUT!ub8´Çø çèx?ñ.Ì€ˆˆˆˆ�ÿÚÚ¢³<ŒaeŸDY/ÿÿÿ½ÿPœ¼·$D¬(躡ïPŒi§ÿû`À€Š9à… éâH#4•¸‹RÒAbÉuÏ&Ž ü:=ÄÝL´2!Ô¶#9îŽÔ#"5¿ÿÿÿú­ÿfE$ìȉ,ª1HËez²1’ª!ĨR ˜‰Ì§)¢((â¢,Êc°š)ÄÜX¢¬,qE„T9N@øˆtÿÿÒþ÷ÿ?ÿû`À ò= mÁ¸È#t�¸¿ÿÿóËäܯðÉ÷IN¡æiÞÿ{ÞžYg§S—ÜëdE/'ÿÿÿÿÿÿÿçþ§Ì¸g Wëï&%ÍirÄDuñ6.ÝítÜ‘mtP&ê,Ž�«¢’Duhâb¨D›ÀN±ÿÿÿÿÿý`Zÿý{ÿÿÿÿÿçÌímÞó¥/Þj¾GH„<&ñÎC¥ÿü„žl÷ÿÿÿÿÿÿÿýþÿçJÎÉP��1•¥I’òÔä»ò9£3³ZHFÊ;ŽÔr/viƒÃ�1  Ü‰…£2‡ ìÁ�ÿÿÿÿÿÖõÿþyÿ?ÿÿùz\¨Û+dDΪ�1ˆÆckTIw˜ÿûbÀ æ% „MɬH#t‰¸™¨…¶R²¶Í´öÿÿÿÿdÝꓳÐ÷1êr© ÊϳîÒ»³lÖ• lΆmC‘Uê÷c,ì$(tÈ4BKÿÿÿÿÿëåý²ëZSÿÿÿÿü¹QRÅ­ÝŒ‡>³Ìl®®è§1Œ¨ˆËf:V¨m&¾åDGB;?ÿÿÿÿÿù­RÌé+ƒ9‡}•+ϳ+±ÍUÐèÊbPSú;1Œ%Ü; Š…R•Ìwt”€Î9Bÿÿÿÿþ¶ƒÿëÿ•ÿÿÿÿäìúRwó5�lª„s>ʸõ#ÌäºuFlëÐêɕћÿÿÿÚÿ³«ÔªFJȪyŒEus–ÿû`À" ? „­Á¬Æ#t•¹a2ft*3άVwVl̸â•êc�@@Ç‚o2ÇåQÇ;> ¢£€?ÿÿõ�sÿÿÿÿÿü»µ®å:=¨îïv:ºº•VB/Îlêèö-ÊZ$Û™5OÿÿÿþÍ'*MD£�'» È.–z¹›S«”ÌêW!„Ça溡Z!3#NǞ#!ƒ¢âcH5VA¸ò¨`†`±�óõùþ¿ÿÿÿÿ®•g;RWT�ÙUÕ½ÔÝQeÑÑTľÎB%OÿÿÿõùÑgêÕ9F F‘�T‡j9"Î(cJb#!Ç�xˆÕ3³ ªEÿû`À, Ú= „­É¯È#4‰¸vcœqL8áaàÊPq¢�Ñ2$48ÿÿÿÿþÖ¯uÿºÿÿÿÿÿ?£‘Ý”„5›Rl›ogGÐŒªöi7ºÕŽ·ìKwÿÿÿÿÿÚÒ"1Ý_™Ü§8¤T„Dg�ä;YƒœFä%PìÆ \ÈäRŠF €‚äS3: ÁÈQBªà•Ü(ÿÿÿÿþÍ�—ÿ/ü¡ßŸõÿÿÿo‘œíbnYØz(‰‘ëu×J:ä·Id£ïZÐÔÙÿÿÿÿÿþŸJ'»Jƒ Ff®ï©Ne+ È 8ä*&*†q2 0�Ì AŠAD…0’�Q!2ª”¥A§aQEÿû`À6€ ¶A „­Á¬E£t�¹0ÿÿÿý°/ó׿ü¿ÿÿÿÿò]s¹œÐô… 仪Dþ9FzÓ¦[7‘t¥+M¹2ä³ÿÿÿÿÿÿÿéÿ9æÓ*FE‘D‰»ë2³×r™9“Ò·I­|¼UèÊã±Áz°spÂ+† JÛØ8ÿÿÿÿþ��©ü¼ògRfÒÏåÿÿýþ•$íc1üý§º!Yz:d÷#ê×*º%Pú?{¯ÿÿÿÿÿèɦ·5\ÎR£¾ì‚ŠTv{˜Ä$A™ RkÑi†ˆ!£±ÅÊ�Ö(|¨rˆ˜pðé¢î<ÂÁÀ+)�h0À5�"ü¿ÿÿÿÿÿdîÿûbÀBVA „­ÁÄÇ£4•¹�F±:¼Û>yê­)Ý�ì¬åºQò²+7cfTÿÿÿëÙ[óÉW£•hr¿ÿÿÿÿ�iO‰�&�׊aÒ¶§ö’ѺkL“ÔW0÷?ÜpµpÝÿÿÿÿÿÿÿ1ÿ×ýúÚuz÷¤sò8ë›~9�çˆ^;Ž’˜…ìar:¦hZ—Ro|†AwÚÖìXòo®Ü**>@Ö0ÿÿÿÿÿëËWuûJ�FÑYìîåˆòYÙræ\ˆîjí»*"±Hßÿÿÿÿ~î‰m¨—g*:˜…+"ofi•ÞÂ#E� �¨²)JçWACê,$aqÊÇ)„€p1Œ"Pè‘ÅH‡(Ñ¡`8�ÿûbÀo€5 … ɽH"Ì•¸3èòÿ¯ÿÿÿÖ×Ýzè¼ì×»Èr/È¢ Ê®”d£3Ñ—yN¤qÿÿÿ÷ä{"Zåu#ÌeR ¸ñŽÄsî®e-ESi‘�pÕ( ›0“�„bŽ3‡Àãs�†�yNEr”ÓŠˆ¨€� ŒÀÿÿÿÿÿí�yïÿéßÿÿÿýz.¥1,o5ä+9·Ežuvf±Îõ¹v}ÈÈ–NÿÿÿÿDû}l³µ+3UTŠCo¼¥>%èOyS!�XŒ‡‘Æi;�\ê8#)Ń:‰cÅ•Êt(P‘À?ÿÿÿÒÿùÿóÿÿÿÿù´š÷fÿû`Àx 9 ­Ù¤G£t‰¹b$„vºftgdû©kU-™œèƤÆVäfÛÿÿÿÿìŸêR>Ó­ÕK5(i5; Îñ“•ÑŠwiÇ*¹ˆ¤"âŠ*.*1â¦c´x´çRH@“ˆ#•bÀÿÿÿö@¿ÿ-»<ŽÄjµ=]ÖÓTª¤®Æ96Kä<îäsn³¼ó—ÿÿÿýv"Ñõ{Ñ]LëgR�g©ªF5ŽFuõZÇQ3�QÓ ‡Ç°›”a‡¨Ô ˜µÌ.tP‰GQCå<ÊÿÿÿÿÖþ]ÿþ«¯ÿÿÿþÞˆy‘žr3ÚÛg§Ÿ¤m4U++!d“Ö¶_J´Í{ÿû`Àƒ nA „­ÁªG£4¹ÿÿÿÿÿÿÿÿöù7ÈqyiHsC0¤Er_?* –gÐNP�‰îF¸v#UCªˆ9ŽB!* jè�A‡1Y(0ÿÿÿÿý`_óòþ_ÿÿÿÿüßíÑžïzJ_¹K&´išôE3Šeu!&>ˆˆþFÿÿÿÿéÌý<ˆs±Q#•ÞcÚï39’Àœ“Ùœ[%ÜÑÝÄÇ8s¸Îd†; áXä …C0­ƒÿùZõº�Výi ­b¹*ªOf3U§,ÍD=®E%^ÝËÿÿÿÿóHêí³=Uή¯­]�™žØâ®ª9ÕŒfd#9ÿû`À� òA „mÁžÈ#t‰¸Ñ�Ô�¤C»Tˆpø…Å”HƒbÈ s‘� E,*Qÿÿÿÿÿý`9oËêkÿýýÿÿÿÎë"åE§KQîÖÝ�Jî·<†aG TGȪW›F}]iÿÿÿÿêÞªú#f«¢Ì¨ÅUTH̵Eç̪·;f¤€ÜâÀÙÑÕN]Dœr¬¨qNÈaÝ(ÿÿÿþ²ûçþ}~_]ÿÿëïôìÌÇûèw.šQÞrØÌÌäb-lzèÒÒšÿÿÿÿßé­ÝíSUÐæg«DL†îB�ÓœxÝ� ¶QE§™ˆc±îD €Ñ3‡PƒÃ¡ÿûbÀœ 2A €­Á²H#4‰¸$)Ÿ1Qd‚ £ýÿçÿÿÿÿýÖþ—tÍT!˜¦ÈwS5îêëfº�ÐÅ*”�lý؈ŠßÿÿÿÿôºµYÊÊKžÓÊÄB²¢�Ïvj±•QXÌB *”a”£¤q3”Á7 áº¡b±Îƒ!¬k **�6Hÿÿÿÿ¶ü¿¿Ëå_ÿòùß%é,«¿uÜöeæBÊìöJ¹Mwº®í­]Õr«7ÿÿÿû¢Ú®d+Tµ#!•ˆDeœ‡æ)Øì…F•®q`³�QËÊ·K ‡!:ÁÎÂÃ�ur‹C˜®àÿÿÿÿú@¾_âüÿû`À©€ ž; „­ÉÁG#4•¹¯ÿÿÿÿçïÿ%2ó¥xzžõËa©—ÝßÈͶMŸšÃ™);þe­Ûÿÿÿÿÿÿÿÿù~~KrS¬[uvzŸzYq¢ñ òlQ�wÑß#}¨\‰jZ |‹T �¸Ä!ÌéÀÀàÿÿÿÿÿ�Ÿž Øç —Ne9Ÿÿÿç eR!áçÖVê¢õœ}!wÂOí3UUÚZWU>ÑÿÜWÿÿÿÿÿÿÿÿ?íñó÷+kLÖÃùŽ*Øëk‘s*—gJ�4`ž¹EÆÇviF"‡$˜z©†9‚XõÂa�Ë”9pèP·XT]Çÿÿÿÿÿc`qîyÿû`À²€ .A „MÁ­G£t�¹‰#±’¿%¾§ÿþY¸tûîú㙬ꙉy¥˜†ýwŠõÚ©¦÷ÞÒ¥©S»éºæÿÿÿÿÿÿÿþÿ¿ÿû¿Ž¹šk¯«YO›­²<6<’±…&TÉ눢Æ!wB±E2ˆ ¸ö³J‡4\V…K1`°’ކ6Ëq1Š@ÿÿÿÿý±ƒÍ#˜Wå¿Ì«ÿÿÿý:*\Ȫuo™��H(έb+JB{1¨¦î·±•jjÿÿÿþ�7¥®·tT2+9#ÝÖ<–ºœÈ©*­ ayŒQ1§3•Ú&=¥B�:``ë‘‚¢§Š ‰Zpð[JQÿû`ÀÀŠA … ÂÈ"´¡¸ €k?ýþ½ÿÿÿÿÿþÕdR•¨É¿WDJ2oR›±ÎÓêUd©Šf3¦Óo5ŸÿÿÿÿòKk­Ê„y™bêìêt3–S’È5‹Ž «�,† 1 áòŽr�JâŠ0¢„#(@Xêè$,�âŠ�8Š4xD*…„ÿÿÿÿÿ’Ëäû×ÿÿÿÿûνey5v}úº*±K÷U2‘ÖgR™–tK"µoEÿÿÿÿÿéîíLÊŒE:2+Ù’}Hî8†fc ‹³)†ÅÌîìBˆaÇds¸“!…„XPr˜xñÊ,Š($0<*5 †4lüÿû`À³€²A „­ÁÛH"ô•¸Ö|ÿÿÿÿÿÿôM‘Û[VÛ²NI”¬ÚÖçbk3›ß¢ªÕ‘Z~¿ÿÿÿõ¡j‡»µ¶g*•Ø”ssB«¥r”¬QGª‰ ”„)å1˜0‚ädÆw<)]Ì($aE8pj‡ÐhÀ³˜À¢¦‰€ÿÿÿÿþ��ßüÿF—=ÆÚþ¿ÿùå®›±÷õÌk*"§f5§¢*YÕC^bºê§»LÜÕ²ÿÿÿÿÿëî‰wcª¦UÎ<Ê;0Ô=QÖ«žŽ¤�:³ó¿ÿÿÿÏé¹&q…+T©µ'ÙTU•ŒgeR á‡B32)—ýž·D|ïÿÿÿÿÓ]«Mɺ+YŒ[Ö¦0Ò)ÊbŽ¥Ž5EQ„ÄEa!˜\h˜AÂ!ذ ³BÃîg À(ñá‚ÂC &P 8|DV&Qÿÿÿÿÿû`À´€ÂA „­Á×Ç£4•¹ÿéä^¤–ú,‹ÿŸÿÿžÒ÷f»‘×d[Òº½ V¹Lës ws)P§z^¬t252]koÿÿÿï§£÷]»ÍÊS2•gsƙٞDkaœÔ9�Ç#˜Â"%F âƒDL*£¢ (B" ‡XÂŽAìb¼>ÿÿÿÿÿ±…åþY//ÿÿÿüæ©J$î”Y?RºÑôVT}ÞŠrQKjßZmu}vÿÿÿþ«ëzttz%¦TS•1ä#ÌÆ½�j=‘Òª”ªQ!0c ÓH,¢å £ÄÄÊ,¡Ñw‡È 8ç1Ðå†0¸ÐÛ ÃjÐöÿûbÀ¶€A ­ÑÙÈ"ô•¸}s—ÿþ¿ÿÿÄ@÷:XÈ®M*¨Cc¹§r”ü­#çDQz­ªý§µ)ÿÿÿÿýþ–ÑNbç›-LQl„0׳ )�Ük ;˜Â,5ܣŃ‹;"Š 8ЦA¨$ÁÑqÆ�\M…EAB@Áç( *ÿÿÿþ��ÿ-ã4Ñ—pþRÿÿÿ³¢îVlìU·K&öu+<Ï™‡tLììv3¡ŠÔ³I{×ÿÿÿÿúûû•YÑ ¥*«“êçªîR†Ð<Ž=ÇÔLU…aÅqáL (sˆ”ñ¨§D4P€È�‚Ä !˜€8ÿÿÿÿÿû`À·€’A „­ÁñÈ"´•¸ÿìŒ w"šçÏ’–«ÿÿþMÿÇýwóó¯÷Üu]fFÌÕH÷SR‰õô±×K¯×ÿÿÿÿÿÿÿÿÿÏw§qóßLò°»O¥O3r²1GÔ­mÍ»±å;=šSÊ8y£2lÏ#•0ÑÄÃHˆpò �¢¥�% « €ÿÿÿÿÿ²ŸÏ_åËzÿÿÿþþŠŒ÷Z2>ô±• ŒÌ]ªC\�È„VGGuyÕ(Êr¢J´ÿÿÿÿû[BUÝŸaj«ö£[‹Õ™HŠèãLRˆ˜«yŒ‡œ¬C%Üq]Qbì->A!Y�â†`£1\Xâ@`Ò y?ÿû`À·6A „­ÁâÈ"ô¡¸—#ÿÿÿÿÊ­ä&ʪË�ÕèêÊ}V¤1Ö³Fnn¹:û[¯ÿÿÿëmjÌës¡ÒÕF!ŠbŠê®Æ)˜†‹‚*‘LŒcˆ°�j¡¬*‰¢ï0p¥>$av!œXè4DHÁÁ5‡ÅĨU(p@1@ÿÿÿþ­ƒüŒÿ¥ÔËïëÿÿÿ7êˆìµR!Ÿ#£µŠè¨~ܦf5æfb1ÞŽÝS"ÛÿÿÿþßèÍiš£P®vJÖ®d1qèq”2ÚÈ0:Å+‘Tƒ6aÂbEl?2‡DD…‡‡\M"B £¢† ”Ácˆ4\6à ÿû`Àµ€.A „­ÁçÈ"´•¸´ý¹~öÿÿÿþT«Û"£—ÜÇž—ÑsÙÑhê®DÎmYd½îdSnÛÿÿÿÿéí¾­:ª3š§š•c%®5HQU<§!ÅEHcDH@8â(‡E`=‡(¹Ã§qR¸²:$&<(j¹‹ÆŠ¸  ˆhˆØ6­ƒóæ¿ÿÿÿÿ#í%)sMªØí1ærÚì·IUkwG‘rîGtTe÷Ñ—ÿÿÿÿÞÕêÛ++Jζ%ƱÞÈÄÌ<‹;‘XÇ8qˆ‚:‹ Aa6qe- @ÊAA¦`‘Dˆa"ÄÆĘ„@ð™”:?ÿÿÿÿý$ÿû`À·€A „­ÁïÈ"´•¸/þN_¬™ôëÿÿä ÷Gõ>¾J¥Ó:²�—G4¸±Q(„tC\î{+©•®gOÿÿÿÿ쮕½Ôˆ³!O<®ë!¨Žd,ŠæR1>‚%f0°¬@ê>qâ¡ô (¨˜åœ4ÖQ!0ø€ºX‚eQC€ÿÿÿÿÿÒäþgì?ÿÿÿÿÿ-‘œ¦ŽI"*ÌD£™•̧Y§In–jH~­’Vkg»T®Š¬‹ÿÿÿÿ•úÑÌŽäRËÕ®¬–K¦í[ÝF"Ψpá®ås ƒ”<îƒáC‡A r$ò 0ˆ×R‹ŽÌWˆ€ÿÿÿÿÛÿÿûbÀµ^A ­ÁéÇâô•¸½ÿÿß›ÿÿü¿->ùŞó/ß&@ºÒzšºË)¢Ô-^Ÿð¼Ž½Ïmûÿÿÿÿÿÿÿÿå‘ßæe ·îV›E‚˜6��Þõ$4C¹»¼­dPÀŽŠ$B¬ŽAÅ£E "£,†8SW©9 € €`5‘çÿËækúëÿÿòÿZšçTC£ú^5Ýõ‘œ¨bT©‘Üz-®–™=¤½ŸÿÿÿýiCž”èËB)©au”‚o,ÑÈ8‡c‡ ""@”AÐD¥*<:*‡ °x:@ùDEEH8:.Œ…Ї†ÿÿÿÿ¶ü¿ùëïÿÿÿÿ©ÿÿ–ŽÍ­îGH¢’°»NÞ±™ÄW%²zÕóØøDo“eÞÿÿÿÿÿÿÿþ_ü?)¹leyX†¿ç)ΜzR̈Ÿ"]Ë•L´'dxÈÐtS 3j±Û é àÿÿÿÿÿÀ~˜dsÿû`À½€>A … ÂH"´•¸æ½ ÿ#ÿÿÿ˲µÐÕc0‰&V‰ZâBÅrÌdpëFEyFˆm ¥*³¬Î¾ë×ÿÿÿÿÿ¿¿mYÊŠVÊÆ}LêÆ+>j=‚¨,å-*UcÅB²=� QSÎPèÑÎ"ÊY˜H  ÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿ¯ÿý~Æ(`JEª*!ÙÙÊbª”Vs ` �#³±Š©ÿ³”ÁB(ÿû`À³€ n? „mÁÑF¢ô•¹ÿûbÀ»€&@ÞMÀ[Àÿû`Àÿ€ÞÀbeetbox-beets-00724b7/test/rsrc/unparseable.wv0000664000175000017500000003120015253035401020656 0ustar pieterpieterwvpk 2D¬D¬¼â¶é!RIFF¬XWAVEfmt D¬ˆXdataˆXBWWGVHCÏßïë –eŠÙÀt@¥¬ ‘ɦfÞ1/°¤% ˜k^‹�™«\Á¥”Eãž7h… <–°ÍeÀD*ƒb=p™bE‘ÎÁ¨¸‰±I(€šxÀ‰À(N%ªT£´°TéæÂé6™r¬‰�Sˆ(Ð`xtÔMI)gÙxL¨Up M ”¾¡hŒ˜`pH /Bš×`0â@ 7K6ePÉ=J8(p²Íü†Bd h s�r`ÁMybáhÎn2÷T £�ð6Á�:ªû�rÇ`…ŠÆŽ’Ñ%"39>JL9Æ uì)<ÚL;=&B8GAáøkÙFhF”›;n@+A¬P`ÃH›AŠFÖ$FlŠf¾÷À} f©S›áDœ4/°Q¬RÀ+žÓÒ"(â°¤ � WéÄÜ÷´),²0±µÐMP„Þ·$Ë„ÇÄÁqŽÒ�Fàd-À×?©µfs�h"¤ aXjªŒ`²<½†Ã•°9Œy1xŽÁ‡êrVœu°<Õ.™î¤¢Ü>¢q±Ä-8np#á8ŒÜ¹âC#yT†1=Æ �ÔÚ@ÈÅNòc$ŵ’Álrc U¢«‰ $¸O–JªFQ ó&³Qd™ˆŽ4/ z @jQ g(l ÆÖ4ƒ3ùJ�~ñfИŒ1¦Š%€˜¤ÃhfTÔàôN¸àc“8HàLaD R+‡9QˆT~„ºDÃŒ2:Q›IPvjŽñÁë atÚX�Ö!HªFÜ °†ÃË)Ì15ÕqK P |–MáØI=�ŠÁJ`�Õ±êíÃ+D™™X­ƒÐƒC=�2™7TŽƒJ3)‹cðáDÍ,É"¤ÇñQ'#z¸PúDü—‰6ø RYÎ;ÐŽB¨¤4Ž']'�T ¬À‚D3@ˆ…ÖœX J|påS ‰ š�‹Db2Æñ|! xg¾pÈæš½=¢^jc'ɸeÜ`ä&À©Ð DP+ÔÈàˆÆŽñXÈÜ% ™jªY–ôjX†ì�j‘l¡:dÙ’Û[µ>4& Àá>Ä� ĉÒNЃøáhŒå¥€,d N¢³q<^@b…>Ög¾ÁÓŠQÏ:X-è`“Fø¡AØ\�¸~¢µfs� µI”Å’Å óˆNŠãÊñ¢'v‚nBà„ž¹ÃøP.”ãA9؇2Êic"Y è�Œ4FXžªa!�ŒP§"øøcb¢ã(ð’¾A6fȈùÍÈÏ@q*.¨`¯[k�j®Ò ³€‘�c¨YÊñ+ìx„j‚áX‰¾B$ìâ\R+ÈD× R‡€fÑD6ØT³,é"l,ÀRÂ’éŽW€PxS="=i t 7©åT3A˜—0`d„ÜÃ�ÄQ0$Ž2îH;-îÁ�b5Ñ`´ ÈG˜N4�ÁÓCO†P–°¬ì†M! ¤ YpJ…ƒ”ŒD  m€Ø¼,x ´1.Â0 MÆÈÃÊ•DÔœ€´Ñz")6÷Á± P,®hôÀFÕ\Ò�š–t?Š‹F¦‘6²ŽxAkF—X˜äjM P#Þå¨X`dI4Œ=�ø(£ 9» 0óå·�Xš€—tì`¶h AÀÌÙØ#G€¤ÖO†Ö 4šÃó% ÁNvº¨%„N ZD3”¡-97 .!í¢ÎäÄ÷iA”‘ŒÔ X‰à;#QÀ&܄쓭:LtnT‹ àhé¤mP¬„IÁ(ÍK Ђ¤Å-Z¶GO‚d‚7ŒP@g�Y=˜ž (‘¹‚p%l!HLJ|ÂʤƒfédÎÃA�8>@k0'-?c¬ƒÍ‘ Ž‹, f Î¥“ „d³Ã’jØ)2q ¡‘…ej0§ÈhAPë©®=a–Œ2`©…Pò\wç�ñP0Uʼ¡P!à˜gÊòÀ± €§¶X~œ˜µ¨¹äl8ºH,f³ü:‹¬àL;ÆÔ¹$vÂCHª@x?V  Sí0û#"³:X3¼� ó’àˆVŸàÆCEÁÀ4:bqL$`<¦¦„?L5/•ieââ8{`hòbXs¤á`€©…+CÀ”T€Ú2¿ÆR(™º¦šj”ƒÇ*™x„yXòŽ­ #Mb‹p8‘‚E5Àcº¨ã@#+�Q�RèHH>º@áÒ@4ƒ¼£ޤ“ÅÙQ�%óRH®°ôpS�*-¦ñ—h ØÀHä Ï5Ê6Ø9; LT>•$FŽ5hYdaÀ”â2CyìÇGÉ0‘A®A>A#•©õÁ:`@=c“.Tx™1 ;dX%‘ >�âÆFEæN€–²@H‰ÈÌ�Á™ØÁ­Á `æÊÜà@òX% ³ÃX€‹òŒ©b €Xê ÙÜ™š AfS(ë1ú…‘ÙŒ  £™€g�fò…YDËx aP¤J4@"h„B¹ ó2Ã/ È‰ŠŒá�æÊ| ­� ŽÓÈ Ç†m*ˆñ46Í—ªÇžðÍ åx‘¡ Ô´�Gp#áx/Ôbã[€ 4¸@@ -æ$°TF9n€‰g²˜Ö x�XöêŒ�¡Âš¹Z³ Ël a#©*èhêT¨yAÙ#ŠqÁÓYO°ŽpHdJÓNbÁZ‚zºñŒiʧe“Ê«ÇÐ¥2Ö™„£`Ò×|Ò•%‚I°ˆ‰™'(‡ ˜F†*’ÊTó�Ö¬ŽòHƒ+ZÁA” &À˜ K^ n( I†�ŒkŒ`ƒèÐ8°ÜÀÈ#‰tˆ2ÇÂ%ãùaÞit�¹ˆA’AAU¨fýÆe"„±8Ôä²NT² ‹FÑc=•ÊÛpJCƒÊ°¢‘Âø .A<Æ&&ŽÆÌÀ£�Y:ÇM‘‘€‰Àžõ1yfK,(�$£Ê á<àÕÀ˜ kʔ߄‰Zk$AÍ’?AÌK@A˜ÇÑ3%f6” HS£µ)ÇkÀ °ä g;Dµ{”‡ÄÁåÐ8Ò@$p ÉÑ�$ £VÜMÀ<Õ-" S‰; G4M¤g=AsMzMæEe.¡� 0zˆbeÔi¬;óöá¡dî� ÐD °Åå´L¸à0F X9• ýR£Âw±‡¨â—) Ù1& ØyˆØWr”ešmŒ6³MÔ,¤ç¾È´ΡW‰Å²§²rÀLd“zê¥ã�²y1B6o' Ê‹—޳Q–À*KÐ"04EÄ´1qù¸¡ÛAš@�õA›í0ˆ¦î©†ì®K`%(·5'‡›ž¢\ÓåPgý›˜±&´™’€R@3 N•Âu4Fáøø¨xA ‘kFð(;šã×ðĘKJÔÀ4£Ž“GÒ8 DHŒ�Ó ccͰ ±2ÁÂú¥Ábœ…=];p™PÓepj@� ˆRâÈóH)Lö Éu¦«sɼÄhB6°0fŒI)VæÞ2HÉL’`�p| £%3„JÁXTƒ€òÕá×x´£Ä¼ Ú”3É Ù@ôÃ"GȤ j„6M ¡(^kFá1yf�gà´L´d:*ã%¨Ý€=XÄòÖMAæÆ‡ó …l¨Š*E ™J�ìØÀ@qD¦»á†#PZ#ÊÆDGXœi €/Í7šKÉ�–�tAÑ b�ÚS@t\P9˜n ѡ°k1V(Tr18��°�DŽt”ƒ�%€‘i2E&¬Çü†(œˆ†s±Ï°Ê­€>â–à…‘4¹F “DÍ/ÞûP ´Çä±â̵#EX2yÌ•Dd”%3L øOÍÑx… {Äp Xçø‹PAj¶æè"Ô©‚ŽKN4uª @X6Å'Rp ”T„é�˜ Z€XŠàÜ  K`‡ŠF&­D†!¼CI‰ ÖŒGt„F6¡ÀuªÃ9À@2›ƒ�„FرÅ@b¸ÆdA&¸Nu�”$c1Ù˜S„,W ªsâÕ¡�r7@²°ÂGÃp4�ø€<€‰šÌMˆ5E`\Xd€Ø£$å1¸ÃD­5’ p¼ˆƒ,Oìá:6☡'†‡”*/Š"Ì3ó�€P¡^´%Èe"‹­h"uC‰iÍ ež’ÖF=ÆÊ¸ÄH¤ã!„KÈ_²uH$Í¥ÔZ 3ø0HøqZœ6Š�”Iü  \�'V rePN¥†fã%$R‚ñ-s‡p�±ž˜8„»`ÎÐ=¢©0_4¢h¤ˆcýETØ‹ÌAŒ¹´�ÚP™_À€š/1£Á- D5¥–Ž€™2/¡ÙÐR@ç!àG'ÄxâbÍ�<Ë%È1–Á8l8pzp€ Ì*Ñ�³Œ1q‘PŽ• Å 9Ö¡A¤Ê•¹‚Dƒ(P¼¾ A �H¢W„ã"Š%"GÄÙ‰xi‰ÇhûdN•�õã¯?T@³ld A›Êšå\‘a 0i�4ѱ.B>Ëbî3sx8ÃI¿ 8\ “wÀ;Š !åF «‰—:x�SSJjñÕÜO…”!È�2îPy0„WãÑX $Ó@†¯7RjèŸ;À|á#e®¢T¬²ú@ƒ‰j*/€‰�aºaáD l²ÇºÐ8ZÆÚ5SYx„x4ŒˆRI—ÉlÁâ"kƒFhÍ×"ÙDC©R{4‘ìC±€‰Rdxf=R"ÆTÒ f �2†ãCmˆp›daa#¥£‹ˆ£qL6àå‹5z”AR 09Á­Às‚} d£©dbAÌWæÒ�ãín¢¬–ŒÊ3±bGÂ1/tA�q4ŽhŠä;#º§rÑk.9æ.(€´ÐpÐXØbëá7Õ¸³k¬9šñÑ:‚ŽX|r¸tÄ¡Âü@¬`Á¡K€Ñ®q–„ „+¦{Â%ðrŒC–%Çî\r e‚aF²Ã(K' K ‹=–D#§B÷è-Å“�’𢂦À½¢ÊB.Êq¡Hd9ä�Œ.ßÈŽÊ…0pfa²!‡{XTt0¡k!BJî�näW6¥• W€ÙHÔNâ °�IAËT‚F&Ë¡Â4ó‹ò©�¤©B´Ó T¬ì¤6]iq#l ²„›–HO„@¢Ñ‡QFËcwð¨2—ÌÙø’H@-Ñ:Šð a#B‹ì¤R¾#@ÕàÉ�«C…Ögâbâhbä,æ¤`“aaC¹*b \B«(n@S a2Rh&—FÌ’C2eÞ€°P¨ðx*”%�ýcXd`F“…– àoRzͤOt(GcPÛ7HDÈžÐèý„¼OLÖñÒʈŽb(D kIâ �D…—Sb2ÉÀFdÎC/RæH<BÁD8`Œ›êÃ5@§ÅG`€ïi™jªã�vëŒKL>Ô– Ãr°Á|Á’n06"¸“ ”ã5 Qþ%PêaØSO ”aYb‰ÍÕ!yžn„,\j¥Åäd�«K°ƒ!AQJÓ37c-T)'–ƒÄS(Œ …ds¦L]³Äq4Ê€÷1t45²z€ŠÎ|àºp´Á5/ UBcŒ•ÁB;@雀U$…»àˆÒÌ/!TéŽü Sð—â!TâfÄ¢¦{p�tN@Gb²�eÂFaއ€ÇY‚ö0™ºN=©z°2Ê`Ù§0Iñ $£éø’H…£%žQÃ_ |˜+àPÖtM5å¸Aäè�7âã—"e(àP"æ¦tìΕ¹ fh˜[€c-�0+›)P,ãTÎV8\:2,U`�}@¢™¦æN¼ ‘Jad"TÓžtC Ì×€€UëO\€€3‘‡Ð‰2ó°�´ÆÅ'8Ó:Š ôa£!‡%¿,ƒ —^(±t<ÃPy8‡$•$° (©ÆÐPXRsêØ‘[D^¥‚1ƒ%FT6ÒF˜f¨.IA‹¹a`F<×\j´Ì[#ž�&æ“<}0‚ b¢˜E²À( ±žõ°f)OuÄGž*¶îó¬añ ¢c. (¿(˜µä ñ‘¹Y&h‘‡R 3_=Çí§ð).>Ú@«hÐ�›/qŽ…9Å�Èà´‚úÆkw`¦�qX`Á’á>ŒO y@T$Å¡I‰#…qfád(è¡x�qɉ€LÄ€‘–L´6£‡¥€ S{„‚Æš°Bæ©Á¼8ÎÑŒ)`)0RÌ­AÒN5K5µCÍ5Õ©Ò© €™jÈœ¯%‚:õAÖ:âB8$Â%\’8„J*IM‘&Ч%C¼¥í¨ž¼˜ ühscQáò#\B)êƒ4Z|Iò�–˜` Ðé† ­è`¨9’ËiPé0•bL$Á)RÙpBL‰º<ÌÃHá2zÄc‘€M&3úàuÐ… u¬1:.<ЂÐt zQ—åCj²>À7Yzæ$ ‘a€‰¤¨B;ǃ„8àì!™hª©)Ë ÈÆ7ÄŠ% Kf?È\ÃÅêAÙÂϵnÁÔ,7X È\MÙ =o“¥µº ÙIK€•ÁÚzE¥q ³9H…ŠEàH¡æ P^”Έ¦È ™©ž˜šh,¬’ÃÀžú �Ù–ñ0ÚHyêb¢R!5 ïq ïÙhâ‚4ÐaÅ\9AƒÀÒV€MY‡C9¨H–Ø0nŠ!0YÈ z°´4ÈI3*�˜V , b¬8þ�…DÐ#�¡”RH' ¦4µà†<9r<Æ©ÁM!‡ß&IX8""3�1S 7W'‡d²OGÐ ¯ÂgÇ﵈ª10ÖÄQ¡Ëô‰b„ÂN5¥c•�‰ê¨ ŽnÂ"&�逥”ŽIeæ-Ñ5_˜¦Ñ“˜Ï%jºgª<ŽYÂdl@gáç”IOkÁB±gÌPÁ aQvÚÍTr $ÁËKplFcÌ2¸4Ò™bs±½0ѨÒY “g @R©‘Þ�”ì#Jsªƒ&f7=\Øè¤o¦S{ E¦@@sòœTaadP”�;.×°Å`  ‘!ãÑ@‰gh�E%"6š6@šG‚p@ö`–‘82y E•Ìœ'Ö–¡” Hf¶a â‘BcSdÞ#Å'[ª%%nP'€h¼cºX Õ½20–4À¨F#IÀQ¬$š z(ªØ�Ånˆ&p¸.PÃK aÑÃ�],Æ¢As6ÿ(r2Zh§� t*Ì¥ˆ™^Ã`Fž|)¥%1¸U™À=4 ;8dx¬¡ÜZ3‹EX<|RaáEÑ�RŽ/IÙeIá°ùå«a,¥”͈a(‰×�HÚÙPÆ=Ô­³v8�B¢ÖTŽO² �‰À\(/…/BÆfˆEp,1ðÈ W±È JÕl�¡^ŠïŽBL% A£¥00üqÀÎÕp)€N}3‡sC�kÂÊ@‚ ¼Æ°µ ¸60`q‰‡²E=ô|€ X&ì°Ò‘Š[Eø2…›ÓÁ#ÃFuÌIu$.¥^,]<5šK  Qbã�ð—uxM$Ý~�)ÏFÃLÑ&ù…•Dùi_ib0Ó; –0¨Sti(ÚÙ€J\‹®²”É™¾uÀ¢‘)…�#A¤�PHdbÔ´{ 6lÂK¦³ã3RI…;G Xc¤E ¾K*§d°n¦èȨ�7T*ã‚Æ%�¬ÅkŒ>' åÅF¦£öA @¢ÁÚ(ùI· ìŠàyGùeD‰ �©ŽFIž®€¼7˜ÈoI\ƉͽŠÙ( Î;4Ð+BñEX0yàFsÅ1RPaéPjºYplžh,7‡æè$Ä#ˆ¶åSÂïP…| {\u†¶Pä6¥‰ÖPa40óµã ˆ(ËB$ˆ:½9¼ÎÁI4‰Pƒå°4�„yahâ€ô`ZÀÔúð2ÒÁ¨âQÜ�ø½Æ¸²‘Š (dOQ…tÍ•DeC>�éH*5Ú0ž´Æ P±ÕBƒ;@S8l^–à „£€péêx²„ÖJ.±Ð"¸ÇGQŠÍ›"&ƒgdÒ¼›In0ÚE‘èE×Â/lÂ#,0â¥aZì‡A ™9� Xó¬Ii;ˆô—ˆÇ` ÄàÐ… a^àÕ „æ»1Îè3Ó@-�˜2ÙQfy‘u(gÐ02l¡Ͱ|�f´Ì,M¦i4®8;ŽH4ŠÃ`&ÆÔñ¤DÜÉå €X·`"¼ÁÍ©§`ì4¤è¬·"ê‡/» ¢èñ= ‚Ž8à ·˜m S+3k")KØseJ�WåÑ�1AYd&� :˜©v Jij*If)§:�@ò„K5‰‚rœeÙˆ Zƒì!&J“SÍ'`6Ö+À „‚°6Øt�ùŠBïÓ÷ ñ\¨™`ÌZe‰tZŽ�Gˆ/M�*B•«Ã=¸ŠŽJ‚Ä`ÔÀRH š‰Æ¸‰9†rõ@Ááö„üXa‘ŽyÌ<¢’f~˜ß Ïh;A‰­V µh¨-Ÿ¡<¨Aêð…##Hœ(Ö03€§Ó’ZFŒý -Hiwè²óQö‰nZC»cÍSŠ,AŒíœ7ƒ¾ à¢è N!ò¸~ÔŠãh(s€Ä L²1ŽÑ‘ƒ8sÝi±pVå…@X2¤17/ž—˜Qˤ;e¥Cp ¸”%40Œ6”uAšÁ2gyä�ÅÄì1û, p ÌÑ'6�ð6côŒ/#€ZŸdŠò’,® D£p$�ɲ$"TЬ ô–Í%HÑ'©M˜]b Ç âùãDòA4`1×(âT24H9 ñ‘Ã:Q13(/’‚wú P3žcAp‡" ók™ì ÉÁJnÆ%Ø`\r´WµÖCZá’he¨ákR  Ä‹3Ób¾p>ÆHÖô-éŸÐ‚7¸2}IÊ=M™i\D²uX’ZàpÝ®¡N•±# ´Óœ(·€Kµp$�4ûAF0‘£«ög„ ¼�8®‚Ña[:*äF‘5V±Âw"dF$Rj€¥„�Ȥp#ñób�/<Û3BÄR`Âà€˜Ë&CÂÓ+Ä�ª¼4bÆêB¡Y q®3—ŒÐ2ci@‚MÑiç´ÍDgšÊšÔ~HS!)7—€E8õARJ‡ÑÄh€r¬˜:Ħè”#>ÇšBµW&}è0tàŽ‹>Å ,—–ȳûO€%莴€c(eS$(@­ŽF˜�O²hì %tD41ëƒuÄ¡I‹ÀÎ0¦Fć%,@D&4fÊTæš!Þ�C€¨†$âlîÌ´`Ž5%R¡bTs}æu ªP8ûAõ‰qL˜nžJ�(‡$’y³Ù@˜C§;n˜’j³t±·€ÆÀ� M4@ Δ›ô<Ý …*ÃqY ­h×À\jÂ�hxm= ¼¢'ÎjôÇȈ u±÷àìÒ É`8 Œ¸tlyÞqpÀ¼äXH1ó ‡ÕÑpG T–�…©9Áx©Ø$€(ÀT”à $ÈFÇ”ãkD-Â2Ñ· P»s5Q‚Ó×DsGB4x óâÀxpU8 P¾½ÜCa¦ši‡çÍ!06Úð@ù +‰Ã�ÐÃ@¢Å ø0?ì× ”T#:'·BXÁ58KOëõô&lŽQ+`ެ¨‰ FàX ‰“¡%ê˜îÁûˆƒÉÔV`‰TÉì*R¾‘¬aŽ�¾(R$Ë@6¬À!5ÖæÎ\9N�k pª` ¸È6|FMyˆZ4Ë©Y²ð ‘©Qr¼§‰W3{¨¥�µ&ÀŒ �@öè�†°M…ãdvØÔÌ;©bÝ óÔZL±lN+á6À •h£9@—-óˆ±õ£Ûƒ+�ì·‚D¶Êh€Ü4™<:æjœ¡5 £\I\}T "€Ére.hŒÐh°`3.f#þY&ÅÎ�¤DáTkHL@ Ò0 hNm’¢¸@`gj2P!=XãLCÀrgÆÀ|»d’H =ÄÊ0Щ2«¡Ø€˜– Äcº'uÒa4 @ E£ÌAÄš�Ð=½3à4.Ö‡;㊠O�#20J´§íÇE„&hŽC÷‰;ÑñºÐ-!n Ý#z^u½ P^jf�V€DsHD„ l4(4Õ©&ÄGĉ¨5ÎŽ=- & < § �A㬄EgẌ‚EÃÇQÂ<#-…3H�lc0­�O¦™;j�0/Bi´ÌKzHJŒ&ãh26`'ãðZ™FHÄ3W<(Õ�ce¨Í@ÊÐg^‰†�GÜ<"ÜÄ¡%ÞZQꔇE ;hdà™ˆGƒ,!רŒ1· È9OmŽï„ýHDÔcExΡ]¬4àÀ£!ŸÙ$€”jªL ,­çY0AfM$…Š ¬§Äã4Z�—$ ªÄ¥a#aÀNu�Š (¢‡ÜѦi:Ôy”Œî\ú´r„/E60®‹$4â‹ÀãÔ>¼>£D‚àF`z6%æù R¤Ù�Gs|¨Â]0h”u(”—Z.Íø0“dƤ3R9t¸ &´"y ‰ZƒH&• ¦®£ñÐá‘5§šJE=¸‚YÂK¡`^tt?%yà°8ˆð]Y4È9î «ç†œ>ȱaNð~$ûa¬h ”l”Œ˜ —ˆ€ D†°èYEpÜn"âDA6=X®€Ø9^š™ŽÁ±��v*›²�8Ù † í©€t'5Wg¶8Ńú‰šGÃ\û�¢‚(%öÁÕB­oÌa<Œd�‘ó† /‹ª,5W†â‚€B/Žè�•=úТ 9ÖŒ¬±¾@Qš>Tâ óaPœ•° iƒ1Ò, ÉËsŠ„ɺ (X84ÆCiÚcpò‚•¨$<&…¦+¡\"@±.iÑ8ˆ5‘è�5W§a2 ¢�ƒ[B£ñ0ÐË­Sr ,Oh‘9@•h ',A@≃pN‘£ý´'YMö œ(¡,±^Äã�ð]Ð(@M…—ØÅ(@Z� €ëXiƒ™Báx„‡e*W‚”¡š«3žÝOs"YÈ O¾hž‚E!e8…PÆÆOY0Ñi±`6I@¼#ò53dÐ]SÊ¡R.:“žì?b•fG¸ƒRÚ¹0W¬Ì•pC¡D8¢Ô„¤æJ¸aÐTGsLЂ8ª×\c切¬˜k”hB"),ÒÐ�0Døkb( ©[>¼B¨¦}ðµÝ€ ™ÇØ–óÂq+ð „h€4ÈótK ÁE8\B•DKQx‚š(#€6e "¥KæƒcpæÔi –˜6ô”$¬8žÂÃö�ÇA†Ê 2 ˆSÅÞOÚƒ†Jt=D%Œ‡iMª‰pœF?„�S#%‚B˜_~¢‰&Ù’` ï °Ãʉ²©tØP´CöPo€ÀO` ZóÅg‚dB,HТ{†Ês÷ñª8Gbá(�ðºRD*kx�ŽŽyq°æã+�€¨5ÈÔšc2U†\‘£1,òRd£,ìDaîŽ£Åæ aëP±‚¡UŒ^Á3d‰KÑÔ¸KJ(�¨BäY'ö•8TØØ¬™»rÀÁ*G@‰F  M‡*¼ÇÀÌ•¡ð•¹Àq�<0zò Ñ�a¨l4æ ©²è:ºÄ©2)82NMIžŠ8i°ðsC0*µ`šó`©2nBÑø�5 °ô‚f(c¨pÊÕ�„œð"åÒ´e†×8 {ꃌ[„ÅDДr†Iä¬1j6@êl¡…[†gÂ:ÁÆŠP³¼0WG#‚h<Œ â©!qú‘!Pgé£cÈ*¤äغ¦æ�´˜È0ëHG H$OŒ�7ôd%˜‰Ä#2¥±!´Ø‚­ h᪠—„à5&Ì|6p àÀH5—‚‘’ (Nâ€$ü‚pìÜ ‚è*FBÃÃh%¦�u°L80™LŽ,«Pì¹Rä67CDæ #{´}œ\­fŒUlM`=`A™â0C‘øÐÊARK#�‰�p ò €ìhޏ5ð‰tjñM�‡*Øœy1¤YÆ?@‘�’§X0ÕÏ‘¬¸)M–€\§($‘SM…q‚YE1µ º§Œ!£#-S­ƒE,½2„£i¦Áh¢PqEBR)� ò²h â‚Ê%ƒ0‰ˆ7U‚²©<œƒÇ°§‘C2¤(¥P³ñ4*\:º`é�—eRAšø˜o ’jÆ/¤�²µ .� ÖÌ=¸X˜—M€<ÈšÕHƒX Á±:–K eÆkÂd€ â5ÅGcl —æÐL tÀ†Jô:àYCÑ.¤ã  &iT£1(z¢Œ�«C¨ñžê HËÄ­´$ %€ˆœ7„ðkc—Äj #îT™ x‰“ÝDpLŒ ¥@Ïtbäl^ /0Ç@Õ�ç!�h𨺣‹RÎi“èp ¼0ư*ÀÄúð22€³… ¨iM!¨Q ¯�f•°Æ‘޲HèâHYÀãÉ�Ce¢1 6!™>5ˆE0a“L ÀiA,`¹ �¨’³>0t 7W¦%è€l€*9…*aÁ�ˆä�{�í2lÌ™qöB ¼È¸Ñ,<"Ãre\!°Û/�pQØPÄV˜pØ’Ì!N)Væê”dˆT�.“.AìÁKÂŒ£€dÁq±¥ÁIê8ã ¦ÐTOëðN§~j‰#Œ&ôØ�Nc’Ê$RC–û¡�ã�@I�ÉA Òã7&5WFĉã’aØHcóÄé§êà !Æ+Pœ›J>P,AÏ„¦.U¢J"14¡q3R¬§”R1J‘ ¡9np …9 D l¤Œ<ÂÈO>œ’qVƒˆâ�Ñ… ‡+Á-'´<Ѐv3DH Òt� h²^€fOëjæµRš�y,)UöQ?âg�)À©£DP\L!Á28Q pe `Nêq€&�Dc,b¨Â¡ÔÑ¡TQkèÀR ó"(H8¨2d:b¹b°,‹d h< \Re¦¢Z ºiÖ¾Ähq'°Œ)�i^U°Ø˜¯š—"Ÿ æ‡öQ àÄî\ [‡YN%Ša �[NXc–U f”S%Ô3ª©ÅC×ñì8 h‡¦šÖ�¦jx À&Tƒ‘BÅÎc:\B>eX$‰õ¡kO�ax”ªXÁ‘a`¸ªÂ R”c}†½¦©m(³ Q@4g‘øØ(a=¢‡…�ŒãP î°ÔT覚)ó¦ èƒe€lŒ%Oì$¤èÁÌÎAçctÖ@TcQA<=úN)I~*ƒ¿N:œŠ#(­2lP‹Œá ’›'´ÇX€LÇi G ·†Ä Y¸ ¯1µ3™@¥_$ŸJÀØÈàóh¦ZG@&Bd ¹š8=S"b€`Ø8;¢ÉÌ,ÕÔ5Õ¤ÃaeVG'Äš�,th`Û ApaájÀŽUN…�=zÇ5Ê7¸¥=¥¸“8ÔCC‰�hÙ¦8DnS"Ú<ž(d}¸”©½Ôh?€`ƒ!š øa/„Ðä{'ˆI‚ñ)0°£}Æ�$¬gö…÷XÐ!VPÀ“DžW?Eaþf°ÃĘ&vK,LìN…zP"·!2Rñ�<Ç‹8 †`J±Ê%Må™Õ ò¼L`q޲Lµ ²B@gHÊ3d%ë>p¢l„/C Y^ ¥JB9pL$ÌeAƤÇ$�± ™ƒÅ",zÉ‘M u$‰ Ï�ù ‚ßxL6ð�‚ŽÆ òBj®Br2D­”ÔA�úÑŠÒXJ˜Ì‹*F#/XpDhi¥™¯6©à�¹t„È nZ4C<@J€C‡”¹š¸>Å*TJ×±>؃ÜdGsØV@¶™Öì 4Ecƒ 6û=Z A–Ø óÄ5åæMA�T`”ZÀSå Ž 6ŸPó ý :w‹C!�’Ù×lG^@Êñ~z$4¼^ÁЧtj2e"O¡kÂÇÍAʃnDÚM(…SX^ ÆÂ, -Æ ‰ Zk ø«cû;†e $‡GëT.èæ¡¨  Sh ¾Š‡†Áq‚�FO€ÂHâ,/€hÃ3o ¶ ò:àK#@ki ¤�b� $3�ÈÀÚ™óÒL5õ¤Dü<5Çþ k„'KNÆé ™ 3öàd†ÕT³”±Šœr–¸ÃÁJšÌŽqÚa (%«Ñ¡€-–ÆKò0™ÿAPETAGEXÐ8  DATEOct 3, 1995APETAGEXÐ8€beetbox-beets-00724b7/test/rsrc/whitenoise.flac0000664000175000017500000106311415253035401021016 0ustar pieterpieterfLaC" 0 ¸pw`©fqÉL0A܈Ñ:Å„D reference libFLAC 1.4.3 20230623Comment=Processed by SoXÿøÊ |×V#áè9É�K@�{Y|¼Ù¿Û ~œ–«êÚ–´c¿ÿ±æT/„Ÿ™<Å’WÙi–ré¼�Žn=E2 ÚPôlm!Ê@ÎÛìpa ªG’ªl#Wß�koÙ„ºìwl§æ–ÕÉFÅàÙ5R®Ñ“!F3pAëÀRcæÃÂ+ÀãG$ Ïjf}„X1×¥_3~K©üT”øb‹ ÒOeaÅ0|háZ!q4ü+–—ù¿j™BÖ‚E[N‹šÞÐmDÉüÔ^çe{w3Ÿ8{é7â�ç5}Qv™‹à¡�)Ó¶Çfdà_e„üÛ~ Àœ<’<�S�ÿaÖÂ4×:kÖ=ù'º|µR·l3–Úº)X÷é@LþͦƒÐJjÏ�¿åŒá¯J�|:˜!œ�¿�íBø  tXû0Ëi}ß`O¼DÜsÐ7ð�‰ÖRqxZ³Õ]âé?‡ºÛ ßš8vDY9%Þæ8Ù¹‘íèò„‹™¿,ý¸‰eì'*ûë´JFZàñýVæ/ü®Ñ €I‘AÈD»Î²eíjQ¹j‚Ì´æ^Ò ‘SÂ! `NöšáÞ�߬…'Ú>ô0ízH‹ ipØ·/HE�*üe¼rÇò™#cѦBOÏúÄßÑ:¦ŸÓæc\uˆþ¯îýC™Ê�¥$«ë@áúíw8±+îÎcÎiGfÕ¶™¢‘ê,éÈ ÃVÿh•R3ƒÌÞ4¦‡}bؽþBªjîM‡j&Êå5çä ôÇvÖ™\Dd/ L Ä1È�B‡*ø f—ʹøòn ”¬™p "Æ&¥Ý¼Oi~�Ń·fzCumÁ5Е¥AžçŠõn¡†ò ?ÝOÉÙŽéóÇ­k]è­ÄuÈÉê-QØŽ »:á`hYªÛnge¼®¡ë`Œ÷Û…5»™œæìê¼(sH@z�µ0âùHªrÛ•%`c9»éȇ�Χtµ 4³~À7J7þ¡?)³Ãf&(£Q‘çù£eáÞK†Ð¬Â{RnÚ‹(±R�¼rÞÇ ï+åÑŒ¬JôŠGƒ¸dI O9f&ÜéiÏ×òw¶ÓØÒ-e‚0öð‰ßš±Jy»ã/€“6Þ®¼¬19÷”UÆ4C©1ú^š_EL*iÍ”·hÁ†¾¨Åc¶Ñ‹—½.é@ËÀÒ٠ܱq¥“ßÁ¨÷tª+N¶?q“‹a`Zg±ÃeÍ�Y~$˜ÿ;s…a»¹m:ÏP¡Y ¾žŒ°NèMqòçø+éæêWJ‹­£Ï|OlTª£N‹I¨ÐI-¦ûž` QÛÄ%|Tß;>D,`À½ ªÐ<ΟÇäD6´,1÷/iø¿r$OD¾+¿·Z¾?Æ£÷��?´dðõUç Îü¡$üzâ Ûå^ÝžÞ+{Ë,SßågMâ¨w|q#à:‹Ù.ø&B°y›ë‹¨ßT{|âÏF)“ZÑ nJÂWÓÔ€¿ú« (Dlèa´ðAz¾:®A+o¾¨ÌzÀFQaìîØ›C—ƒ L%ÉÉÕÁu_L«É ¦ÊK ûnòâ¯ÜI3¨G¹kF.‘yd4Ú«à S·¯ÊÏ$æä¸�PÚU¶¹ýN y¯é<ôçñøhÕù2yÃ\³oHÚõ%H Ð�pSÄ1tfgñ�T „;7±ÁŠ)¬œ©Ô�„´мïÇÅ89s2Ì<ÆM~s´2]�핬¼H.vz0·FÞfg¡ƒi³}Yäº “ux“­DWºn®Ð£êÿ”6�#nVèÒñ•VnlhÆŒXzÔkŠ‹‹\(<†r]y}~í¹g97n“Äv-bíO2¿ › nùmÒ«�ò¢QlžRœE´ÅÚƒ¯M<¸qæ5~„›>ÞïºDt}]–.bÙr¼;È9rZ”¬Ÿ[`~c;Z‡�eeÄ(å�—ÓÏwŠ‘®oÌŠ:_‰ÛdOYöÅãP¯Ïò¤"ì~˜‡¸Þk+—ÏF�ÎC"Äè¶½X�¸7Åø+cî}ŒÜCÙÃ…¿=ÂÙ2üĹ^$ AY ¿žË»�,Wì� Yõ/³2ŸóUpÛðÖ˜v‚侌h]Ê®GÖ–È{Ƀɖ؟¥ÛîqÍ" _‹çz|}ï%‚<ßJC´€Âªˆò Ì«–¨`oþŸG†|�Hug°~ƒe�µþ²ÌWzb¹(÷e¦ŠF®UÎA(!¹Ê‡·4¯•6,£ •þŸÏˆ´š½Í¶ÿ>9ƒ€ ºâSÖù}xƒ‡¤S�(FżK�ôݲχ'¹„þ÷À1Ã…f–ÊOuüyκ@¼Þlœ¸.ƒ©xx�c�}«S�»„õ¥ £‹R =x&Ú‰F}p‰è›Üñ«Å[h[Ó¹’FÈpH4Ɔ$…i{YÄaþIƒy’˜Íhún¯.³³»IâF–ôÎ1ç" ¼ç��¬‹% –u(xgZ\§+À‹IlúÏ�Þš@8 �®0‹ïVlì ú!ÌF�‘ †–0%à5»Nkj²ß¶q¢—\™¹w E­—Ùl Jiµ""#@S: çŨ-/¥›V4„dè½ÚÏG›×ú¬›ÙÎP 5 ž^ â8.ŒžýëSbëâPŽÓáx¸½4Œfü<汇çÜ)@Ê‚ã¡FœÚ [�Ê6“ÓfµÚFEY,…ðWrÏ ¨¤ß7Ù·”ÛÉ“è"šÌ gÊsi Baªa�³j]ÏÜTÏn·Ä>fnê§Í×džÔÈô`�W.Ú=‹Çû„Pˆ>x‰Ðpǰ)Ô®K£!½CéQ¸•ÎÁþ 0Ëš¬À%©o8_ª)ÏØýÙŠ{‹ù“ˆ¥$›„‚„­ž5&&#6I¿ñ,aãò¼Gûý—±Í"¬6íC�I侪cÕéªÐÍ»$òH{nÐüÏçåˆÉزYSNO,“„9M ð;0Sóî–ß3º7q`¤ï€ˆšwS8 ÓX T]Ç_-¹|Ò‡~=^ÞÞ²ùj½é‚pÊß‘�ôsEBã¥yb j¤V‘ÛÅo´cvè† �¢ÐÉ3ò ­€r£E]ƒáU¿ù(!ü±ôV@;Dæ"ž¶ >H‚ÄZå÷S•ž~5¾9Vø–ežþйá@&šé�ù³5¶„ŒØ¿NíÆX¤Ä‚L}Á97�tϵ§—\÷kà§�ïÖ´ÝΠÍWÆóÒ(gÆý[$é‹?·¡1ŽE圿eCgß×êÍÈéì¬_þù¾{ÍÁ¬œ_ѸS$#%¿¢Ñ0˜ÆõÈ/�4,ù_AïÇÙï9/ã<" ö^ùc!à ™3͘4Ø›‘»åºj¹2R«:0åg�s¿²ße3âJ#¤TGÕÐÅ7Õ>¤�ËÆ�gÐPeó®ÕW<�e7tCÃ1¾œñ+y¦üÉŒ¸‰9È¸Ô òÛˆLµ†žâ|›VµÀ:¦ñ#(‡Ô}ÚáxG¿ JLgùÊÇùÃõJÒùÆñ°ëfMcø ·t.K>n­l†[BeDIfûZ­˜/ŽÜµ¢@^?�N?¡Y”Yb�yW¨ÁÄcû÷g´Z¤}ŒÌ·~7(‘½Ôê¶Qœ0ÿ …eµçx·©È·—eªžÁí½Ï"†£‡Ò…–ÅÖÞ‹Ž ÞK®´)Ö< æe©å¶‰¬zô÷%u ‚Þ–,É„®b‚eÏŠø˜0iÜUÏf<µÃÖ¾¨|N_$”t™íð:,ødý´ß•©à–îÿ̶½äº^B9Õn\Ô�¡Ðm #;Cr»¢Et}'Ìut™™P¹0E*]¤¹üÓözÛW¾‡É¨áè$%…ÐÇ®áÿâ:ðÕ¨þoN*Å�땜3jVÂ1Ž©9»Â^Ï|ç —³unàTó2b…àžïu}lâ_½téÄÖe+Œr¯ÜU�HÙ³#q€Å«g£òUXØéôm|b ¾±Žƒ]mÆ5äG¬EK=¿Wrëµ]�|¡'•§=Àl™ÎÊ}¹IP§�DÁN_œIú`ëPÁÌO8#{E‘«…¢cQpÒµf¦’Úºó–ѺGmoò ²qäôîlËÙH·É¿ˆÒ€yI¼4 ¦cfÈÕ³Þu‘ˆ‹]›¸ýèb™Äµ7³HØÏÀ>u[œÿ•ÎS%ÿ1©ñ· lr/5?ýeu+nO ¾!q¼¥ï÷UÁ–zÃ-];oíýó˜ rB}¨ ^#É2Ì™,±E£ìKXúé±%O¼9ÜZb¦ZuðWz>xùÇir”Â1¦ –#4òÊ ¥lÍ*iË&!ïLj<+¶�óÙ4v±µVà¬; §ä—†Âö³ÏíWÙ¢HÒ–‡ÎkÒu…œÑçûÊ3û«bèJTÜÄT’)Ë>Z"÷N5àYͺ�½Iæ&œÔŸ^U°hèéi}S~懧RÀË® 96oÅÖ!ˆqL´é}�ü»â·me¬*Ú+䚘|%1m–Üx_jŒ7sw¡Žj|óŽ<+ʽ?oëv»Ãöo4;­8í¹JXô'ç½µ=Õ¡:�|ç«JEô´�¼‰æ$Ÿ|¾ ­+ú$· Z:&_ÌqÒ|©Æ îP=YwD™’w–õ€D®�u¦_„Ë+ß�AõZŸM$ìú4´„í~ÜZ„ÊÆ¹/UµÑzvÕ •â#-”�B‹DzõžjÕ£%g|©]!áÝ‚MtýJmZ¡<-ñ:´Ñ³ ©Îö^uÕÀCî ^«>4Ȉnƒæ[“ TËsÞPß‚Rï*ЉãârzŒ‹ñlƼ+>Uš$µd ’ir¼økBú”ûkâl^‹¨¥ B]èp  Døz+=Ü…8Ö‡Ó¹r 5¡ãQ`” ÄùC {ìL¤‚gÕ;‘Ï*/&hÀªïHžòóýÎá-ÖíùEû@xm/”zòb¨ñE!${:í%~®¢V}&S�ß7u¡u æ¦÷�µ×ß¾~ÂNÁxq Z¡¨Á{Óíz‡)Nºbî�HÎa°@ä>Ì%h ¿.ýèÒ]Mòµ¯)Ö.<%‡sƃZˆªOâóe�ç¡3ßôì‰]ŠÏf\çÙöÙŒ­jß )°ÒI O×áB©AvÏ ïn]x¥ÿlëÓY¥hæ¨ZH‚pðÔ îì” d ®F¹˜ 4Øál7å-ÑÒ´\’³ì1@‡]gúLºA²z _:혀‹7…eú�TKe€ ™ãôÃ\°NØbÇõ¿Ù]þÒÕö3XŠ)¦‡~ò{Úõëz`J,ÂÒíÐÊ7? €y’eÌ+Êã–-³�«o‹!�*eË<$þ¶®â´IósC‡¤¸’å{_q¨÷kŒD8ô�ìÎ…~@r‚Þú î&{/"ª…ž{#v3 »/A)§F ìX^ FTˆ5Û󞢪^ª+¿‚…lºz~´}×Ì`‹²@M`H=î_7§’S)‰Œ\�3$Ÿ¿Uä<[¬R �yåóÚ_wίѣŸäXëTÛ«Kç¸ô!óZM7iñ±´Û‹i.(€1p"Åž•ÿ÷ñ™]¦ƒçk2ˆ#eç4lØVÃÊr’ãw~µJºf!ÃÕöyø*o„0V4€ H8 Р›¢`.¯¹Àï#:ÒΫhcât §ô5ö2¶¶hzNò5‚:€�°fz'‘t ¸."KÝ›¿�þCû—Òü‚³ /�÷bèÃè1öüÒï'(ivÞËÆX-9ëž•y˜‘ ê|;n—rVÑ夆]4ЮU¿ì5ãÞ�{ßAõÌ)‡PxFtŒ7CƒÅúx¿ùÖr¾X‚ ûOúÀýLbg|O3­Åaóü绺µg»*CËúoš,¡jÔàÚðSŇqjÅÊPç>f°‘ HØBÈaÅ�HQ-äÝUÉ+fõ€$9È�ØR´Ö¶³ ¾¿vÛ¹ÇdÓèÑïó!ôŒ aò}1Çë ØgТ�Å3J‹?§�Á8¨cí—G7hÃ?�ëSqdÕ C~u*oß4õ…â.ÏðÚ”ä yàîT˯ÊýÑøMwpÂe·„vÍ{ïSÈ÷!ñÍÃUÑ6AÐåK©Ù„²˜i|þFcÐaVþ@½]dÞ×Ñq¨ `4Á®¶6 …'²çtÚ¢²}mü 3éE¥§&¥Ëþc–b\÷YOK?RßY-afQýЕ’¡4%È®!.‡ï †Ùœ(Z�üa0ÿ¥!B J:—Ò» ¦�ÆuHiטO…š�†ç¼ßr%�ÏŸ¿ ¢gvù]‘‹”òÕ…(2”ú�í ð´džç·ÐŒZU ‹ÅG3}›•a™ˆ+Â[ËÕºé–.läKâ¸U”ˆ )Ûç=ñ6�rÒ[ɈMLUk sþçP§:—w1[ÇË"“M¼†?q�ù �î&ß±þlZœÀÞW�¼pEfçõßÂDEÞ/r ö×(]0‘�´Ô3(žv8¨F9Ata¥0Åf‰y�,%ã—škÃJiCn¡tœ¿Q®§Wê1K º2Üu»s:-ÛÕŒå•õü6äµÜÉϲ»©SF–zAQg_“û¡Ìr=Á�‰ÓwiÔúþÖ »a„ÙMBg°¶»6ÀFt™†yñã*´æhZ!UsG«i‘ej›cM¹ï3zÖä<çi¾¬5hV½�ÃémÙâ;&ÔRÍç%V‹fßÝC³®>¶´jró ê4ƒïÑXt´-b¡å*âÉt‡_e4s“¢�2Z.[6©:,÷TÝZŒK¨äYócØTÉj¹þ(êçÓ(¢1¸½a¢c¯DÝO°%(?–O¡™«Fµ¸Ã[JéŒÀÌèK‰£ÞÉÉÞÆ‰<-”¡ãˆ üKg0…=ÍÈp�,«ÕèÑ.Öæ÷ʯ¥°´ pQþèÖØÔibæ‚®; Ÿ4BIèÀ‡’;åÀœõRGüD”Ôö˜G˜W 91-(þìýŒ“Œ½zýˆ�쾜›m–87¼Þ!ßv�`‰ñÐÙÅÛTi~Ðp<~[禷¡µ£s:(Çè!K91¯×¢çì*3º¡|«È !Õà2Z¤æÄ)ÿCœ³ÆÒSÀþbðXœÇCH{•p¨CvÚ*Šþú<»„ýÐjÙHE½ü&|û¤ˆß¡”sZ’…#{êškªŒ}â‘¡T�ïø|óqM?21¢š�2AÑx“Ÿ)ð/ëæjT§H4½ f<2L³¬„áàÕ›`hÔÀüƒä¤ Mè|�ÓçJ�lv8X–IÇߺ UÓ+�•¢R}�ž¥ƒ÷]¢èªÕòQD’í�Q©ÿ+蜱HG-¨ú=jxÞü'äÐ >Ñ�L¾ð- -�ò(ú0y „î,6AR^Ž)�ä3d�!Ó¯…Ùóç z†ÈbqZuƒù"àá�Ú«Bàr0\'5x)ÛQòŸ®ÁÔâ„)ûXÁj÷–ôd±vu†>ÓDAº[¹ì¹þgýR©€x¼=eÀ1ØsÁ1Ð( 5 ž’"ÊÉ5qà@§TtxË)¡@ܱ�ù°q?l´U3#jRXHvLž<æ¤E“#=ï!�›È÷Dôõy¹O¢Êâ@ŽBfZ4#;¨ùÔ§麌H‘Æo‰?œ¾æÌYó3b¡Ö&;ÅM#’f­3ˆo¢«+¸¶m5Öì«ïCÃV:1£·S§-&-Ó]�žg©áÑrÔIÎ Ä‚¨øRœCHw.÷£³!ÁvXΚÒÝHžÒg:©ã+®e×Y–ß––£¸š_Òh¹³•ɧ‹ËE´qµiá•ͨ#…¬ó‘2Ô5‰>FÈÓ�mcñ6þY¥öŸ™ƒ;ÛP÷2·žOR›vô뇻éã°"RD-üdìÁÐʧ…EèªMÒÈž–'Ì�L1¥‹Fä(/lˆädF£ár{’¨p¼‘C\­‹¡Ló¢o+ÿùÄÛl&Ñ`%—„Ãà†¬±6vw¿9%›0©¥3¦?ôú·’d`F˜G ä¡»¤ÑØ’�ŽSò~QФL:žN|£u¶ AÅQ"]ÂO¢� ÇK}ÛkV£Àºl2|}ÛÚwkZ‹_1ë”%‹u%´> Yn!Ï�g®(ÛK“Ù–s‡yg`d®�c߈ª¤œ¥æVËŧ–ëÔ{ŒˆÙLÿx1vì8Qc.¡i/UÔ“0˜èù±Ì·u½Ð,‚Úä ’†î¦À7öÇ…$è•ÜEï5T”pœLr¯åº·W¯ §æüe•ÆpõH»`Ð�«øNÍÉîëLŒrýÑëÙÚñæe¨ÉA°äTY—a™Ð.{¼å&ô[| }(‰ô²iu$%[ê–yM·KçTu"�Ù‹¢ßηÕãøž Êy„ÂnI(Ã!VvÎ"o8ИÔbð¦dФ�NL*Á)µJÿ¼¨3§ÂëÓ«>”UŒiÑžX†jÃ�VCK÷~ç¤Ôˆ�Ry9öN¬ª­Õh?qØI25—[çÊòÛ­[JœÆænñ±t»úÙ/W Õ:¡(»â;ì Wÿ ²wØnîw|?šˆ%눂<(QI‚/uΠ7ú��„¬ü±7n·±áØyúy Ø�§8qlâîy û+±³´eÜ<ƒü³wdª.MÑž[Ù\dí­Ò† —ÏEئi=‘äD6÷ùEé(“©²Ö?K,½þ;󡃃?Tv›‹OA>TÕß[šþy@ô.ât.UœûV´id4bí…ÀÁ­8'(#ïêÐW�ÇŒg~Šl^:ø”;A?âSÑ®*^"†Øÿdȉ6]µáƒµÆ ºâ:&“ÇÆªb£ ºE·ÑWqÊz¢)¤7KÖô=i\ãÂNL±YPš�ù:$Ž©pÛ›WY9ÊÝ¡�W#�a£ ¨wxfþ:J¸ô€:eź^¾ í"Ækü_‘�·÷*n= ×ð*`¹ö€f Ö v¥·hìUTƹ¤Atß B‹Ë0‚áÓœôGÁ’V/µK-ô0ÁûZûÉ‚œµãcÀ¾,òJH·³©ôÓø#>ê\Ã$»qÍœ&�ùÖ�Áëd'‡H_‚©ÆXsŸƒ‰v답KÎcÚ¿ ”ÂyÐóè#|ô® B]u ª¥:ðw¶jqVe\ý-ILÔHâ½Hq¯\O�½6,)ÅA�öÔ@�·N…“ØÜ�kx¶Ð=_�´Wu¨óöêßaÊþÁãÇÆ²Œ%¯U­0GÕ, Œ�‚íY©>YØ¢ ÷‚³QßÉ/•öržÄz ÔÝ«vHŽQ†ó9øeHº&±¿«MÙ¹ü…}ζâcTÌdÈÆ±Ö£ƒÅc+Œ;wŽÈÄð\ˆÈQâë"¿§‰J T¶úØ[°íXW�;Ïéʱ%¼£"Š+ÅÝa–üÌ hÀ£H âq§;  ÕI ¯ú‡¯O¾¢šunZ˜Ô—äÑ•ì ×ÚœÒë ˜ä"Që–k9¢Ž£ÅéÁÁ&^r(–ñøØ·¡±Dy&²z±Ó²úð?àÉx–ûÕý'žò0w›F“ W©L–v‡= Æ“þÃL÷tZ‡Ôil�ÀßiÚ3˜M·É;ê('‚á^ªÕÙ=d5€ñ¨Ð{’ð€šƒ03L°…vÃB… EŽoÈ‚(j?Re´0äõÙ̉,eåpÆ8} ·4øÙ�þlë’õ�ç1‘ ƒdá ’²™�5Ó{S>¶¶÷KRË*Ž ¨HKUDVPëx-s5ó&¯a÷Éhß Fùcéõ³„ú&YÏñ12õ 9…%å±»ño*ãé|ä@Xms�P’¢° òˆ¼p'¶ÊɾIbw›cCŠ–þ%1û�ÅãmEÁxúbÄ”»¶¿W=ºÿÏDÿ’¼,Ú›È!Q…¹Á¡r„F”…²I);(Ýó‘¿Ne–¼Uÿô­ûýr%:¿2~œxWÊ`&á¥?˜Cª”0ŒØ#zå¸x#üŽ«Â±«Ÿ+kÇu¤N‘ I³²µÞfTБ�hªnÈVnË€~݆·q"çìo˜:7zµ�ãŽÇbdZ¸ðƒ´»„Û ãü0ÙhÙ³Ôh«hQLY¼eÍF—‹§“]âƒÅLLàƒc¹d%-{–ù­Û–É7dALÒÐ5‰CjI[Ï}'hßkE Çh¾?… 3Äu/äÜYaµ#Ñm3ÆÈGzÐWå9}M¹€£)æ—ÞíÜK-ËÓò¤Ý®mík™ÄïÉ0êɩۀe6I!ŠÎ¯Lø,êŠÖ0Hf ˆ8:ŽD>Ê0>O"?³{…ÑT¡S ÞéI¦¡Ti@/‚qÁúôB»õŒC<&Uj9£ÃvmÓ¦ç"pIþ5Þ=·c"5s°Öx«Íì)îïïGÿ•Cgö+8ê­H<þ÷ gêïP' Ú&‚™‘$�+‡Ù�ÒÆ¬Ü95_¯~]ÂeSS=«ùôàèõŒÜQÔ€“ã0íñ¬mäh7WÓqnë4O¯‘¾¿dæ–ôˆ”�“娄 æ‘ë>‘8|~ýÔ„ÉýXÜ^Rþ.>”Å vWÿLR–«®ÀU™ã$oÎÌK ¤P«ºèG\©s¸Ù¨!x.¼YŒý´ÞKâ§±´EÑÊFJAµ–&¦\x ªtè$ã�!CYR\•?•°YÁÌãÁ+ì’”LÃö¤~vß…@ᘑ¨kAÖ ,>8P¨(NxŠÂª¢î¼�‹™ƒ”¶à o$›š?ŸäŸ6�»Dü…í™2EÁÔ¿~‹u¿£[îÍÍhE (Ð"øîy<‚ýþÛ•ã"®)Õ�Q[²u¹ O'�7m%„ž rSÕ>Êýªl•b”‚[zšÃne÷ Ï›ðN‡ÔR¨Œe—Ð07[›V/Þ|yÔBz!ø8‚×A˜cüñs‡/‹‹.y™anˆïºæb J1Ì/¯Æ8�:2wíì/j{ÇêŸðFBF!g—»…��Ï cѽFç{Ñ´óCÞ‡o^Ŭ©â{¥t^F�‘oGÐGÚûĹºSšŸ�p;£g}olŸ“»—Á]¸_}D¬µß0=âwœ¢—meMàUßà[¢ ú0'á ûH”YÒS¸òM«ŽTÙ'BUÚÁ¤\žÜÄ×1nœ¦ËÜG9$09 Ü›�N4T«`ªÐ½’�Ú”Íq8�ˆ:GÐ)__•–{À®^­V?†c°«íËiÿ©L>/x•:Z*G‰~ÿˆ3t”'!Ùàí2ÿæC„ ‘ûÛÜp¬Ë„ñB�©WôþÁÉf/ðúÛ®t冻¡yÞ¤|P…žjOI ™�“V�Á8�­äÖé8tì±…íoxr©*—Ë`Lê4šÂBb¥ïMxúušAàÔ¦l¯ �*#²cÖ¥O¢:—)w‰#zU¶uŸâÖÀSþ2¦ãðîšÝ�ªüàäñN󤡜7›kÍ8ˆD�Ô¸†-mXÁw§ZBz;2Oû4Öé?!z Áø„!½ô]M¾õ7gýøˆkÆëìY¨PíBe¦+Uþ÷ü™ˆ&îÍâsC­ÿL÷öæù'åÝtiIHYÜ-22x–|„½®2/«ÿ…Å1åx�ÛOÿ´Ð…傺yû¹(FpQ…cÆÝ&lªh¦Å·Ü¥öv–B¤jÛ‚Kœ%ÂçZMV÷Ñ5�¸—Iü�ùU¤Ž°f‘"kÇtUíC—óñD}q–…¼­°vÅĉRè=Ÿ% ³Ýcm» P_(šPÊ©¢È{EçôëItj: žœåD0`7eW(�6AašŒÐWÍõ^²µí#ouôO…Kæ^zP�'zö J�µü|Ö¹.…*{ù\#ª§ªþš/ñ¨”¿¬xÿ—…óN¶°ž¹xüI ç bŽÂñ­â=è—H°É 0+H¢ÍÖë¨y1ó?lk[/¢#Ú}Z÷÷V�ÖMÍaxk°ÓQCÚwV�mpXÁ<–ª#WÝUDk¾*³Ü5rЈsr»?ø�Š¡´u*$™Ôj…Ód‡ÂÆ\"þ|(÷GÕô‹ Û8À“ÒhVuzÙ÷ŸÔ*zk«G›šl7ˆ›©�>nÇ@Œ´_fbÇ©d¼;*J[ðalÍR ›zÌ•_^^Œ^RE‹€ ‘M)X…J½VTj¬ŽPJjc˜E¸ÿÕQ£‰¬ò¸o5_f~Ñ»ˆº#·KK’1+�j5Q‚O9”œ†/Ä…ù(ÓÊœõïìÆê\ù±§E–8Œâu�ðpä§áÛ…`2)Ý×?7Ø·YUpÁc ]*·ïÁ‘«0Ï”ép‚˜ A6ÑËüz‡íàUò §]‰ ®lOù£Ð‰Ö�³`3‚²`AZøÞ¦ÍwÂYy‰¨p?–}Ó‹=¹òÐhÄ£7Èph9V!ÀÒe¸u{]¹2À|Ë�ÁpКE¿oí¶v�d¦Ê(ëîý]z@5Èv$Jì�æ9Ÿè”^šzK¾ ÄüÛ½)ÌÎëÿ¢þþÀWW–o!„§D?Ǹ´‚µ¡æ#(Ò£ÞÞºy �!tåß–­‡¼[ &p‚¿^l$8^´w�ì=ä(·¹ŸÄÄΕË31.éÇRŠÎ{‰µÛnĨ>JÑK‰IóÏJztõû00í å¥p>ç—2÷PÉÉ\øø^þõ�Р6ÓïÞ|§„û2î�.J”G V×ðòцç07Em]êèÉ—OÕ–›@û†×JŒ„(xm?¯Žu1Mg´wËd$¦.ÿb…‚6Ê~}³ 2_2ÙÊN�A ùØ�w+ð7¢¼Xyãý�;1eÌÚÔŽ];V Gßµº±L¹Ô*Ø©8i"N¼²ôî+‘• eÈúhw½!é¿÷¯'™ÎKrÇ @ÞbÇ ­=ÑàØ§>u-} 1-Ȇç ï…ëó¥f�[â ÙY,iV°f/.Êm ©�¢î(&oX8EŸæ-j%f„o‹J3ÂÏD`R¯ÉÅÆ6eMôª��5®í‚Ô­+íHë¾Í 1z#МÉܶÊúׯö¯ø ¬Må�Ï„/ÝDž3¸ƒc—ÏãâtI*â\£”Øñ¦P�„î‹”ïò YÖ�E*¿k"LÑ?9�Þ¥\cñ]+űŒ£ºÕÊúw¨=[Ý¥h©£ ‹†NÙœN\R/Ó%šb4OÖñÀ?\j­ŽZ‘²G™­)øL¬% ?”Š£æ1(að~Rý€K‡û ’¬ }‚‰ÐóWD|ý�ÔŒ”‘Ô·E£9bÎfv Bº‹˜ ^Ò¶$àDKøE½ÝÕ‰òÉ�ž°b—lšÇâÅš'yskÚ¾&ÉÁ†S¨ø,G*êvYx^õQ/˜sÜœ3ú<~¤Êüq$�éç“‹à¯c6r·ŽˆÛ(‡¹ê8�åY² M¤œ)ÊtïjÎovÏ}¨ƒ¢éèOÙèØ{DëéŸÙæ$xŒíºö”Å_²n7’]aZÛ­ç7¥õ(•PÇÅ›A$sS×âœàP[òˆì¨8ÈFIX J=D*Œaó¥oGh“Óñ§)£>Äb>¤¶ÐÑ3/Z€0Y°�äíÅY¦àg+–ˆgÕUÞö‚Ýihi®º ß3w£�ÊõÖÕM'^Á‘LeÙìÈK"©þz’TemÖ)d>éO-‚NU¹|šÁ)h˜ZE¥,øÅ5O.§ë]m7^^Ï p?ˆ:c[ßf†‡Ìè\„`Œ‡u ˜ƒ#ÑŽÜÔ-¸öf«Ox0çqÉòµÈz$UPJØ,³„˜ey[£aôFnÏÔ1diýGàwøÉJQþ:dÇ^û®y_Ú›g4rV 7tÀ]^ñ]ìåÕYƒx—�p2"ÁáŽÏú/ñy²Xþ’¸0»x~¤´¾zÎáå¬ü•b!³ð$‡t† q��»Š]ÿÕÂuƒ¬þú¬ýöC¥'tÖ­u9MÚv2h—³Ã˜Z@~­îÈò'g.„|}øÛ.ÙR ãó "¶¢¿ýˆ‚6ì°·Z§�«ta¹ƒ±[§»ÐùÞ"(# QnuÔ—»]Í^^‚‘N}Ø‚±ì”ù$P#ië9ܽ¦ÎNy–ChžB3‹¯pÉ¥)±¸&¡Ô]Œ] hmÿÞqÉÖi•¼œA¹_ûq¯ÐToA"#‹ñýd.I ™Yä(§y=ú¤ï f¡IÅÝl¯ãõI(¾ü–'Ã4)¨4{8ˆäú²´º*ÿ¾ˆJŸT%Ë|ÿýèTÙ�—ްd|H§Øæ�æ, /‡5Nì=iGZØŸ�ϽIWƒ9–Ê _«r†|búºÿøÊ {,£3{2K/ÚyËÃ’Ì—>«”\È ûxõé0„)Q�ɪ¤l\¯Òoi�(#Â:¹’炜ºm1Ì%€pB+$ßäŽ~ÑUg<—T ÿb:¡²÷Ò^‹é›‡¼Š³7Œ$^›Ôê‹ù–b`Ch,Ñ€‚R‘Þ|w¹¶í"Ðs2ó4¨ú§éÔ¢‘èB �u°D…£óÑ,?€Ð –›Eµˆ'Añnžð¯{`“ ™2:©ÀfpªÑ/ªo…=øØŒÖ|7þ؇¡¸Ðh«x­¬U Dt Fßlp·Hx(ÆHº3&€õ„U·f0ñDlN„Ì Þ„Bç�ñ�û‡ÜJ¤Œ[•O°ÂÛ¶ Ú\®ÇâÁéƒÓfvzŽ*�^cqµôšðáI^£k­7 z’äNV�ËÔsù�m/~VÌ+˜C¬¡�áF%CáˆÓĦ†�z¶`i)İíÐïßêql-•ªé¤¼½8ÿ­"è›7"¨YÂs|8;KhZæß±S›æ�Lœ>“2ØWGÖ&›ü‰!^ÛÌ5Hmâʵ#Ò›–³F% ðSˆ¯·ý@DMÞŠ](Û¦TiŠc•BUƒ¡ûåÐõž=¬3ý»¡�—ßг) JÝ ¢TÉëþOìvýeO½ÒŒæûëþñNôGƒé¼Z Œâã øÒ`ÜFÏ·{íhMø‰™ „~LnÞu ‚óxbçQrЂ­•nfÁÏ–`Ca|鸰øÒáž-mJHdÂ5�ú¢Qï®àgqu(Õ'~õú9=¬çõMÙ2®>?ýKR†‚ Ów­�ñ|3³ðáW,éKún«ÄóÅ]ƒ»ÐD] Eå#g–_d¥„  R^UT$•®�[smõà&¦4ID½œòýÍú¡§])ȤT$ ¾À§¾×)…ò”¢�™MÖˆbõˆl{¬ÖÿÎ9‰³� y&Ø6¢QF´ˆáÛ¾ùÎÔ“Î+øsõ‚³÷î_6WC�henNö~{rWÖå[hC6©š”¦5;Óqép ö-Hð˜£Ó߯pmÆÚg¼Á•ܨ)°è‰,1�^ö\€Kk ÎÖ“m¤Iu sOUê¥ôÁ9ÜU9ñ6%L@$ßøW ¦£W??ª|Žˆ²¹ åµz“&g`!öÛ·_Žlýa92ý8Pó 7A«±·“¯Š™Q9è*Ž‚ºYÅX9òà½�.ÑùUyÿ”Ïbìs^mwÊHÔ°Ú”ºÀÎ7ˆz?üë¯Ûë5*Šcëu�H rX!Ôm? r„RúnA¥#ï3]Üy§ŽîÛG·ÑIq|‹™0&±_pùkõõ¶ô–²÷Rá¥3|À.ªu.S|ÔG qm¾SÎ8"^¯Â¡oXc[;c®\¾ÂÛߢïÑ™š!E‰ü™6ë¶ÆÊú‘�9qÀ‚iæ#Ï=Ç~•š³ÛëÞú‰Ão³{#>÷þ ÕA+mdØë£º“ä ~Éi=‘Ü­XYÆØñVÍöU!VP0Å›—�þ{‡Ïßn!¶¶íw›tœßQQÃò¡^þu5Dº·«‹ÔA1`’oµÌ£‹Z½q_ò<„‘àõšYÛÏ›H,¸´”¢kGŠ#ö’=(Ü >P:Ë¢¿eŽ;æß8]È™ã# Ô o6‚T/Q¤,ðNê¾0Ÿ˜é­ 1ÌÒ۴ͯD.«�‹†zÁK�)]ß’ |äwi²`–l‚-©*ˆ,Ü}h0âûLT<ñi´Hº/¯¾Ëñ‡ßµ¢D«‹î2{‹�¸±oúiõwÃÍÁô•¼£8oÊ%͈UV‹Â*ÄIþni§Q2/þ´�,›#8¼0q¬"Àˆ” &ËþFlUÏ&.Po‘ ¡6þ!¾}'¯–á8Ñ›ÇKî®4ïÆ×¸ëÃŒ8"™Ž×Cà nBÕPãɾBêh÷o\G6š`‹õäT_°£æóVMyð‰² ºow°«Iˆ u�“Å®ÿéF[Λ@Ù0ÁŒI¸ª\ŸIÙTÓ¥B5óS =¼¬¤ÓƒDè %”Õ8CèëÍ_�Ž¿…å. WäåBÌ‘ÿ‹ÁÉ‹.[¿±ŸBƒšÎ#ôNÕŠø ' ‘»ƒ— y5“ �åÇkQ3pXX¥´_L+´ÃØxb^¼'á¨L)!$ D9kMŸèº˲ ²0‚Lib±ý¨¿Œ®õÍ'HÚÞâ«2Ô‘†Ë“C ='­±¾l`l¿ø¶‰Ï’…©oÁT0¹sáÄi8 Û˜ä[Ø£ÝüÍ&)Ú†CeeCWUëݦªn�°Ü¼‹ÛÞþ¦6ñ $óe_®ƒ¾Ò¶²$E¯õ׊ÀÚ¼Ìx£“ãéÒ>Áš›\î\ø˜a+ØJó¦1ËRÌwkîSÆ�.mEUĿܶKp׸ìRöX3½Ï8ËaIx!hÓê¿$Ôû…‘%a75Ä‘a�Ò0ÎjgÏN2ò'Oɯ€ nÁÄ­Cd•MxÚ®c-õI—ºLUVS†k�`V•5nšJ‘—²ÛüÌ<÷ž¾�˜ùÖm ]aMCÛ�ÇEŽÞ³­�!ãXÍ5Ýv½­ë RL*x†iALÅj+¼£ˆ\ט?–z 8sÀéÐ2±OKôbPéøÅB}Nɲd´„-7#MÌûKþ#S%ßK�‹’¡YÔ£h<Êqo·}¿ù�뎟ª!MÑ̳ö´7r––ó²½M7›3å\â�W¬ ;‰÷ó†ìmŸpª?þùhöÎq±'š£V�Ÿ¡áÝú]�;­xÍî�”iz4b‚NÓRîC¥Ë�¢ÝÕ~ÐÞñ”fÝÈíÒ�ª¯ŠÁ¹Æsƒ €àÞ5›Âzð‰°¹�ֹͫ;µÕíÝŠ 1íßEPù0QÞ‘LY¢Àýžñå…-V à°“¦79àö?ÆsˆºÑˆïɰrèm)€®Zô½|;ù^Úù9rô3ÒÖ\žeæøªÀµX èw éÜ5çxßjÑB«%›[õS®‹ÙI-½®va´ó-®x#Xòr|D#'�È@¦[¼£Í“×+!#OØ£UmðßS#¹+œcÅ,H#¥ÕëÑF*Þo«®9c— ßgÍç"ªÆhmãŽë¤T.¸!×\ÇÛ6$"1ñYñÓ3º«€m¾Q%Æ=Gª¶±‹úo§§vd}œD„vh;é lhŠõ××¼7™ãƒë@©@8þ#Þó³ ¦îH€‡Ÿõ�›s¿¥¡ƒùDâoÖ+Öz�i™(”>›ÀÛY *´x¬a�p½š‘öA­¬—;™’=b%ÂH‹OÊÕ�¼ä´””Q*.ezó÷K‚ƒu˜x‹•¡ÍKbu³c(Âc¹DÄï�S]"K�>Äéco�}ˆ+(«ŸP#>œë¶Z–va¤|í7¿V`p¸P8¾_=�1ª ÏÉQ®øÛxUó»·b2³÷å� àÇWó һƙáa°ú´ÁˆÍ˜ÝKô–*5°ß1ÍVüOÁ�æiòíŸZð÷$ÛÛ©y¬‘=xtðE¸«ýÉÔŒE�"›}å]À”+Mè?^AdèkÉë06tàS¶Gø\'pŽúEáùŽ#Iœ_Å�:f÷]%޼O7±ÍëÚ.›ʼ•¿x®!ÒqÝ|0ª#‹�ÏËÝ_DW]@>éQvÈD“ú„”óÚL õŠ /'�©Zœõi54® r¡pbÑ2†+ù£xÁÂßqcÝeŸFƒaçl Ý{<ËŒIÖœ• шçú¡~›ñÄ9Å%î‘ÚŽ€càf5ñ7&!Ùœñ=€xþvÉ¢x‘™g8‰[å•9ÖÝŒ(Úl?6½¶ô©}|çæÎ �¬'mI§p°¢8DüÙÙhM¿VàmŸ_£u^} 䣊X p9_ KQ;ݼ²I�6ðÕÓ×6ò ÿѦþÞälZ®iô&æãhˆ[Á ˜ÕºÎªpP_-L›ø÷n`ؖƯfCˆë%÷ñ•g�CR(ÉüN¨Ç×X�#c£¤tBJC‡të÷�ÎÎufû²Wàý`þˆÌ {ǺªD¢Ê\­l�P½Ù>(ò6ÂRv¸¼cóV^[/�{n3T‘ ¼ŸõЧjÄj&(ù¬�7“ÖAq>NvN—a¡$ùîö3pî’XeYÖ¼¯pyÃñýÈ;“&(F1öå“`ŒÆ¯õLÎfdÕ…p!<Ú²S@f Aû«³P1¦á6Þ™´˜‹ÁÞ8mc¼” w¹œFªàC_±*äÄJC¢˜Pž5™öoíA*-8à7�†U·oâZýf1H'Ë•ü›±\Í›yŒzÇà–rlˆ­n½–íª3 *ÈbuÃ}z§G—ú¾WD¢±åúL»Ì(zb¢˜›‹‰´ÿ<&‹3�H‡C]Ó·JxM+±Ü@Lt—:#ýDœ2Ÿ×MµÕq Hü¶5à¥*‰Èð­"úº×cS½+@éÒéï‘)BÍÄÔ9=ÌLÅv’ÿÂÓv”oI™j…¶¯à1½Ü»D³"ÎB˜j®¼–Øà¿m!¦Tæå<²f†#b!Ú ²V–¥Â>÷PU­Y�ì«ÎD»´ý‹j�ƒGHZ¡Åì9è,®Êæiº‰ÆïÅ1„ÛÃ~–F+þÉ£dËÞ4ï¯G¿N ?`}›:JáÜVœ5Ž_»)µ²çR„�–p«7{ ŽdlÍrÄÀ®ôе}«-9¢™õ6GH›;‰êUæj—Â(_±½Ô0ˆ/ˆ“¦¾üjlR×#f39lB–?¡E�2(~?$Bf¢ÞÕý“Ž}µøK±f~V ìÚ¦­‘øiK”õ"ä}HzþÁ�k£æ‰ÙÇlRÐ?…êØ“‚‡à<'dp�„ØÅË�ñ ŠqJßi¹Â e âŸÅ“2Át×yuÂ0©Eé`¿4lˆW—^â¬ÃñÐ?¨-@t—¼*TÖLÒ¬Ÿ;+uÿ p¢„Ê­#»ß¶D,÷ý†æAÜœRzë1ÛtÅaZuŸL4(ÓA›dœrf­ß"Ÿ˜¤Køôæøèý’d‚¤h6{F ´Ñ¬Vìh‹­išëU-<=‡ž„ÌC®}�$Gm5ˆÊ.DÑkãWИJ¬ÞPb£AÐಠv%EiÑSCžŸ½×í¿©2ÜùvFÙ\�&½å4ö KÊÝ3t/ʼSœ°aäVÚ¶mÞìº!®s|0)ó-aƒ0,þ{Ð�bv€Dô®ÜRè\Ä¡CF;4w4K©‚N&Æ 0Ôè¯íK1”Q�q˜`a.cšÆj÷þe³!ªí5è†Ä‹Íºž˜^fnú]#‚>kmòMŹ[Sî6J+�a›„ŽÄ¼í«6'ùœ‘N¾u9�ãÞ*ÚÓ.žø=ô^+åábŒ•cÃmIÇ`¦Og(â¿^Ø;âèTQ_K¨x¶Ø±Mí©vã„69‚D>‚¹Ž—�çsòذ%p@ü‰™µ­R°"ù£»e•²xu7€ØGÒÔÆaóÍ­pYÏÿ'vm“ab�©r~ýí€PBí¥}¡!j’cîþ^‚ñÆŠ(Ý­Ài·»:¹2Y/éf(«7|ÕÈdµ/6± ¨& o5_cmVj~_Oá€3¿C‹_EÔžh¦-›6¯ýl±¡¢n‹_ó.e6.›ºÓï\ßLve1qµP§�„SÖ]Ò’y °G&Å-+BÏLÕ¾í½ñ…Oz�\Û{çU6— o/È|`‹öî p”7_ LZ›/îíµ¡rP‘P4ÃfóŽ`ów«oŠç dìŒ6WÂ?L.ŒPý®xÔÊñËÊf &ûÃ;–êG, ’¹Ij5à»ù‹ÿ]®JdOí²…uÑ-ø§üm¸BºÜ°É­H�üô(›ˆ“*‘Î�2/ÀäŰöÒMþ» ­¥ˆÂ ÀðL [q¾ÒÞÁ€ˆ™ š«.öU ÛYõD�î_õ 2s Ð]põøb6~MÖŠä«õÁ»œõ'wÙ+Î7ø^ÕpæñŒmK%s®Bu@žÝŠ,U+¥n"´× ¯zª£íH½Ú猭ë‹ÎXE.+—¬ó‘çÓµ•ˆC9¦ÙÛè•êK‚>Ñ9!29®ööN ¦ªÖ�-Ír·Kt¥r�:J:Ê9�*½çṉ̃åÓNÀ‡žŸ½Ø÷b¯€»Ÿ×wfâÔ 6 šØmøÃð#òâôÆ­!¢[yű±ŽÚÜk¥O´é´á¬Ã[kCÇBˆ6ØB¨ÿè3®W‚©ÙO(Ø�°ðôçBÞ*PŸ;ôãA&åS�¥ú9Ä|1·ß$0d œ´G?ßÝ¿�H¢å¤®ƒšÁd¥”F�)ªøltv9h%CtÑš�5²¶êTë÷ªv·NýÞs &ÈQMIœ.°€�ùN/ª>–:‡O6;DöÅAÀ�LŠÄùcxV)[ÿ ³»ükÒŒ¿ÏÉN/9àr·ÉÍ‹!ø u1Š1‘»W¾ Qwá³ 1¢Ïã­±Cìk^˜§1ù‹Ôù6™%ÅB ç@D¨ª)›³7ì=ï:&]šŠOÜë·7’#±·\;½ªy;wÆT(­m%F€À×îKràµ:%0ÉT1³ÍsùpˆY{�ë6³ T³>¾·ÒH`Ø€ìLÁ�0¯ Y«(G]Ìhß!�¤ŸÓ8ñ½·ö€GÎÐìÿºHÙ×ß9­p;èñŸ°Ì·agü{…f³I@Âc3ÙÖªpø¼®y=ÐÐêàI ›G›³NUÖOSÃÃÌLÉšþJ›Rx¦=£™>˜ŠPÚ¡ý“0¥,è<òŒÛMÆE:ç§JÙ-Ÿüøt`š»ú)zU�¯ú÷=ûÚþß_"ã7Ie$·M´Q¯� Q–'.ˆöÑñ¨¾>6b® ^¡î”;í³ßzI^âÜs%ßÑÌ ‹õ+j^[Ñ•› ØBŠ+Þû°=‘Tòm0Æ[®êCÏ/á| î�¹üßB@:Ç*½�v·þ@'0˜Æw™èƒr¿’Ä£ñIß­àŒ-ÅŽ «œxF˜c¡5¶Ðc›^q‹ÂÞcb©÷Epc³?88a+]�Q” [vÚßÜC2 ¡ÍU–}Áw­¨yÖaœŸš¿>Ôª ÇgÓ9Ï~8m²Cð|üèÐ!„Ý®IY ] ¢µÓìix†eÒüHzy®üŸÉXÁ™Ï¥[Ž`ÁÞ ñüNwúï¡"¼á3íE#䛚B iž@ÇtV:ÎX2BöþY¹ëجÍóȤóÎ’½©v´¸^àFU¢X:IX"et­Î¶›¥lÁÎ’•³g?£YÞÅÖJ5ÁUº¹ %a-�>¥’œ:Ã… Énûg¯VÊŠ6ΔäQ S7ûfAïÀÝþF°ÄÊRC€ÎCÄ[Î"_å–Kì"�¦q%\ajDÞÐBAÈ¡84ÊÚ}Ì[¼Å[ûèònáºZ_R‘#;xkª„¦ôéÉw¨LØYkAý»ð={~Ñ‚8%ÊÎÅ+ÿNÔ‰>Ã�þy·?£ÒäfÜ÷0ÄÉÇ t0\>߬þì�\fN$vLœcãRn([ÒcH|h|Uõ³÷ÙyMޤó(Ç;ëè#'› å¦j†­pÀþÛf�;*…=ðt}è샇B*TDÁÇaêc×îU�»¼L5JÖ±‡k¨_®HåËÚd2ëŒ0k)g2‰1x’z¨è0¤`WqðþvGu%]«-F�tÏÃùeæt”ú´(wðrö4šÇß�Õ³sÔ>Z¡}”Ü1²4t&,Hå’¤L€6„zõÔ˜^èY’ójE·½PÇa¸7Nwîmc�2åÔyC§'#½R‚”¦J�ó,·PˆãÐÉš\QÏzyøS¾ÁWjX²{É�v™C,�#“*+¦ÓWb”A­9ËØ:ÿ¦.ž¡Œñ$Éò3×ü`�q�Æ?~Ç¢Gî®Á$uùX’f!­œÀ0‡ðYC‘êš{·¬ÇØ”nƒ"™ ©qg ï»`h&ˆA= \ ë{“ÇÄoA ú‚Œ¡Ä´aû\kh*a{”ñ >bh–�•ítg.`�ÓSTY擉B-UÿëºH®ëŽ-½ß‹òò,W‚TðYb¡›Oõ¦7ª^¦Nò´ÂD5 ,¹ïFsC¯½7‡Qá­w_øþ5&‹/É ÛÝ|JAzÒÓÑÓ¤”%:>ŽVƒXõ.u†‚•ò8Є#¸I©Cv5 ÖèHrEÕ«G§Â¬‹`s'3ÛO'�Å×ó îxVßÌEÝö^4WÞ?n)¦¥ö‰Fº±~ðòT3SòǪ zˆèàÊX æ=0þö–�ïõ%_:÷åî°„gû[°ÁW�X¦áJ5]‡;¨¾×Èg#£œƒç´ñI¤Ã³#�›Úg4‘’±ŒGì9ÈsG�éÚ�ª "ãbÚ |…SÊ*Á^#6U5¥«zYc×”O’»W(ZÚ¬Ð;½Z½ªŸ)$/@ MÚ2ŸþÎîÓŒú“Æ�&;dãõ2�}q€ä¡³}g®IŸàªE?lù:�Nn�[ÅÆ$c¬ lJÇ”_M03…-I•rY÷nú,Œ1-QóIÑý4äs}ª£šTpž¼ ýÏ(Á)?  Z‚±µY4ÎFöZÔ¨ø¥ê’Ý£¡fè'ÍÊ5mžØ6hm<ý»ª`‰¼µ =%yr²Ø5”@A«/iÅrhí B˜nA-|øN!-–²õ½Ù‘LŽ1Êx@‚+¨–L€)›aCLl^íoÔ–6fzzšgýó|  Ak /Á¿šgÒ¾öWÐNY�ıù©4 ´W|à )Zúáµåä{ùç»�#,‘”ÿµQ^Ò­÷²§L[§ý†Aòtvy‰]{�ßUÏQÇ]Çäô;÷±hÀµ–S˜ÈKŽ>œÄLÓkNDŠ£Žx¼Þgï>¶LWGÍ:ò7“üÒ.U0h ]…z#i%ØÀ΀ÐÓ­BCûûU|oÒ C•ÑØ�8:;´âq䀒kÂqY÷¤uÀS‰¥.„>È{ï�Ï%ãþs÷~ÏÙÆuqÊSLD‘¿$=¢0{šc;Ó&xýmåLw k Š™uºžË¬PußCÄ÷•i„ÿ†P,8ã?à�Z†™½.« ·0�¨^K®åórF‘\äòÜÞ øXgàÏŸ�ÏI ü«½å!æÉfÑÊ "§ÿAÀm|¶ÀŠ´fÅ”@^”øõؾA\¨ÄUƪlS¸c)GÃæ_{ø¹Ühkµ6 §¾#b“ fAœÕ“Š5®Ÿ½0/Ð Vëh¿NœÜDÖ…/»Su4+··Â´N¯Æ’=ˆÈ|}¾sz k+ FZÜRÜäÛ:Ó�@¬8êoµa%ÝéÛN#áÿd²’+Ìô•ÿ�qÖ2oÿžö‘‰y'ARC9Qlv‘;sœ‡÷Mbžê£ýDãÀ2òÞ)Úp-<÷s.Ý  Ç`’Õwµ¯Ö~•³kÁé>¾<#wV¬ âÜÀ‡ýÙ'—Í÷%ÊšdÊ&Â]³æ'„…›É¬ëëéÙÞ�:) X?¤Q lêW'Ú:ØšÎ|ñ e•Á¹n¶¥|A’o¥0NÐc½)º*r­†Š (“_MHä[Õ,vŠ2¾+Èž»ã/ÿÈN(zdLᶦ¡AÅÏb)Û€ë¶úmé�9À‘�ÿ;´n ±˜É¡°` }ÁÖÉànßþþÚ”¬Öiߪŀö¤ÁX2È#ù¤ y; ÛðašdI=$Þh .¿¬Õ.ããÍŽ‡¼ÍCÐû,&Lrùóx°ž6u› Œ �“ø—­-CGWžpÑ�Ì…çÎs›m¶•÷^¯U2ê5¾‘uæ3ʶd,Ùiƒxµ23l~S.l,o%%$' Ðz;b±tÜH½ôvu§Ùº!†‘ô<¦C-š¹<)ÚJ‹²Š` ì§ô3{ô,gk%„.Xz…•¾SÉ ¾h÷Ô='·†u@*ò¤]'H–Ä�}¤ÇÆðÌ4pM9°¤œXè<Òe@«ó|fÅ �¬0óa1•”αBÆÉf„£eï“|J˜cv´•ÒÀê¥àuy<ØÊ¨€ÅdFßaT|5/ݨ`'‡OfGcLærÒ;�Hhï绂4¦±‰IÛòd‰ñ€>˜�yý±×Y.8ïÿ¡wÈ¢ž‚UåüÛcKLI£\¡?f3VN¿7ÏŸ/pM]à‚ÐöPa7“Œš€^|î8 ¼]PКV½þ>A6×q®JÅ.Ê�ìo|wÊ Ø·ñ-}ÊcIô'�þ”T�A¯7s†¨óít)Á%ìcpÍËjó@ÝæÛÚt$h£4t]S‰$ŸÃÒÝ.…w®¢Ù•«Îþ@iG V0yã8mÝMžÈѼNËzI !pDãš�jŒX:H`rÆ®IµŠÖ¢.?—­Ü:³M³ü‹2Ϲ^ÍuÉä[;k÷NéûÃwÒwá+ééÐ"JÓd›àSþë˜|j�TJÑÈigj;‘�¿’&@ç`¾ V19J¶`• A¶Ô*"¥�DÑù~`yö{Ä/A”E H©ƒ»†D°ŽóE Ø’týòÿÕœ�Œ…8 ¯=-d4þ¸:ÕB4wÒ”¶RŠÝý‡ª­óòG‡­3cЇˆ}ÃûU-NV¹ØŸ´pß‚ÈXìáÊ'/�ûYÔ|”$$ž=ñ’—8ÄãÊ»C_Ør¦B±>šwž1$§-³…Æ2m+˜@¾»ÉÏ8wE’Wd¶¥8%“~ŒÑ½v×bò75}›t‡¸IJõÃíó}²k<‚Í�,�ßK¿i«ÕÞÑõ«@jD‹O5Ó‰"­‰Œ’”GÖAhíŠ{-%6©«,Váâö¢(küKëG¦÷�B'åFagî#æ$D÷É‹º¶n1núOV”åOôió×”ØMrþ: êÖRä½ß•G»áÇ.ðm+ÃCq=º³à5ê�ôº6•˜tÊw�";%`„|Ð:<¦.þ�”ÌGÚ3ø;³ÆAæê�ug޶å±jESÑr#]…TÆTØÎîð© ¦n‰Ü9E y&¹Þ•éÌO3Wú*úyÔ 2¥À§pO(ÿOÀI–칆9ëH?™²252y€‹2�,ܧ¿ušÏ¼ëP÷˜¸¦ZÑ7>üµÝ™ê Ü+E¨‡Ù&ƒÜ<„ÄáV~Ç�Ç~K<ØmƒÌ9ëT4Tgœ3}�MLYío‚bÛC/Ϫú«H7ݰŸ úÛ/dbÕ›à´o »ŸAƒÑ ØÑËŒ©ZD^ŽÜn+]C£ÐBi°ï*ý9gÅÆlŠi ?#·˜§v)™2DŠ0ÿ*4Ñà8‹ØÝO<ún~CbÑm¿šF Fôë^­?’ŠÊØFnuÞ—°ˆM­V¿sß»� ñ(„�…‰Yâ!…FØZjŠG$Ù{{kNíÆb�øÖ†~öI\ê±öXúlýKø+EüµÐ]�NŠ,¸.oØ •+ã¾´ùSªÚßW!à')^…€û何ôËÿ³sù„‚YÁ…æmvè‹t²,Õš°ùBò);°³ë‰“l––µVvCcÊVE’5Öùÿï@ «Ø>¦±C\â-·T4#Lë˜U1¥—n¨Ç�JìÇߺ@b0ÐxhŽ úŸ…#yéjÒ".ä5¡èêŒ'~aOåõÚ/¸íz^i\a½dEá†a¥·ß³fpƒ7„êâ¬ö°ÑÒWlYœ¤Ïþ‰"%°É38”X‘*µà xE¢ñK˜õñêÊÖŽCW®šX(ÿ©nÜcÎUÔ†jôÞéxAbþÊÉJó�XQšmö,`¸ Âî¦%Ên�áç H¹ÕE;a…™›(³“ÜTa�–·»¶×¶DiõðG8KsÊmJL½Ý^Qõš·g#][¥[©“-<‘˜î˾ÞT¼ô§‹ŠÅfS'*š™>0p"´A YHãÏÔQŒ»„.ÐØ9[æ7ÅbôÀ“]ð‰†¶“F¸Ëx‡¿²^¥“Å'/x™?£a·Xý»‡¾f†—àNgß§Â\¯wz¦”^äú·$™Þ?Òë}ë–%Û\„H¸àÆ�ºžðçpЗ‘´Žö·Ÿª3zMΔÄN¢/ogYÙ’z-èe{æE¤¡$óÍE‰Ägnpõyu$žK<¬,¥�ŒHœxch|xî5ù23 Ilþ6 e!õòIjyx¹Úñv#†‹•éÃÅ#Zp¬2óûËýû¤á¶°wgJ½·<[e騲ӨÕkª†õ‡…lÂÞ©Y༺™Âm?â=ÆÃ:µLò½¿7^{( ¾¥ér}Þ%vþe?¥Â×x”²zc¬O•9á–°cnx¬ž¦°~PŸd–€|ãÈYŽúê°¯ZsdàØ‹šÑ†?zíG©]îJµ½Ÿ$-ñdCøò3TPr¾[™O�lp¨Ègह>aþ�Sé¶imü³£]|-NÒ5*"Bsµ*}[¢ŸeÝJ`KM´…v3j“Ûþè� ,=¦dgyêï9`”“‘©sû„ «“WUøb•;„�R1²¨ øù«÷/N;[–q>bog '{ÙÓ|g‘[Lk½dðúf>æÇÑî ¡zöv,h&eœà.H€Fæ”ü  ªº�ÇV݇½r·¡<¦'r|ÔvÓI{D?ŽâÙ•÷7ÖîX Ep²<Çü¯é?šŒ¬êVŠ ŸôK�€Â`kk#ÑÛ(IsË¥‡°zs×Û¹ú䵯êrøœox8V¾ë^ª, †½” [·`�x„]”¢G°' ó*e~UlP|o»ÇöñRI_íÍ÷y¦Å%–®_Ù^«¯JDL£rj–ŸAå/„¢Õ–äÉž‘–îÐh�* fh¶sö©«yùHÀ¨ø3³¡²+ÁÆÿ«©Jää´ôQÔ)ò€÷ S©&å¯òÇIòl%=`ì¿ïô¯*4Bu¾wå Ú÷2.Q1ª´aÁû Mò€ ß-¥Ò0æÜq4¥n੪žBAÉo÷‘Ïþ˜_•:R¬wuI7¼�½€ƒH ý/Xtó7Š,ßkþâVÅöx$°�¼—RÞhIžaˆv$Àa/U\zbÓÀnx!ç×bßûÛÔðüctÃ,¢â3™Ä—C) v4ØrŽ­ ÈùöZå¨ ÝFîýˆÉCЫ”ð݆™L.¶Ð¶mË…»Q�Ö€kËò£$Õ»(¢‰w¶ÎI[¿=&Íà^ÄM�ûz<Š€²çðuó"Š'éß>·™‰,¦œÈTJ66¼1%Æ 5m÷%ýó ªg¾盚¨¥å8=Õ•Bógwx%Lžkí)ÄÃôÑòtŽN�ÞÓ¿.ÀMr+Øc-‡°^ÀÄ'‹Œ.ŠIBx$§&‚çâÃ(`Û>›.ÈØR˜^ ¨Órò£ÀÓ >*{_ ­]¡Iå<øò¶‚ýw)Ru¬„IÀ³$æMnz•å—3n$È'¤_̪ä‰M®Ã¬ÿ7Å óë—ŒFö`m©ŒàùI/ÌþJ?櫱š§®ÑtÓÏ*×8¡“fKÄq÷„�î$õ¤µùüDG7—¤»p$îµíµobÆ÷¶ê©ˆš Ì9ùèj ¶x÷¿À˜ž8L|—*ð�¾-™JÛ®ÚZ*¼I²­dÿøÊ r…ðCH{ÙpÏj’q¨ÜȽ{‡…K‹äúöžTãµnôm4¿ƒÈ9Aв@œ “¸’ƒ¸=Aõ\YÎÀîQR³ß3`oòŒBG+#·2î×C "§ú¦TŒùÇJ�t÷ðå(<ÔD}ò�e¹Wo�6¹`N•DUaAà·Ä삊½V$°ñøÓàÓ  ?óôVªØó“„,¡–t¼�€×ŠG4A“nÏš¥Æ¬‡7ù± ³SíjÚô½òÈ–Ó æMFfy}.”ªðrÑ"ÝO2×–…™,|&Ú^mPˆ:®% Ö#o0Q IŸc)Xˆæ˜Óh"ý=Æ'-½ø�ŸnRŠB—'§£ëÿP‡s'”ŠvucÓ£Á L=A¯hœc§(fÀøõëÉ€‘á®8’µ9fD@ï÷Æw"Ûš¬›ç£WâK#•ÌÝ¥µ¸sá¸ÐªIAiX[¯žÌœû§â›»›Y @0"êÉ:(6xQñ”kMÁÝ ÛqTÙÍf¨�¦éW#;QŽ×�ñ2#â6é[Ùø ߌ$éÅ!‰õùÍD¶ý_DäÒ5jƒqr-.´4[ÈÐÏÊZ.Ï7Ï+ëÿn¿úÙZ’:G¥\¿­h7.=nc]J­§¶–~eý –=l†ÇáÝA)vž ßêìNÁsÙɈ(†Z CßÔűÄ8Äçž~{Ÿ=õÖL†Ëœc‰QHFâ.zÇ‘8¨éÇKÕ‹,ÑÙjå(?>ª/Y7¸)ržª¹ � ÷©ðtI`MÝyÐXC©5Ø:Ъ™¿Àƒqu²[N^þQPã4Ç3•@ãÔ–U49ÿÞmtðm ¤×ý!&C峦¡n¹«‹FΗf`q˜cýqÅDIÞà­¬mºÓßÜô«¨û2OãЕ0ïaDÔGÛõ�ø+ 2Tp]Û¨ý« ˆ¿¸27D—,^��øR´Í�¦zt%ÒíftÈÀé\Ÿýº?(äM&ô~¥^ÅP!L'¯pjÊáŠU…;'Ô×*ѣ݊>_—p³VÌÍ7yš�f™ ½ŒTÇcîr¬ÏÓÁýÑœäÿ¥Q…–¿R›â#�߆R";ÑŽ‚V›¤M� húêòÇIŠÐ£�Œ^Çþ“ÐqÛeaðù›ŠŽ&ø‘?Üè_Q®*ò- «x‚˜+�W暣]NO­�tŸ#áàíñ$�ÞàãFÌ@uœiÈ›áv.ì>27jCc+jh’šnŸ¨&ê œS:kçÇfÇ6\Púš@ëd×Qin&ó—ð/4mvò�iÀ™V‘‰*õd™«hì¥cÒª�Ý'–Ôì*@¦B�Q8-ÆÇ¯ó©%�Ò~ã£NQ˯stz�Óàk\_aäkÍC \7 f¶3žT{þ¯)Ü5EŠÛŽÏ®�Q¯Ï~¯SgÐ3t³T?öõÎz@ФHWÑ ÍQò÷«ö`íŒ�6-eåôè»,æS|FÖ%Õꙃh]c†Í›ßbä9rÏ‹RQn: ”LàÂD>f¼ë®þ…úï0íø ’tHÇM^Z»ZO‹�D‚Î�’ŠqÜ2#bÁ5e•{õ¾ÉU¨ôæ¾pÑâ/›7ˆ¡C¹(jr÷›´Â5ÇÛ-ç/–ìum¥I1‡E�¸DC¦QÝ--ÃÓPc¦c¡|ˆ/Z±Õ“÷¯… µø‰àò¶Ïj—áðÊ­íë_$[3>[£tµ™ß~å>óÛåù¬8Ç_ãcž;wŒ£ì³Ü~†aÀ¿›tê–OݰÖÚ.„¾«œÐÀ ìH3ú”ËK ½TÆU=cð_n@!§‹«|¨³ òCÁbü¯š1Z µžC°jŸUà |^ÿPïB}¹Ûåª�£Ía °j\½Â‰¯C‘2à½.øH,QÅHÑÓ5l±÷o´Ï÷k:¬·<Ëæ«9¾[©Ô#N¤N±0Ï=7ò²ù»ùtq¢×ø,¶K]”v(²4üv¨²{¢[Í@ü 3dûÚýU™ts¨õûPFùôZ;P‚²Ú¤ïbó·DvVK$3† ´IˆìƒNj|ß+Ê\—€Ü´ ä} Åõ! ×£ù_© k�wéeô‡&”ì\w¼÷Ý1 û_'½ö©ª—»‘ŠÑCÒsӛÎãV¶×�ñnQ@)ïkðÓ6ÖâH^Œv.¦ $-Ž4y"ª<#(<°D)Ô²|\ÌŠîÆÁD=@éh;L–g“x·õüQ!þËZÚâ6n$gC]{ñ/:áJ; Û¾ÿŨ›°r�*ÝñüxÕ«s¥9ïJ¥Y­XT[F)“È/ÿc@×ö8fO 5—Xت¼@-Äçh‹ê2yyRážÊ²ýÒS]n0’‡¹Ãò½`!äî�ÅQ)©‰‡wÂ$es$ƒpZ&›ÂRKÒ1nÍñ.B`¤£º²bQmGé¢Qµ`�†nDÖ1mç&ïzŠçôu–�’Ú]E¶’Ižk$J:3ä·º4²¤f^>Þæº¢»Ò0l°XÚÒ†¢XhU¦|­€µ¦‡}²8òãf©3fëßDËߨZQªl…u„ºg\¥í5*Œ‹h©èõžÌÝZq€ŠsÆûÁðÄígÕÔ(„ÞÔpzŸ_máç…"OVÙæ]àó–`‰ƒÂÔªlØìBWx)±~AYk Rާ»�²PH­<ÜÒmÛÓCR#çA ð Èt$¼­7À,ù=qbS“æœõ_![½WáècúÚ¼|Y† éK+XóèY ¨ßn¨î'«‚œ,7£–õZacÂì<0ŸÒ!”_`îlµjïÒãžrO�}‹(ƒjé­¬œNÛði¦¼Ýtã†ûîM{×NýаoÎ`‡=/àÂŽƒ½@¾,_H‚çƒé€Ô Äf>lîCW›T^Ԍ֗±6†@ÄTS›˜V�g焵`£ïõ…&y„¦„¶6Òþ§'ÀGkkžÈ†æ)ÇÉI¨×Ö®ÎMÄ·%ó;+N5·¤\9¸àîËÑ8k)ûþQ ä©ÑH@€-`Î6˜ÁÔg•5(ÙµÃoŸ&¬Ý¦ùþýZ3Vˆ¾#‡ANŠÀE@Ûü,ÛLyS†í_ 9MœØÌâÊ¿e$¡œÃô𝂸€Êêe ¸EèDõ×p�”Ú‚ƒü:6qH)n -#i ˆÓ€¦w©è.Ñ?۲ѦþZ��ñ7ÍŽKŽ“:¥Žk>8?�Çå°¬”L©u"‡¬ätPù¦­8¸S¥ !#’Åu¸QŠ}MœÂ9ª¦&® ªx³K.‚]­ä°™}…ÒA®ÇßÇ äémôédp¯°Æ)nŽ¥µ"BãÅð"¦o+÷™̉×�ɦÖGÆ Y�à·àççÐ�ЪnbLß³É ë½!è÷«ÞéÝWçF½ZéËÙ~“:©�´;$aId=âÓ[¹xˆ8_Ð4¦jÄøó&éQ•WÉ{’ü¹ß䌅ËËÚ�oÀ<°_ŸÜO–õ´;=¯º-}ó1�ˆ¸î`foÈŒiljì3Ë µeóŒØ’øW¹ç…6I¹|�Æ¡6‘O^g£g½ÏµE¬E4�Cù¨c¢´ê_z Õ¶‰/ÁïȨÎúWõEÖ8vÛE¸†—7¦è@r�çÛÑ®7\µ‹Øñ !°ñùÁjHýlYˆ±�t,dæ]IANùa�n YùºÚ ‡è¿#FË>I„Ð@?ˆ�-,†c8qÙêM5XXÍ'fG%A)ì: œLx°jqåXñwÍ7Ãzß[ºLHÄIU�Òr£Ã¬Ra¦™ÍÂñŠ5é\ù*²JçŽ9À[³s�X3Ú¾*XTÌê³H2U �Áñÿæ'Ë‘´”a¯¦†ªBœ¦M*Eþ=ú=k¡´r|ËæZ‘�ªDza9�«:c€” -Í%ÊÅ .º£æ Ùñ»Ú¿g>Œ#AÔõX­-z ®eGNØzr2õ�ã‚�Þ´»+ZéÂÂuX‡øýU!üÉOÞ�Ð3Ý`Šr|7ÈUbýɹö‡Tã ƒ~s$Órþ�\¥úއ3HÌ"ÿÐ<ŽÕm©Hœ°‹´¬¤±›KæÐ?Þð!9EA·Ó¥-.xv‹Š"5/Jý!øÅOýîÕ*^'—’¼K ø%7ý§vŠ‰Â W‡ Àß/ãÅ <4"k(õþá¼zN"`?I©’ÝGîb—̸F ƪ›fT�ð�½”Ã6ØÁHD’—ÅîŽ ?wN£¶�¤ô·õÔWÍ7¢¤h–Ò`©ä^†Âw-"�´îîÔ‘áA÷WšÂM[·I Zµ|Ö¯6X5þ„&Æ©oApo¸v¾Ämâ§tÔñœ “€Ïº„ÏÈ縎$¼=©ÏPïWc…TY@]e3 üEìï�!ý¬!Gp+ÏŒŠ7„«£ÙòÿàðD‡8Øáãú,É^ý žÆEs8òˆ¼H{²¢ŒtÓ~ LÛªf8G8ò%øèj¥¦“NñjSÔDÉßþ}Z©šsÏa9L§ÑY $ Þ¥q§0SÏ…>€9 ­ã]Öîë癿z+¹Ÿô–C`Ÿ·Rµ'd�¸cš¯nïKâ»Z±Ü꩜®<ú±‹ÌÞ‰x•Sö®�? œª†)MÃk[>¡¢ò�ÔOìîĉ�…_ó’hI–ŒÕd,k=-”¤Øèáþ½¢’©‘&0tçÆåœC¬Ð>ô­—ˆd\ðIéê­†t~Èsô`Fúß=Bu,ɸ÷#zÿÙ±9±|T�¥­¾ZP«±²í¤Ú^Š×o‰sçQ*^®GHĘurEÛR‚rš=ÌÎ6?·�öÐÞl¨;áxÑž°Fu(x߆›3AÙçúy"a5 -RÓ5z sŸQwÂÁµâ€’* Å)1‡:÷¨[(‡5ø¿k ¦²·{þÚaåÁ¬?JʤjQÖ¤ ©³Yô@XÚGIYÖ|=–%sôx˖ǃ ÜÈaz–¶ò×4GîÙf=òy 䞆ÿ2Ú¼ nÂvÝý�A!ë˜6ªr@âHÔÎß�ùc«ö2ˆ�7Gân qÔ?»øM5 môÙ@våÛE´’þ …@}¬NP´ß*ʃãéšö¤ýÉ6Žâ‡Ú|| uq¥·BôBwÍEïDŠ.zShà¬é€\9³­ˆá�=ø£îc'™-¬W ~ — H=¨J OƦAèû¨ª-ýÒw ûègT?6}êÿƒ†³ÿÀýeoO*—ÿ—^=i(‚lÂ�Þz¦¤q…ãŸ(£Ä©æ|s6ÔÍ&‚B²ÝÐ÷ôÜÝï¿£›{XYs�vÍNK3Zû."­ÙºðGð‹þOW쪛›÷<hU&½OBLnRÛ{€�ج”D©*™ªÎa–ÎÂ)¥4>)VÆÍè#= ,2niÙ9ÕNÙM˜+ü£Øw]:-¡¥ ni%^©5…#Ø‚ ÇàDJ@�ÞòÚ“�yó&Ç‘á$„"º)* G+奟�ƒ,›· ¿g�„{m½¸¥�¥§Wz IM<�6ëþ}±7^un•Ô-§}må×­¬*ê#)0—zyvdùx}Êšx‚àhöÂ]‡„‹ð§å g�q†Û(�UÁGKÄ©›è»ãÏA³PõyÂ�H¨ŸÓfuazøPJ2g)ä·Ycäå#ñ«Ëýð�jXz3dEÃ7‘­þò†ÖdY]AûdØÀñi“øá¬�,“—;èfäx;ÿÂ.éÒM'_/` 9ƒ«$8Â…;ìzà þscu‚cŸÖÊö”Tx�@5à[,B­Ž®ïÏã“q–Q?M¾‰»$G¤X×Ö(¼µÊ™ õ³ay„Ãú8&$ÉW:×ñŸù´ƒ¤ÞövaÜÉÓ~ /‘þ‘ÿCdÎî¾ÖUµF·vçѰœ V !H)¬ë8%–{!¾ïW4_Ô™ž“‚½A�T€±"äÅ^f@H'ñ¦OÇlÈ6ŸÆUA™Î¼¶ö¸¹ \xÑÅD…¿×÷"ïïðC¹}߇à]ÿö'.ÉtßÄ5ü+39Ý+†‰;pñÇÎv8903-ð’õååð4]�çƒ(/_{µ�ZÃÐNÊ—ëÁؾ©(8õû¯[’ÍÑ?3àû m|¯ûc4Ÿ§ˆWeǦiЃ|J­Á$Hm•¡ß¸aYÜ—8OZ€…RÖ{Mºndž1¨7>Æb·Ñå%úhÉàäb=æd�˜vdÿd¨ä÷ºPÏø—’¨HÄ�2#Bór >ò‹?7>Ø3ÔŸFÑR[¨lÂÌK5·XWb*ˆQ{AÓà!„H£ƒ#*Ñ«©Èý‘WÈûE,¾0}1_˜›¡Õ§$p ââüò7¶}õñ/K³W_lHžá77¸A‰†ÂžƒÚ{Íx2²‡$(ZùEf€'º{må¶"-ˆ]}õ&»Ìë7�Ä„höY|ÙšYÛ”Þ»&˜µ¢C ’/[]~ò0QD¾®®‚nþиNß²(uøÔý à‚�¡0�KÎø{jUøu´Sˆ³naÑ? {v4Ù‘u‰úœÏÈÏ’Æ‘u¯‘Y±ÌI»çs?]QŽR þi!L�NºpûÅr¹¶à•:¹eÕ÷ûÌõ¬P*‡� Ä)¶ƒœæØ£Í†ÁŒp«ßÛˆK–ÝÓm�µ;Ì,-õÅ,Î)M6]ÇNDÔ½µñÙ1ö1J§Ë)Š}ÛÈêTÚˆŸ±¡ßaß‹œç¶Î96˜•`³;_<÷?þ^Íú �Ÿ--a«7²œ‡! jÕ:\6ŸBó×Ï;þfRU«bµ‘ÁÐå®]ôL"ðwRôî4ÊEOwÔÉ¿jçÄåÁ¢aR9¡BÜéJž°ZTÊb À!3KOCB3äŒüãQTåžÀóæÜ‚}`<Õ+çÑ— Èwô �;û'L±¡ ·%UW$Óuè�rs � ©¸4É@³²“vr ¶œJú¶§:ôoü&mº•½ÇqºÑvá&>˜ülÉü!O% ü•h¼”¬ÕïRwŒL¡¢ø;µˆ1ÓœI–Ä-ˆ§ó 7-A:XkK鏨Ú?¼sÇ ¡±áòåü¾"&"„¥Âòu"nd¿(/ŒdH_ˆDrÑÛÛÍÿF\A~Ó½Hmsp¿^<7ë“3N°.ÍÐÂHD�¤dð¤SŽÖS~íļ ‹RoÉÁ-ƒ¤y‡“—›8Û`Ÿh“™Tl «K÷8’••Çï%IcÜ‘jxáÉæ$¬êx(¦ eS0CbpѰT'‚áew1ûº¿ÙGà�½‰ RÝÝ5Qî&a¢H$ ¿ÙÉBãU¦Vþüõܑ앧áœÇ®«�‡ÔSÃMvr�&鉾ÉÁE'á³±�9 ¯Iý–´mß·Zbƒêªo. „{jÛž\ôɾEŒ}è Ë�÷B<È"]•“õ)Á$Ú‹¹mÓ>2§ÍߥÈ̃¿YÑ7ßGŒÆgb/ÚÕãÄð~G°&–#ÉËG]v¦ s œ æ~À>”Pl„t… ÊŠ3ÒžE.ˆ-�ÎÉÁ÷û\øŠfü Ø‹7 tÐÁù_½µé¥@jY=;Ì�”ëú. pJå*u®¤åb2œÌ{Yk»™rχûö×VèÍvôŸQè u—èͪô+_lÖe9 èÚTáïìk)j— º¦ázü‰i«õro!a4¸SuDš¶?\ ¹8VXš¶®Ë±p‚rI-)˜~c!¦úg æò¹‘¬þÛéœÏÑ.ÁßAdØž¨ÓiÖQ›¦ŽU>ƒÒ>»ÀÅË(¢„ òu·OÿA@~Œ¡{°K¨Wöº½«U2Å+xLÓ™ež¯Æ}7Œ [É™2ÛË9ÛÓl¥ÜS�¤Èm91û�›%ÒŽZþ¦Š”½üæøJWݘÂd0¶S&q¥›CÊÒ‡»ALÀÛöC<^~ÞT—–™'²7õ^ v9l:õ±žð' R_À¼L‡S7¡ƒFü�MMá*"ƛγ3÷–¬~Ã*’š[þa£îlaú ôÚœJÒú&Q²„haÖkvâ‘UåbÚ„LÆÚyæZ.B¸Ñfò½÷WŽš‘ßD.0k[ZݦS �ìcToÒ†-·‚Dd¸6“ÙÆ—Á¡ŠÂ®ÀÃò=³-èXÁAZÞTZñ¼@ÄÊfÉ?,¹VÐÇJu޾¤ö÷�̸ Ò¦vÆÅW¥‹@(æK)á¶h-YBk»‰s¬“BL²žU°†’QaŽW ;Á­ƒ^˜áj*œSÚPóA�Þò­ãšrªFÀqu§• " '¤?¢Àçø¦¤ä)‹ò‡jßÏz#D³ðpëÌCJOÁ[~ÆJQV– |q…ÜÎ]´ô…‘Á6ï4—U†ÖÊSÀ¡úà^{ÖUÃ3cùüŠšõî\´×U~{%a>Hç nóáÊfõnDM‘M›3¸¥€¯Ï¨Œ¢R_Œlya3-ý2S5Šé–>äËåt[x•†¸ñJÝ7•œ|&hª½ ;ËzçYZm¥§ün‚Ä䃹ÑS»¸MÅ‚šMÛz ®|�õ.›ÓñBBÔ)HN+;¬š”Ъþøª·\äij5`Ü⯳äC 6\)*{;C´*HVÒÚÀÊ©ê˜ÏµeOPÞ¤iy˜¸G„‘ ¹@y)ã ×*… w q¹ ̤)þd¹¨áë�þÁ<·¾w'jÑ4oÆÅeš½#Rç»_õÚè“õÞøÈ'ßPeæ£�,lìì<¥¦”.g8šãý¥ßë¨Üˆ ¿ÿÇ‘Ô$`פôŠ€G£*þcŠøéVÖˆ3]{¨ª sg"�TTF%fbOfä—ÅèlH \brRпŸ)&ã#àÙÑ'>…H˜ÂO…`3KJ@ªí†ÁR�ûUó_Y2}ÿê}ûJ ?H�uh˜ðîšMT°»H-Ïc~—zœÿï«£¯ñ„6ŒS `F ¿‘GîºÙø=EöË[¥|JcTx-_ÇQ�Ÿ%”gP¯®<] }géÖ|é›å»ïºãÊÿŠ›”kGa¤Ïƒ '[=ñw4ŸÜÛÿ\»&VðL248ˆ¼´åqéÿ¶Iðô1–…Í€\Óóèg®X7’î_ø]¼‹k¼™Ï€(ÿEÈÙcµ¢Ï�V1±¡£‡{™8¼›woʨƒKp�xª7�±ÿeS¬ÜþÑpÄáˆQ°æ&v¸!šc2}G�ó ÑèÚõRÕ~�-Æ�„jÃ�´ÍÔ${nRã•yµÓlVJm"l "Ô·¤Ÿ3ì5£Œ½í!@£™[ÀMøÉ ÿûn´ÖÜøm ÜÕ‘ídôü�G+¢œÛÁ‡'mœ^^ÀÒpú5Ù‰Ðu™y6ÃUx&.‡f‹F›~ …£i8ãw!k‹—�� éMW›‘çÀ?²¶�΀‹‡6�½¶ _,zÃÇVíÝ*�öl%‰‰`JO„ º´I¨.®^ëùÐzB¸¤¨¦!®A½Xÿ)ôF…¾‰BS" á1øâþñ¬>ÉÆ)[./¢có�~ÂÏãjµÎ~7ƒ/}èw«W|%mn¿œÆNΞû‘?�ÒLkÞF3™-ö,ýc ȧg4TµTº´}ª%rƒ^º(úS®ÑI¹>‚ŽXW0"¶•ü¹î&;W?|!q ßé ‘ÑŒ·¡Ä'¤�lR09S?ûo‘™‘ñp#üOI*£èð Í¢ü€kŸ}Ä�{îÉ@g‡û—t°ÔÒˆI,„Ã7’˜a3"KÌ!ÕäfV÷zv¨îaí#Š|“4`§î ØèÙhÙü—° ¸>ǸFé¡0 °KIb/¶v̸êÕútžä…Võ]“™žh ˆ)}ˈ ¦ÈÐZÌlû™wZáåŸo5Â^��¦Ž(5³D™pÕ�±¢0 Kžé_t|º&}0Gs]lÝþ³,Ø/ Î¶À‡`TZÀño ,‹ðsmPü�ŠØ)”ÁnòÜ&B�ýµIG�ªeH åE¥_”ã–ÜûZzíú�æìò%_&—Ch\9â�Ü^µÉ�¸¯zõ/û¸ƒ(È€ï$ú<´¯²º¤òžƒöÞ|µå|Œ3Î3P&ž:ÌR…og¨©µ„ȵ‰êr´lëë8d7סvRè·cü˜�\øilôp“ßd*�š™½Ÿ�Í)h>ôÏ·)XŒÒ÷Þ {\ÞÌ3â¢�Š$g¾]«‚¥^n¾Wñqâæé$ñMIâ¾­�uMV�›0 ðÖfßkž�hC›É£Úü>?ÿZÄ›¨ë�i 3d,· ÜX!«d Í~ô1iµBRm„ù¡õ]®Sôº1ìPÇì«]Ÿ³.þóóömoƒóJ`bø�aê’¾™d¤lŽ·f¹‡dgÍÐñfý3 íaNËq…Je\±£¯4bY�{)HðP-þ�Ô› •þõÙ>L﮼ >ûž-q]Ð5Î\KÄexoRÏÈó5ùf²Ñ(¯cÙ00!ûÉÀL�PcS!«µwÓxbs¶!ùú�×åÎ×)&JИ Ȱñì¥ì<±õ.kàƒUNyêˆØ5Ѥ�ÑD^Jˆ¾ÔüUÛ®br¹‚­»í•I×CYôU³NµãJ:Ò=$ñÚèÑ—EÒÃÍÒ×­ºƒ$ðàïÒø£\|C¬É(^„Ôp€<ù7°ónâ+dĘuT¶L¨Šb|¼ÇC…?Toé°vçFAW(a:¸AÿYý½¨èý½¦^¨É¶‹ËDÈq�â ÀÇ&DõŒòÅÃø/'Mۜͫš¡ýå¶ê— üÞðÓ�\X]4eOûX%¼r³�|”ÔÕZ„Šì™~SY”Ý‘+~&c ýa¢JáÆ!ž|0UãÃåûJL;-‹œ6÷”ñ®KX´ƒ4ÁQ™„ƒ®iűÔB8‰ɵu1û¹(ìl_Ê|?%b ÍSHe.îrº @¹LÓÝ ^Go^å:É?hRO¢=‹…£•¨˜ b«½45äŸ8WCÈÙÊVVl:zvƒxµ¨!ÕƒÃzK•)=%I·~eØïCµ™ü¬áâÕêuv~Ž¥�ÑQŸåDJOýÿ‘JKÞù…Ÿªû¦Z$U§7Ù!‚éÝ}"®e‡^<‚Üýз*:iõíK¡ýnEÈ„ >ŒnÏ]ù´:ûXY{0v^k/Z@ |¶p=#ŽÿŽu¨æF\ñ,¥X…w�僲ÞׇTB©‘i.Ðä:j—r0À=¤ÉµÄôÄ[%(\'ÕÛ�EѰ¦ð&�*“]\æ¡Ó‘,)nÉê šâA†ªNt¾Õ Ð;€¢œ¿pTg…Ⱥ¼©‡�P`máíGYDl©Y¾0Ž�¡æœ+Z –‚Fo³?b¨g€æ¾Aâ§;¦æ6¨x� êçªJ/Ø5ŸòN´šù°ît‡8ŒA¯;'oW„HÓÎŽR,…‡åêJy>[-¥û=ÈŒòN­Ã˜šÚÿc§¬åÈåPF, ÉrÐj{M¦±l8Ǧ/·‹yâå5�^C \OÕ÷{†ÿ[DËB6¤êš`RlÅ Nä¡#‡ÙV<¥ñ¦%W]óÞ•8~å¿È; dQ¼é¶ºN,'N½7„"·ûÉ%=ý·ß"×ZÁ`ÀWÅWå[±¬ÄoC e"kÄ*û4qê»hu±¶¾()ùªxÊ|?¢¹h¹Í«ï-hðÕ™/··€(~S²È{ {FØ+âÉ_*tÙ^ú”rD#Ù'@ˆ!òMh‚¨ˆEïÁ:_…?`ScS"àjÒ��‘K¿b�Þ¯»WA²…«ÈèÚL5ÊèèÿüêÜN!ˆåm~Æ/”p*ŽÇ·ÜÔI1»Šg¨uøó��͇±ÇçUà ³Ô%6@kHR€CûÚ4[-Ÿ/ŠQ7ç §Nï«o¼¢ìü âù~w.A<Ú_ZãS¾jÆNkòA³š=yTð0ä.ÙêHò¨M£jÅú•®¹Q͹@² ÅjN‡#¾ši$Q»8•Ô}¿Î^�lFÇ`þÑ,NÖxèë|w[^‘ËØYäÔl `i²ïo~;~Û¦hl+èƒH]ßp�® œîë—mX=èÆ„Už¢Qѧ“ÔEÿÏôê7¡á—aù/€¶Â-59Bâ2™ØÑ>›°†ztñÉ[—Jè]– ñßìºò!Z HÈgŠ\£å4ƒ5d$…Úʺ>êˆ/øÁ¦‡¼9ý?39í@û‡ƒÄwM>7ñ@ˆF´ MÅtª^¥èÒÀ¨R94E¬z|×°yQhL_ÛPb«N1) ]{Éö BVF]†ø85þÍ%†lÆ"ßR!äórÜÕeQ�&Oy½@®¯1+N—»ô¤SÌÔ~ Y™^@:ý$é<`j 4Ï*—ú¦n÷„…Žn¤‚~â*S­aôÑ.Béø }ð|xÃ)p�íŽú¥"œ¸vû¯ªÍ_$m[رÅÅKà’Î?;¨w,…ƒõ„›Ìî^Á-FçtÔ,9æøwÇû�ô½ß:€>p†5a·‹‹®²úØNg„ZɰÝÌw+ß“ØÃèÈ;D žºk§Ûo2–Á�Lu)Úw±}øô©`·/ø×Ò8ÙÄ'† O¹Ž¬Ü+þ²-×{@äŸô_]ŠR©¯ä-tÊ�…« U‡ˆÇq‹"~^‚ê%Áo& $³ç]�– €þ�O�¥|œyêÁDБ€0�î´4"+³ãƒÔØW¶î¨ñ¿'‚m C}…«ûzÐíþTIÕŽ�Ðîøáo“Ò¤«Íˆ) „?䜥Àè3ÄÀ>´½�3wÅÖ!��u¯Ã–†j'Y¯Ÿ÷»QpéoŒLðl?ʽ¥%!X æ‹xÄ Ý¬¥­ÞôE¨‰R½�ÆÃ<ÞÖb„ÓÇ9 ínPé)âù"!‡€¤¤Måõ¾—5Óü°3¹ÏÝ6ÜÃæi‹ö,hǪAâ& .l ÂPÂ:™2ÈôÂóö^¹/ôpùÒî4-ÙWTbÚ•(²dåÓwǸï`€Çá ?ñW/óÿÅÜ�:æÚz¦{Ò^&( ¿}Êì§$¯9tð–tW ?èRK/PI~i•è½ù°„éke³Sø.„HrüU¯Ã¥”ç}·92»«Ñ&;ÿ#j­QÛùÆ~SckÆ»6ÎÔ,·)�#aNýô†*<¢fß¡FŽ�™„Ãèf®ï|ÏMS™qž£ÿPÕþÔ´ nù̬l2Ã"êÄ៦ƒb0£³ª¨YvÞ£÷©škkÌ™7–ÏÒÅyv’q0nÛz;ùR¨7q·Ôñ¶ñÍ�a’§§ˆµÆ" û Öy;}f—ÁÖyßr5"‹pÐ�,ûí¿½%›ñ9Ñà§[;ŒˆbÈ +)ï—·³±¸XlgØ>ÅR"Cmœ›-#wø³ü�ð<ë +^äŒn|ýµYˆ*Ò3?�*ÛE“VÙnÄss}õdfþ+Æw#)Ü-‡XD>èO¶�üñÃo=ý¾°U%¹³ÝÉNæ\ï�ÇðÁ‰}Ù_y¦¤eHø*5ÜÔUNFÔ*Õ3fÀ„EÔ:ccr^§,?’‰F#î¾É�›€y$Ž­×±oKøa—†©äO�ûîí]Cæú,z¯€�êr«Y“ª¸¨’C‚ÿøÊ uã=SIÅ©:núæ lc¾ìnXk›¹{SçÆZÜìŒ,g(@r6Ïf«˜Wíˆsº)I ¤Ÿ ”ZŽx —aD‡®vñ¢¨x§….v5èy‚iX3òf^Ì5õj$Ã,’ ›šBZS¾Î–å©È  ݂龧Ó\|^·2òy ¡<�ž Ój�ωáü�B ’å¬7â\ÒX}` …½è‡µVÊ¿#j@š)v55(zKç•ôÆÒä§úšÖ}ÿíDkÀ)Fm¢X®Ý õÉoU¤LB6¬mV�'Ž©‰ÝMÚ´î´|T™‚ƒ×KÈfæU�Šã8j3h…í<# NÐUø;ëˆpÎîª&›Z»÷Üb{ª]×@´#ÉFXúó‰^S¢M®n8xô6$ûßDaQÈϹ‰\QD�–õÅkÞMn ø³véÅ'%zkõfÅð&±Å9ÐБ ‹løiB+1S÷I÷Ê„¨)ñÆÀt g½E½C½Eû8$-î¹�䀞yîȧ“raÂQOK³èã9*z ß�°ù�yØêÙýÝ-\Í��u~k¹¶‚á¨ÿÞðên»OK Ú§�×9õ^.ìO…¤ q*$ˆ•¬Jx€ˆ@’–gš1 Å} ÓR™!���ÅØ¦qYØ.q49lvÐ|B™[ü“,õl"�ÌS¦|Ï�ÉN[YP+é¤_ÒTX©þiÍ!¢¿ø43[;güHïúþ­�@ãºpÉ(o¹PWÒ§zÙa‘¢ DÄG§]§u >í9‹Ô‹†Zª°S(pC‹*ž¶'aªYÌ¢ÃzÇ2ÐH*ŸŸ ¦*ýx3½lïæÕPöX‘uöðp­»s �DïBÈÁ~ ŸïšÞq®dO�}ë2¯h¥;)fJ]žóùpRÔ¯ì+u-‘„cÝDÚù"1»èXnÛÁWrç˜äâǬÉ^ekÕe„qj½ Xu¹9š,g+Ït~üCÔZoÓáÐG“·Ÿ±ÀçÈò­œTŒ eª!@4™nã/Ѩ£y÷‰v¢6)—M({£~œ%ˆ¸|Æ?Ql§ì¹ÁUŒUÈsOåjÊ=3ÐßU%ÿËë.ÒSƒ««âQ׊æðÓGᆉ\¾W�±zmŸav¬ÊVËq¸GoðOo/³/»•!]À‘x4_‹9+3îž\±pÅ•p¾ŽAë˲ôpÐèW¹ þñ–½ø9κƒï<åb ¥/BL9ŽacåÍ·Ãñö‘ˆj>_ ?%´mg8¾qZÿ‹ÿÜ7èŽí�©î‚YÿD—NèÒ±*—»3ƒ¦ %Må’¾:&°à� âxWg2¾Qxôp€a›ÓóVeÛ¦ØD…€d츬�.õÓ–ãA*ì¶PÉ®³%öÏ@�Ó…Ìùì?ž€®ájÍ’oÒ²ô#”\±ƒykÃu½Æ;9^MÚ\¢fŸûÞ^†‚X·F `�0mü"›„åS|9ï‹D"õ�±)ÕÝo8—åÌßBÊt™S&©bHU Ó8©0œWÒ€°F_L4×þÉf ñ¼ë¸"ÙQnn¦mæ¡*K-µù»£vL«‡.´8ô…ˆ‹N]ÓFS7e&Tá”L/-we~�b‚¨IfWªù˜‹@â?Ô'3OÀbñ¢XøÈûÈK4MwG¸W{RÏã&°?Ñ¥©Sé(NM^6Œ´4´å]ï˜ I•JuÛpðʉŒ0|·o{ôt}D\#_ÉÑ3cïäg SEº]2·•|0çúœlF#B+—ѹŽmÏY�]‰Ò¶¾P·ª0`q1ëçV3N»òĪb¢Ò|oé—ÔEK矷x!ÅÑò±˜þÍóõ¸NÀeö�NüP!ê¹Ù-– Ý^ ±ýàiÏVÙVß œõrDâeÀø5äš©=t“íH0p!#ªAj;…)P ¦Ì 5\?úå?ÍF=¶;qô‚ü§ÕÂ!£|¶ï;$õ±J"¾ktìXÛÜÙkÞâÙžWÀíí`ê0.Kå-ZÓNªÁÉím\¢Ü 1iìö™×�áÚÅŠŽ~CQñöÕl8¯1·ÁÙQ ä_Q½O3]êm#蟦„äÚ R ï¤fÒÖqÕìTõ�Ò€sLYëñ…²òù¤BˆNŸPû׬œ·H‘&�\½.è@t¹l—yÔ#Ú¡ç§]Nì†ÀTÕ!³óä±úöL”"©p&�¾ oßQÝìínœ·"pw9n'?ž?·yýÏ×0(š˜¶˜Ž-³²½Õ¬±o~wŽ,Aë²P}€ð{³@â†ï¼�åŸ@b²0Ϫf�8A@Ó} G»«&�\'ØäšK–Ý[ük�°rª~xŒl›o—OòZ9:Q¬ø‡iÈè‘DM'�­Æ9M€‚þæßý[k5L.6ŽHËú�RÝ`¤Û>ú”BãGSDK°¡½ž)˜±âÕm�£ï—ª¿ÑjÑE l+Ë1û¹Îg{yƒÞn'p«L³‘Ãpÿ’®Ã¿·èã‰üSòìiXw}ÝCZ�wAT2ö,‘œÁC»Ë=–åÚ Ãp ÃGÊnDÊÌ"=ÿ’ˆ Aæ�Ú„Á/Ä&dXÌP}ÒÁºGš<-áÑëÕº4ZFH�w:ÄßÚg±ÖVÆ›[HpUƒä°ä˜Bˆ²®Ù©«”æxCµ¹%«Šl`"¦ÄŒCÓúw³#ih(b½á9¬;æÅ`@˜¼6�Š1v|(½FÏÈ3ĺkjø�5Ô®ýHÝoK•¤ÚÍ»F9B`\þ©cLî«ð.¡²lÜѳœÖ´Sò­*¸?û]¦JlÏ|0Ø«¿CmnW”D•ÈíTƒÅ/¿á¦5 _ý܆lcŠü�Ù'»ÁHÔþð'¨úV´=k,7¸HÂw¦k®_\N‚†cýù­ˆd@QfˆŒ#Nóù5 PÕË zÎù˜HµšÜ”[öyWQ1 "WÝ÷ŒdH3%`±'X{u!lïÖÚæS…·¯ `C‹’®®D©ölGÆžîáYÃ\ Íä©T: š0´-. ×vI¢ Ÿ|W¤©Ö@2ˆ4¦KW‹‹NPR°ŸWpÍ©ËHÓ©6¨”Ãj¶É!T黯ö¶á–Õ�P•çOU})JÜ ì.ïüë�\×ÀjÇ‚ä�–Ñ€ ¶+Ú8Ý�¤è;0=•1©d2˜ ©µçíþgæQ“�]zì«|µhȶÞÂ-o)áSâ*¦ �|`(P f-b#×óS7 ·�Æ� �ĽȾ[¼ü×ô~øãâ0áñM纳EhÌoïéK–xÌz©íîø·'y ¸8® w×Ò¬â¨s�éÜ�ÓâLŒÅîeM‘t:¯§@|‰š;Y¿sPtÁÀˆ!qÚî‰âYýM0]�ìÞ§è6‹ªV“0—Ê8®vß3K²äpI»ÿÈ1Rúo5/ÎãyžDX âÔÈ—=Ÿ¥çòµ­Ú]æ-•�¯IÑáP¤Ôu¨T7Ôµ)@°Q–ÿm<öº6Άþ+¢ô�û±ûq”e;8†{€¿føðœU$ëYåSSº¼†K®´A%ˆÄò~*=ˆ.Š À‘×5t±Z˜'Ù�ÿÅä^Ÿ2è×#äÁð>VEŒ"ï™§íκzê~^ÃÀÎ<#™Pô^+^‰ëï’ä4¶}ÑÓ‰�ÂéÉ1šFE´%hìóªÖÈ—ìz ÐTÌ@ô†‘f3Ò�ÝJ§?4iþú }%S0Ë£aë{Ã}«Bë�Yv„ -"Y‡Ôùžï+cSæ5k°�⤭Cg_$$üÆg5¼K« ^O=ާ£,†°\Þ×À/& Ù罬`Jy¯á>òé]¡ñ{éí£*bù �5ýn»WÊ\œïú'ãí7ru¿ÿ¬Ý~”*…¤à«Ã3AÙsàë¸Ð[‰ñSlµ Ï.v¼¸V® ª£ïÇu%¶‚ð4úòZf؃��{Í#8œî‰«ðômgÕ–PTøtìNø9oߊ‰7n¡488c9qÈ tnë¡vЯzŽB­^b&ç'ƒ"a|.>J•¤#›æÈÿø|D¶ì±“gû­Ë »jÛ­Œ=]»ÓHþ‰b~hØ�o“\µ{XÊí7uÉ\õ.ªÝ« Ž FyLŽ;W‚–áðÆnLø7}þD¥i–O S¶b3‘z<ä[?ü™ò‘ÅÉ9öa§ïd#©æžztÉ+ˆÀ´`Lú¥$ÃݵÜÓ=)Z/ïU»0¤9Áa«ªÔØÏ³„(T4åBÙºWJ¦Ûƒ–ʪ±jëm81¨U0:5`ªQؙӭHV§Dy�ˆi&ƒ5µ®Ñ�†<"™¬)€7K’qz§9€Ü ™J/J$/Óç�ž<èð<>örøÑ±ì�í�Û·»ŸÎå+A2ˆA+L·gVVºS’× ì¥7×Ñ{½ë;¸Z“käø�¿(ÕU£,Ø�BUÖÊUªUÂÜ÷…Ï^ÍH Bï‰uÅIø3e("]ãe¢ø0²sy�>J ònÏâK]ÍÈdK�mŠž 6Y/Þ—ÜÂÊÊŠR™7D§à{, %âîElrs®M ÚÏädŠ(ý-�y!ÿ¦AÖƒX™N \ï²m@µ$Ž9ž×ËBDÂÌciýå1^À¼9˜úžQ¼2þ�Ö»vXJ.ćJHЇ8ŽZaµ›»¶»�’£iN Õ|ͺÛèàÝ[¾õ-‘7ÓTb0³ÑÎÙÐÖ‘PÊK3gEÁûó#.†žŠ un_rÿ/nUžh.âWìþñY�€ýž+\ê_B�þø�÷«Æ—ð˜£Ù"N”Þ7� sžJf­ÒE‡ÅÎçBPò|‘¥¸ÖyÙ9§�HÇ9Ô­ÜY¾³^!$‘d¢ªÇ|êüÙ$«¯Ê¿›ÒÜ“DÔPPk™ˆ0¾TÃ<÷–Kéjc1_`ÜÕ·hñóÆ/9Ÿõ?7›•�’'¤tMLlÿ›ÿÍD¦üž|FÆ™÷×{¶î‚9L@ÀÚIp²P�¼ôWMø/àòC¾™N‘˜g²ç¦DâÅ›¦T)¨vøŽ<žˆÉéõ£ê^6# ?d¯0›ÇŽsÊjYñµ÷= iÇiðýz5õ}€9‘–Ë» øŠsºs÷ù¿IH—/¶æqd¯;ç…}Ó-9j®W%_gÏ·Ûs.�búË~q;AûÂèwÉ#á0Öþp{ò•ÆV”7­Îs2ñÞäNüã7¢Tð Õ¸=¢ölgóyô&�“÷µP±¯ã3˜ñÏ‚²@d–0ÒÓKõ�·r§€Æ,ôÇÚ‰<þ9‚Ž ŠÃ"OŠ3 ’ “Ú ’ó+Éj Ö!$­zž�mk;Ol„å¾/·Áè¶�Ê<½s ˧e¹F9ªë2ÆðŒÊÒ¯ &É?˜¤ö¯¡mVk0y¥T [³kz‘J�¶‘ðÔ6` 8uµðé‡A!<Ä÷ð¶§äõÞÁ`¿�ß¡0|Å)SÓ0‹äñ¿Ï¨ïsäχF’v¹mÌvB!½OBP�Ô÷ˆ!6§¼ûÝ,n†oLüÐC± STÇ´G,ªVƒäeÁ�¹›¿[ÝI4 ט~¦'þ\_n¿~WÄÄCöûuTʼ¨˜G9K A¿ •¾Žžé"ùŽDu‚´npÁ�:÷øG. Hmª6í^Çq»ó±hq3x5Ü ÁjaïqÏòhKqÅ}è�ùDÄs{×� ×JQç66 ªòé}Ð/¯ã˪¸,nA©R*¬‰âô�ìÕ~£\í¢·8ñg¶£áÆ‚Ê%`p…g�‰ ÈÙ×3œ�3Û4Y(_,ïgòØV>�3 œf´Ï¼»)S¯i ®Ö9\ãÞÇM33]V�‘h2ï7oŸO³…”üç” ,Ê䜖‹ºýûñA‚Ýl›f*Q¿£9óD¦Â%†F}ÐAùAÄ3><‰Ïrð =ä™m¦mÕõkFñÉËj—Ëá+p‡ö#Ývá,!�C‡ÎÑ],EfuÛÚ Õ YTá© ¬ª(+«nªn€žX_±±3oÝUê–ÔBç†TÀÀ~6�:ž08¾â›õ›�ßÎÝ@—�Ε�GºëG�°„ “CòK!¸YŒãúªD遼àK‹Ø{ŠbM©Ñ§Y2gC€ºâ7rðDí1¢¡©¾—öÆw 6ud”BKsû»ÅÙXqËS,?&{õŽW�µQžäû÷£—Ç®ì@ íMºï�ZžH€ÆŽÅŸ¼äúXÁV†;…÷ e«Þ�ä(¢ØR«ÁÂÜ1—A¥)B7IUze; ËiGš¬PŽõž¸˜�³î}‰H¼‚Îm¼jœ~ñŠy†¯6d§nÖ�&‹f¾t�aKa°LuC£u(Üî—Ú˜Ì-–abäëã7ñwñVsõal†ígÚò}ª3cÛýꑼ¾ÃÕÉ”ÖIôl{³�¥v<8C?Ë’Ñä ô½wÄ•l=ø×—MqËž‹C®r*?´ôw´…Ä9¯L-Í~ìCÂ8�C…:3Ã×Jêà§›‚´š×Ò Ä�cŸÉñmEp}ÆG�ˆYJð™06ܨ^Ó˜B9ßiÄY–ŒxŽ€|ÃÈâJøœV÷B à~\ë²oÔŒY»³„-}œh¢¦ºUiíoÃÛ±NÁÐzN!ærñIÒdÉEP|ôóE¯Á/¸yXŽ¢a£¦�lmZeNÓ�Øõ:ÀÞnÿ‹¼3TÝACªXתtpã4¤@'áõŽk’ŒÀÞãóhÀmµV¼W-Ü*oZQÖc¯ði£1‘h›wd¡62—áûÙF!áUÝñ’gôäb­Z{@G˜Ôsa«CwjètŸíÌñ)h*œíù°-ïâÿ±�‹Y´Ö�ídÒí›öuÈŒ'Åfž{©«0ÂÒ½’ᘕdBde*‚«¹Ý(O..”ŸNÄÅû`Â`?ŸçR£$Ö)Áôzl†}•“‹Ž«OƒÞ.9øcv·~NÌCŒ'¹2ô3cÌ QÈñ+¯³}ÙQÄä]G ^:ÛÛ>(”mÇñÿÜù£r0œª¾JT«—w›¥y›…eßÌÃ7Z\…OÅw$-«Ôºœ±^VZBÌ.‡š­‘Uª‘´EìM³¶•i‘  `�¯°7ùÈ ¿õÎÝÝ /É@‚º õ·×s”mlå©éPxéNL—…°§®8^©^ð .Eæé]÷[{:‹æv,Úf*i¤–@ "Uò:ÖI¸ø1Iý×z~åþ7Ÿ„}]„Ø|î3Ϲ“¬KÜGØ~(bœ=y¹]f΂z…ý—�FŒéšy¢‚á¢E öl|'1ðÙ ó“&æ=qyé,°ú*öñ5 ½Pó]±)µ´Z"6¿¸ü<# y.gH¨á,!{O›]›`H Ê-ã–Ýà0‚Px'�£¢N_üAÃGdHú«–Ù.èj¼ã»9ðMU�M ¼*ù¸á<ƒ�¦JÖè�Ý»±�hY \þš–´§žå;¾Òÿ¨í°³i«Í€â¿�¬6:-¤ô�gûüô˜€%Ó?.� ¤:ÂàÎÓ<ª¯YÃìÕU™¨Š—Ô÷­h 8OÝ é¿9‹Ø|›¹a{J¥PÕÄÁJO€Beõ/µf¶<ôâhä‰vfÉÏ3ô´øù¨b‘½¿ÜÔ'¿ìxÚ–øŽ’ó/Ý@1T[™Ø´õG7Z¯lÂl@Í›Ô<}­àÜ¡5Ýå_,:ø?ˆöÞbV Ù÷-ô^u;ÕŸÓ)i´–åköôÞU™š„~sD2Duà��çŽÏê'” bécéÖdIûB’ð7¿6B*äË�‰© !$¶A êÜlXJåïóˆ¿ÂfR²Ê²±¹»©m‹ ·F£;ê*“ìpŠ [ç¡2TrÎÑEÑUeÄ•n„èÞq¸<\Ÿ»'ânÜ´8¨j’g•jƒüàÞ8­³Œ1H…®âcýƒ!‘òÄÆ{Y*ç~Kœ >SÖI™fD2xH¿½¡6JC'W@Cí‰Ç ß5¢ 0ïS¦æÇ4� ¶¥‰U @5aBY3%½wG¢¼fìà´öΪ¸¸7€!²èßÇúª¿¼ªÜ­©iÉŸà"êÉ�íÈÒÉD¹×’À2ž—\•^0K›¸®©[dþõC“=¢y)¼vá–ã/Rêº-ß=}n“~ú›…´ë,¹ Ò,n¾9¦h«†D ŸV¿Ï•/¤~|·1iëeO ïj×[¶±pƒÖ„úd™¸ÈŠbs£·Fe'DˆW“ï8†Íi(ð&´`Ã95aâ0yÏJ¥™Ì—;£â­µDÞ#Ë‹@w–Þâ°Ãë.þŸŸÝ¾61‘èæ}0wŽq¯Ï g¨ ž–Ùç=›ÎŠ]`ø±•ú¡Ñàáú‘§Õ²@Æ£çhá ‹'Ce6H @)o�ÿ¨èGCàÜÎ7*¹Ì£ïä^ ¬¬º_TÝ•}:ûË]º´Þ—”·ø“�i·‡úO-â1t»‡77©¶µöú›ÚP`‹WòÜþ¢+ý”L™ü¯ÊÛ&•öOn’õF< Ê ¼îqš$‰ä®vM³¤í=”>I]Çq†˜Û£eeÆQþ;ˆe{‹¸k/Hr±ñµ@D¥ZeöD vN&V€R% jsVƒÒö\õŽ4G0pª7º,ûûŽ- ξ-¼rQÿ¬Æ}<¦TÆGà¿FÆ1)JtÑø$’­pSä‡gÙY/U·(}¡éø›ª�;Q>ž5­á8M¦O/Zç7Žýi‡M¾PܰÖôFNñT¥ÃÜ’öAì±-,¼Â�¼G Q´cõ’C褉2$±n1í^«»ÒŒM’“ñ .ÄØúޤX”G®LÖsÑ a 1Vß­Eb~š¿Üxx/²ºxÈUO3/‚Û+ðz6…IK`CÌÀ;S“õgè L“šüÜÔÛ·ÿY® é/$R)¤ è$>Œ„f@™1ù£0¥1çbÿêŒ_1gÛ}lí{%ó¬µ$"˜°_£}ÒqNKµßTê¯Æqçvõú¿;\¦ï„ÉÆ=Ž #Ý`y»>æIÒôâÒD0_%CÎA2ÒG‘mÕ.­ø*í yÛ¿n)Ü&5×»¾Ž§“ŠïÕ—3aÐH XÅ’¿®«B×>sÀàÜn?sYÀ®íÒ]êyCP;]'j±`gÒGCRkü©:-~lyÂþÿ÷ôãà¡×»¢x”ð:¸�áÞªP'”9ë^ßÀÔŠÑoƒPeÅ7ÉóT&ÚœƒtÊk sU™ œýŠ[%8m4œqÌONÎÆÇ]!G5Oa k•ªÐË" ï¾bh7`½µ˜UàkË6÷¢å\ùþ\&Èáòä&JKŠs¬ÇÉ4#ãfMÅŠüAÊV“›È?i_3‡:=1p³"+Õ5”ÝÕbp:© ¨ª§Sý$ã%8sç ÌÁâ×keÏ{¦ÐOÖØûi#mnEyΟSø >=�¥7]16âÆ*ÒæÕ¾_HÜUñ%»•udÜé¸]«b?1ÎrÚÜØ8›ëï^ÍøšÇíËëxe:úã™üº7Ú1_ÏÞ‰ÜÞ8nü}Á�ohŸ �Ò³l µ7ÛŽhI–}ó˜‘dòxÈqK{2o¼j�–éS¾¡³–óÊ‘åœúϚ·w”$¸FµçÞeug'Ï—Œ«Š‹´•ÞÑB\D™óe)ä }¾>l'7¾²E²Ûõ.5N‡R:£–i�f |Í}·YI0¬ÞP]@µe Ù›xä(Ú[Ó¹_ä‘Vh´ü¢5›ü!â’Åqp?I†™íªX%2~ág£¡u@¿ª}4ËtdÚ¬ÿŸa™HQôìÎÅé;eŒÏIË‹û„��RÚ£@°p£Û¤/ÔU;Q#ÚÀ¢Püâ€Éµa/]­ŸWz³`Û†]2¹º‰FÔÕ‹Y½ Øcé„?_¢d5»&jê}©¯‚×9 Û­’%æúf§_F‰'~:�þÃ×äÝeF¦Íˆ(ÍïxÖ{gYY™z¶B§V«%²AÛè&€ÎNÜ•C¥Ý×/ÅæU^ÆmÕii+˜ÏwÌnb°^;Ÿa\J†X+‡,˜ÞÔþ6Ú®¹œZø›UC£ŽÁ5åÁYTJ3-Ý�Å]¤,¹�Mo`k -ùª<—pÄßFó°ùºý2>6Ê»Ÿ@]F†LVßeœQKëµ½MŠ6ĔْylÁŸ}ÌPõ�È[ÕËøÈýËÛÈ?%¬A+ƒnŸ *iùæI�Á•O=óª‰ÎÐΑ£TÓÄæÄoƒí>l…ž][PÒîªâãzOI@ W•¡óá’€�E 3è5¡F[qS†0µ1º¬²áßàÌjÞÖJöh(Ûºµ@î¾>eIñAEC’ð¶±ús™ï4daµÐ�èC8ÚŸ7PeÊ„2u¯¢=²°¥Ï¢O-†„ VŸÑZTaÓ&-´ÿ³*·¥§Ô÷“ ‘gçÇÓ5}ðŠ›¢‚ ÉÍ}ÙìT£ËÇŒÂ(G ·=ìüôàœÅHÎ\4#2Æ_XÖ&jÇe.îE\IÑö±AÒQN ÌKœ¥ŸÉÀ‘¸®[ðºX?ö2ˆ×›QÅ苬~(´�[¿Ã§7 é]€ L]¹”cŒÐ"¦;­V„-­~ßau^?KM?d<áÔ© ù)A) ´vÈ­­=ôžV-‘Ì�W&×µ³ £‹lL‹×o«+Ç»ã�¨¨I Dq«i‘ó>›ÏV(:Qvï Ö¨ àU#÷ÿíåÁZ¿“v54Ý’±6z!Á� m㫌ݥÛÜÊÝHÚ»›8Ó—WXÚi椈_Û¬±N=Þ4ü¤gŸí˜Ûàæ~ñŠv¿†¬:…BÙe69¥q³ôž o?dü©�}ãŒeŸqÇ>µDmîÓL/ä]š*&-ÿ‘a‘'o ïÙ­¶;�%ø„iÓÆ9ŒÈ3 ”Ò¹«¡ÁÓ-’ÄȈÿ:€ËÜlª½DòØœ®q«>mj † ;™ÊO §k‡Æ,º?ä£Ü˜¨÷ÇgQ7�Ý®xÃì¼mõ€¶ˆµî´-Ön¶µ¤Ûã¢ã€ãUøÉm�ç0ƒÐ�<š´Z„YSuxØ7éÈ«Æìañ|@?B:ˆï,Çéc“| '~Ä1p×Zв)�4åœ šÜ,¼WÔ'•[ÚÒ—Ÿ9òꟚ¦ò.ŒØÊ¯ýVè¨Åòž]ØqCx»3æ“¡m?1Ä…÷¹‡Ñ渹±í®ŠvÁu5¬jä·¹£;fÚ(V&ïâæ@Û‰k•Ã{—›ã #ðç’x™•ž0ZûƒWÅ{š‰l}SËÚ|‚Ìý=âªHýÎSb˜©_rùZ:†3AЋ¬=má-8!ýzåÜ Øç 9Ýåö¿ÝK�zÀ�pü"Ò ²I–C…ò¯Qú1 îŠŸÃæ–éÏw؟ñ�å¸éD˜:<‘�& ÕkÔ8c":ðø oî,Ÿî}¢&ýK (Q� êÆBx‚é;z.íâY$ ú8j¾É:Á­‡S_Ùâ1ÛñI.+PÇŒR»Œ×Æõ°c±c´v‘¼�X€µÍŠj/ø}ä ­ëN¼7–9ûzb²1ÊÜZ¶M~±»Á3*|©sTRºµi^™ÁÃ3&*5ª¤‘ô@'ºzÆ8ökom z½eÞ}áœ�^ŒÕõVW §‚¹­ý(×Ue ÔO8#ß9+×�¢AvÞšk8:ª†Kb—Ë…5Íóœ9vØþ�KŒC˶žüü°½Øíy/*꾄R¾o'—T0ÚÖÜÿÓõ+2½Tn?ãï�ÏT‚zj21x–í…‡£KÅäÿ’û©!; ÁðΩĉkeé·r†°ëw<��1ÿÄÆ™Íû¬Â]&ü''×L g[˜Ú‘zê¦@rˆz¹BË€.Ü!"�Ë~`$õݧ¬ûaøæ­xÍ8Êö3•ÕoŒ ‚IìïÜY¡Fé^¯ÝØ4YÊË’èíV’È!±Äø‹%–Ï&ß©â<Ë4cl‚A[5 8¶B� L°¿/¦ÂØ„F'/žÙ/Y%Ð'ÙhøZ59ªã_¿gè÷£~4¾T>33îÍðcÕÏÓyQ’2*9$¿Œ$ðHáëO!ÝX-¨å‰›Ž@ûž¯P¥|n¨¸¹UÁžâlÉKGÙûLh…¿ 꽑n�ÕÜÚS‘¤|9³S„Ë@“„(DŠC€«×1i£-EJaœw'±˜ã&\þ;/YÒGÄ— Ëdçíý{·9 ",…nz䎇Èì44„µÇe çFƒ©ÊÔ2sy»»Œ;Î?Ûfäq4H)R-v‘8¬q}eב‡´Ü¨æ’çIRõ›t½-úµ¦v¯¶)·÷¸,ß&!N¯_z¾K²›ªßâ”X¯ k=ÿZrCë0{ƒ}”R &¡c8[ w­ VõUµñ p©êé2±2I+¸]j4pœ(ú¿ï¸WZô\C_gÆêÏE –*Lm‹YÙö®I˜.ùPÌ·ê€ “�·¨Äñ³O¯HuŠàx„¸LK÷�ä€òµûŠv¤wù”>"Ì,}S…e7«+IOÿÓã/­³hhPz¨û«ºFý=i×¼ÌL­¤_繃ú± Ì!„˜V ®2ñÁFŸ»=“‘©>>v©žro¢¢à<ƒm_Òã\ó=Ú£\bWQ–27”ĵ6²Ú€Ì¯¹»†Eé2:þꤠÝ5If%šUöûÆjï?7¢Jôñâ&‡÷HÇC=…0«]-áç—çfì ‹¿É¶6î]’Üeoª‹s›²àDçËçMÀ®QSà±',é©›ƒ±¯:¬¬‡è HçÕ½•OõËò’}-âWsÀþĬ0À«›eR­Ik} ±…š Ÿ"-Ÿ dÞ)h0ÕÄÏŽòñ…ÕšŽ†ÄÇåóì$*(ÓhÎØ#ŸîýŸèÙ“⬈‡1ÉÎÚ™¸œíA”ß­5ÑØkM…¶”-xoaóXÂÁ�\å¾–%H¼C‹ÜUd�c8³q®·‹�d#Õn(4Y´Ie =iWkèžÍ"V¾Ðßï_>[Øl¿6ËŒh@9¦?jAxz{'!cäQ©ÇÿøÊ `DŠbx¨‹†¼™Ôý‡»OM½Âsë=ߥõR?÷“ºäàÂyÙÖOÓy^©¡Z²í³Ý…|}¾k`¹48T,œ€a ,$-Km&ÒÃBc8@ÁÏà—î,†çþl6›? tÆM¿ªYx«°û‡ÚÆ'”uÿZödÈ5ªd.IJÒbsRõ_Œ!”(\\²@U¹KÆ(¥“Mq‰Ô"±›ÉkÖ„9_‘©³91FšñÚÙ£­mĉ-yê(ÜÝ�Ют?XHµ4<m© ;ðkü˳Þ0Ë{°1¸ö÷XÍ)’ìYŽáPqw4²™?<=-�$Ä‹,ÙGXEÉwÉÑœ,cl;:„Š€n!Ðw—'å<|…KðG$@I%>-¿å’§,Ã…&á›C “ôçK1à6]ô js’�gÞD4¼±»ÓK4ÿúèS›0…gÚjéN¥� 6åcÃ#˜�ÊÜœÁ{8S÷ýœÞ?¼Ö.—DƒèÎ<-ë†9!·½“lË|o(8iœBWÈöפ§ m˜tšù7ë4ßÈ^£¥“ïÈ6(ÞÚ×Âùm�w@DÂɆr”‘t)(uÑ‚f¿j¹z�Ô÷Á1ŠW’]‹~ Ž÷`%ÂdQ$C¬Ãé¥U"ù›o¢&ÂÜK2;ðg#¦ fÖ¢Û(‘µ Ù²ýŸÜcÁÇ">¬¹b�­îVaM"ÑTœíÐ:’ô =…ktЦ$f V¾ù4R,!F3j©n èÿ”]Ž98Dr‡wne…å|µ7¨À5ý1ëxI¥¸Žò�~õ£â'©þY¦ƒöý;ÐHu)›5‹±©‡ßs\yåÇn4>©ú«fàÇu! ik&A41žàÚ„“aÝø]�-9„ÆuÕ_›T ©2åQXà½Ùlt`�)fØgü5 ÃÈ]ºã*µ{úEþ8Õ›Ù�b¹Éì›á[¾{â OW·»4¬GuSÚö´ù'MPÙUj™RV65‘Šm‹v†}—‘è'noY¯Ê§÷‡©q©/!ÑeCÃ�‰½¨€Êú ´)+íJ�eÜ~¢ ,µ‘ CÎí­z_® IEê¨í§È²ïìŸ`ˆýú×%ò_üfçˆýáݶï"qêøsÕ×›£">)¼¤Ýçà®9¾©ˆŠ°žáx«iì�¦Ýíã~'G0Q_ã¹[éó^4Ûì—Ô¼¿¯×—h¬qÏ|Ò±áhHBŸk•DÌ$Š,2Þ~ˆÊæŠù›'Iæ§>•)åñ©¯z2¸tÉîm%qpI–ɵÐÛ ¹”b#CjÓÏCîPq7ÎÔ<~R´Mƒú9^ Ù0wŒw ½:öa€ÆÓßTG@6¡ËNÐmû#’vg¾ä�Þ`³d��‘ØUË>½š î \ÐDd_�{¨e¡œ¬¹Ù�j^HKbËGÆ(ÁÿRË¡8<Ò%¼5˜êÝîÍ|¼´¸•q�ÑŸè?±‰›—<-ß0ÇÅ›-ßL¼†WˆŠªÇ²œ©5Úìu¡ÚQC9dÒÑ?¨�»ð�ôLI"— 5A³'¿ýïÊnÊ/}—;¯‚Â$,È‚U‰aÖÁçò ‡F¶ªD <‡P-`ð†ÚìNȃç?DÔ¡þ]OoØê5sû³øe#»Â=Ò%«/ý“%ŽfÄQfM¤¸|+ÿ31ÉâÇwÜŒX÷®À/з®yKµ(MqH§Q‰Ó¼ã;¾(¬òüÓýEZO„EY8SÝЄªæøñJ8j–Bm†”¤9ËÆ»™â#Îr€Ðî1éâ ëÄäòáh�Gò¨€.ò&Éê÷)�‡[šØ“e޽¾qyó’×ô>[Ž ¬mÚ ¬9¼ZC®Ãkóþ¾Ðl¡[ïÞ‹²ðzýùÂŒö´—œùï S»/ªZ¥„Xèo×€SeÁêcd|v~)q“$�+¥gqa ñk,zp=*»­{ìnUY’â fÇá©BÅàHªÍk=@as'/–ážÎ EûáE-彈Á×h%®†È3ѼÅ\õÝ‘ ¾òéPQ›´ÿŽïãÍ&áð¦÷Íx–ò7�ÀLš§˜”gÊ)-¼ò[J›Îê­�Ú%³ì§¹~ìp²…}�Z'à£ÇèÑͬ¥û •Ó½©�·ÐPW‘Ž�¯U‹;¶ ‘“€�ïÊ»|�ëÞ ¢ýë±IME‡(çß7ú;þÖ¾I‡[3¯—™J:R$tÑS¶ ñ$ˆG�þGI¿è×ýËÃç'O ‘ÿ@ãÈä Û�J(/ùV�óë*P°~ûF†7@D#“7Óqc8÷в>Ü¥ñ*k×�Ä»P­ÍýÈ7%§Z«Ç»Á-�zó,ÃØ"²²šaéÈucÕá ë`k¹…ü,õË:VþY¹»V§9<Øæ7÷1VŠ~&M¢,Õ&åmŠc§#T nN«îB©bá`ÉȱÈ÷mƒ2¶Š»–£}|�È%Ö(×W 5-‡Ý㪉×Áœ«/n@ÍÅÛ‡ Æ;}P(qÖ“ì|(i_™°'�ÚÓš£§úÝRˆ¨-fÉ[Þijñhd(\¡½ÖÚ&ÎÉ’Cí_¦x3ßH8aÑâŒÏ)½ËÚPh&"ó÷…‰ío"ÒÚPd¢y­Þ·x̽¨GÐ#â$©»D|‹Rè�¯X û2ð¯ÌN{ßDx‹àŠDrgj¦ô-áy|»uHê)#4l¿Î_™%¿å¼ÞíìZeošÐ° Æ÷Œîå .”KšÙ}ÙžßZæ5(í’®¶ÿ+@¨ªC0õv¢ZÎÊßQX,ÜNôµÂ¾ŽWšd’Wo«?Áïk1!ˆ�Ô(¿Ê�W5·÷‹§ÃZ�˜bàP´Nô¬•Æ}’1©LÔÎé+Ïž”þŠ‚´üŸ‹ t-t®e›SŒÌ´uáî&. ÉýWP´îÌ}XQ¶+4T~ÜíZÀ_W�æM†±�ô«¡IÕ˜ò#нžÈHåÍå�…:Jl 72þk¦ÅÇ$È{2²Ýá\  ßIf‚�ˆ-ûÃÂÿ42\4ÚoÉÜ"l.š´3Ö’´míµ-ä;œ0®�o]>”Vëè‡ 2¹dñá-©oïµ½ó–WùÉwËjBXºµÓLIr6ÏÏІ¾wÄ�vª°„gâUíº€¬ºÀRiûU¦¾Ïóá¢K»#�eúÉ`šÃY޽ål—GûÁªÉ3ÿáï›3oeaÇÍUÄô ÈD™�ÛÓ¥ÚÊàê4ÉŽ�–OÜÝœh6Ì̪,*K®·�Á-Y½‚á%LóO�ª–@?©™fè­Ãw8– ,T¤»¦†,ÔØk?iE%Amáô5xóíb€ý‡�€ë:*ä�GyCy"¯ÀÀåÅÍSÐcS¥ÌõÙÇg®ý� Ï ¿‰tÀeW5ch¿´|U8A½Î »ý4CaŸ$kô¯Q_é ëúN‰{ÒilÇG$*üóﱯBòÀ:¥W_ch^ÜÄB󸪴&U䪌%T‡²ø�7>„oáÝ~Zĸ�…Ãs:8>O­ágà cÿÝ~7¶­'ü~Ÿi|�M0�žÀ¡”ÈXÛâOúé.Ã’ú8rQ‰ô¾C�]ä…Ë%Œùl~f¶wÇ€“õ�É?¤ÎA^dñq•P {YX’cܸC©Uz WÔð»6HgÞ—9PHHs' raíÜš9¥Bw2¨øóôßh©ÇäÀAbéäÕ 1ʽæžã'š¼Éâë'E±¨» _-ÒÚ°¾R²ú-Ëb$¨6j%jéPq'ÀÙy+1à& /âù| ]Yö"ë•+#]«ç¿6K.öÐ�P—\²·À;Œ¦ÖÑÑo@sßb²ž6ÂÀhíU{½•u® oÌ%¢Yíº68>/ gìÔ©|Ê^zE—ý0,‹–¹a!_ÓO{¬Ñ²õG%§ú�ó7î ÿ¹_#ù5º²DhŠV q&»zœØ€úß|<Ü\6¢…:"fMÆÈé´þ•Åd:[ �%×IŸFI­¥UïK�|ÃÓßTÕ::qyJ–üdkˆ9·IBúZ²°ï[ v:)1øïõr�ÝøvìNÚrx¹2~øŸÂä6H¸ö“1â™mÔ{&;¸mn(]ý ²} Â¥yâœoâ)±’öKÉxÞ[æøE™”Š ËÿŠà¥èI"ƒ@l#àé¬^¾=Ëj¸k13¤>ÉòˆgîóE ¡,«:f8Þ͘±½n� ÑEy¥žÛ×G*ŸÜR) Ç(Ž~[›5ì1Çzc…-æÌn�Üf¸ùç4˜É‹;± ¤Ÿ¢ÿº§Ý�¢†Û=[%ûŒcö*Ók‡;ñÚë�á �âª0>ËÇ<0q&‡‰ñ“WˆË‡Wúf ÿ�¹³Ûþ •ŽS£ dÅZÍt’gbõå¨þ _è£Ã¼ã4_ÎËd÷2ÁF²( .ã,r_ÃdÝqÊ£¹BØMÓZ@2“¤Öƒ¾Ä8j It‰k"+Sö1ÔLÒL[z.ïÌ)£ª^ž±aC§Ã¶t2.¨‰\„r14V•ò0�r8$ÿÞ<9ÄpY–f?½`£I\–~‚ü†BR�°%ŸâîÇv®åg‹J´£,òó<x)¤œè¼´ ¦7£ÄÊ›$�,§0 óù¢ä1=hkÑô•eaþaǃ'ÆqgŽò<Úø@w¤`A“[3²×#mûl‚åWC´GFG�ëvÙ¾8'žJ(ÍSIþÎǧ‘]Sæ(Ë Z\^gªºX­eÝ%ü0^1ÞŽ¤gÙ”¹‚é4½•%¡‚lÉÂü›ïJú® nøK‹‡ øw½ÈvÂGy1õ_Dï›\„�„¤O&TP(nµæâ:·ÿèœ�aÅŠ�>½Qß9ò| ë$ŽTú¼Žr¥±í£˜Ž3¤¼ã<È�eÎ�ñ›ßšE÷:lÜ ®°²§”ÔW „þ–pýæ75yh{íÑÆÑ�ßþÞ_7x64¿¨èqoPȯõl€‡ØæCษ¯‡áAdÿÁYèBtXK©_|z³dÍ_‹eRš"<„^öÁ.gÚP“¸ÖѪ‘7Ôƒ ¯<æX¾³ªŠ>Èfûæ("§g™úKÊ†ÛžÇ Ý1È¡Vt¨°Ú–ê/ì<Ü¥`í£ÔÌúº«C|ã¿þ§ê­Á@œ­Ú|{ä)’¢»eöÒN-þ­¼î�®H…²Fî*Ü�/€´P]ãmMˆ% E‡Ÿ[·T#�ÓŠ4r5›…ÀzœÛ7æ6š½SèëE3¹J•å·øu‚h\çæq´“@OqAƶ�–eÍ3×AˆÙW„ô…l›_˯ˆ(F‹ãÃfVM[ø m á…YKÓk¨6¨}i°9^lM°qˆm ´VÃï Øôªû‘C{ÙÁG<ï&bMz5tk(`·Ñ×Ù²ø5^ç‡�XY¨\6¹b\Æá—ú:`“Œn[!,n=Ìi/Ë�ê=´,g ÚZÖ¿ÕwrqúÄ·+=Ÿ“á1BÈѪ”>ÇNg¾Ç'÷�æ÷MõÀ^³)ßñÆa ‰r“jâaæiZJù°ëÍ4aü^S´Cä®`¿úƒ•öm¯“º¢ÚgÜ8OBY»¨Ð誦AztQ'C:¨²Å<ÞDŒ‰&<›ñ¼ÎvÈ™ÎÕ/&Ó°ºnÝ*"Ìêxî!ŒÔ”�ª07æ¼hÅŒù\í@Úc»€‹z¹5:hlRnfc©´ƒˆlLÕ¢ròdìÎb ê‚Ûž ¨Þæ<Häå(¿ƒ#Í%þxN‰9Ñù/#sÀž!’Þ÷Þõ¦Â!íâË~â‹„;bÏ×?\“(|Ñð¿pme’|ç´·~h�vß‹÷vm¦Wm ’h^ÓDàÕÅñvtÖž`\2rËb—WÅÿ'¬ »:5¡Uf¿+£9÷!{ë»�²ÊÏg8Òi[ï¶8t­Œu·e^,ùeºÈ›ë’1ìoسáÕÂ9ÛëÀŸw/]®ùRyA¯¬¹ ePSW¯°­d¤¹¼kÒôCo|1~<䬤¡b�pÅšÑÚE�û.*ÆÚ’]ºˆ>F}¯ „ú V?I9.úEóêÂ9[ÒÕm‘ƒ|å\ zå¶æÄR0©~�è#ÕZßÈ>w 4³Á´!+Üí·ôfÙ£)–.¤Û÷ fx/K—–+eÌæÊÈÖzÔ/CW�€_”óŠjÑÆZe¤X:v‰6"ô”·úv_e1,Ùùâ÷è…}ª–MRºQ”ãè)‹/Á}óI#$ÍŒ¥O�[Ì…Êdk|¯}ÕV ÎyÒQႾcPã*Ñ·Öÿ?ñ…øz¦âû”º`lr¶‚Ÿá÷‘—jLà^¹Ü”ï¡ïzÀB{ÄäGâ+:ý¬¯�‡ñM¿ù V�!ã¼3Ì×Ó5Ðõ%Þ4Ä‹°µ<4—ÛÝw£!þ”Њ\€ó­Zþ}Šÿ2x±'¸f²éAh*1Ǩ ˜h‰ÃŽÜ+iYŠÁ;{Óm“ó°cƒŸïòtžgêwg/u«Œ¦«>n‚d)"°#Žèqu±ªjr?ÁM=€/çö-ÓÛÇȸE |ÚõŒÞF»è!×*Ìö¢« ™ÍHPd»Ìí•ÕSêåE5tάÎ-zû~Ã0YMÒáó©6 £û¤Î¬ñ ÔX'Å¢Ù{o¡Îj0¹çO~ß�å™b�Ê‚RKò¢:ØÍ𸥘_í{Èé I›ü¾£O¯<x´ÕK†Jݵä0I\ɰŽyàØ~Š$ï@BîzQþö7µ”ÖÙŠg$àœ,!©Æó+]¼$ˆœ,�[«o¦H>[� ž Pׄ'3ñtff諺˜ròd†Zê·J,�rh@Ìpå0†O§KR0ŒrÔÆ;Sí7~R´6|Ç4¦« ]õIt@s÷Э*ègÃ`dž¬@åIvŸSâ'Hh�0¶3ÃxsÁÛÅåu‚i­„±&g© ½’Žuq5g44_ɱ`%&ûy5A^#\8;=íÔÓ°ö'ŒJç§!Çoò˜YuŠ“üR•‹¹+kZpçtÕ•ÜÛ�¼m,\-4ïû›7;ѤCöÚ£Ó"ó£Æf‹¯2í 6*kyÿõe×äûé‰j2¾»W€4³îEæ+ïÎj[W°c 3;ˆåSÛ«ƒý=)ã;ªF#9I`¤¢�¹ûÕ#—úR?æs>ñkübÛTŒ�¢«Uÿn²¯2Ô1‰f1hSôÑ|Þ¤biü�?,"NÄq²ä¡ÿN<Üî€\y›Ÿûå⃱o£ÔQÉB¹>¸žeØ{½<ÒÚÖû84�…ÙOpÛ£É�-4© ˜?£v+Ô½äöÒ!¿cQcñ =É�µÑ1‘¦� 4ï)ÊÃ=Ñ«¢÷Âó wãØ¦¥Áé�´(;”Aêr$"K‰º!h¹±Ò§súkcu­ŽvKDV¦'^Nh$.�&Õ æ7x÷ˆFú7æª*Ñ-g–f ¨Ð~ÓjZêϪ&ìeœt%9¾»G¥j—}K8×ï(jÆU<À‰®p¤Ãí¼©A—²P®p Ž òþoÕ%†'Èe›Ó„š:Ñæј¾%¤ƒB=,ô’x“ «~x¡K @߸Ö%`c#-sÌõLÂ(�K(\Þœé¡÷É�au¶üÂø> n¯æ} „ŽI†Ð7B;¶Ö ¶æ3KIþ¯(àŠ#•ƒå¹œýÕ{ƒÍ|'ÒŒOävrB8Ô>Ѽ�)¬l–½yri}=Êú.â±óиçW> õç²I/ÛQÞ, uéǃf¥-°H… uÿ»;¶N›V( ݆I¼E¾*8(W|@Ç=íºÕýW@Ìå›Î‘H§ø�ÇÍ]8(QåÄã²yùÎ/UÝN¬¢9Ô,‡E0“Úå6¥·½IÎ0 ÏTœ’�K¥ÐXèXxök–Eñ¼„Nƒ÷×87a?£{ﳇ˜ËÀ¹±Ü®!á./C¡Y†^†[oNŒwÚËr‡Î-—M¼/ÑS*¥/Þ†9˜§OIÄÝ;lL¬‡zÎ5 ƒ®Ó°”$í“8»“†A}N†þD®…jˆ°n;Þ�ùtáßñŽz6§äg­-ÓD�×¢ZøóÙ„6åH$"«Íãm¤uc•lC œG[iÞp7øKOöÔT+“>ú�y”K™‚ë(@ÈÝ/§®"'YRì†Îwp9Ä…�žHìRøê‰û҃Ӿ屸XÉ’JÆüŸ~ºP}žÎ\^ªW£¼Ì-‚�?A–}À½Õr^j@¾�Vsy�gãJ¼xráxƒ~ ÐthRìÇ1ýcÁ¾M—�òe£AÝÅ0Äïî lÆiÿ¸†íQwˆÅ ÅŽX-Ù9Еܺž îžý))�´ŽñÅ2¸¦kɰ mtíZZ0¢ˆŒ£BµÉmû³Tùîp9i!ñ£3[DâczJy¶Xc±O÷5Õ#J ÿZ%rÚb0„úXé#Ü$G‘2«~ÜøWW{ ΄Сæm³¼tç|ǺSvލ,uMa„EŒìb¿�½‘5ê”]^ÄÇ÷¦+:/çâNƒÆxç^•©<ò]e©""» îGë6ôp9÷^'‰u¼à¯s½r½¯ýJ˜oš°Åò%¾‘i©ô3«%£¹Ñžù‘t±UêÅrOl×ê®ZçÍ…n’6`‚sabLÛES'® —½2wøá½TV9CbÎ!Ù¦â a'¦¿[ö•² Z”3·“½Õ"êÖçÆÌ\íÆ)S’Üà]Žó­š­‘n�®¡ÛérꬹX( t+Ò)´'ª¶Þ†„wðÊhA÷v»vÛwd–üU��öèbô'¶.*Å׈ž 7� C¹ÒL 5õ(nSîÅß¾¿9F¿÷vêO=40|þ–’?L_Å�ùö-Ðø ‰ÀB Ä¢ù1#|ë¸×ÛÄ oªkKX qŸèeØ@Û=¬ÀÄp'ü6øš)º7ïß O#¬Ø™‘†k·×o­”çIË|›¯E¬ç˜Ì„{ùýéãô¹²ÑÓ³¿ Zí8rÖà–ÔjÖðÂKÅ�THòu{b’ðFQ�[÷J²€üM0ój•Ë>%Ž2x@÷Ó`q¨íwlõ­gÜÙ¼<§ç¥âû¢×)ÉrSïØà£Ò¨à�X¾ø´®A„UK?Ç6(üŽÛ?—cˆÆ'^%êÇ,F½ù` bEò¼èÞˆø2Êׄyº¬¶Kº=óö¬¨ÛDrvèlè^­;cË婦¹ ê�À|›/¬gKLü,º žøð̽?…% L~ìhŠ/ÞF„WôŸÎ}$ªà-…Ã?¶Øä! 15¸uå—¦‡,ü�ÜcCŠù.r}üªøwÂ~Àx'ÜчÆE“A‚4‘ðA_Ãþ[m°ñâ�Ö(cÌü'݃þ$­ŽFÄ ×à\˜(÷*è°Q]à¢_øêõÑ~X0‚(‡YÂÊðJ…2š\<¦dQ�œHÎJvíœF+YÍiîÏ�ñ.q[ÏÌY íyó•O›˜æòà DÊÑB~®« ù+¯¨ÛyAý~à¨"‰bCì¥JºY sUD ³_°¢�_:½þ¿ˆ÷œã¥ÿGhÃÈ.k ¹åœÙÕŠÜ&¼£)ÆÂžBA¹í"J(“Vmëiæ¨++>"+—ˆ¯kîP’çZ•ß®ô¶à6³h¢éäåú?•Í,é%„ÖZkÇ1„KÉÃꙬ1ºž‰”Ϧ:$\ùK(ç hÑm¼j’ˆ˜»AÛôó…uŠP™È-‰¿wŠá€5òBqþoà�æ4^'@I6k û©8çr5©*àµé0 ç rúnn²]ˆÍØ—®Ì2V)'Ñô…Kz*ÛØ ^ÂŽv‡ÛÌ»ÆÉ�ÌÜøh‘ÒéSΜŽd"·ä¤gÌæ©ª£¸·Â¼×¾Z©óMñŸý pÂ�ÊŸŠWèjT¤ìã ¹�¤ÞŒ/¦wDe5z¨ˆˆkw@y‹Ì@YgèèʪYßü¤Õ/ tÕN)¥çÍZ“Ì©¸4aóN7àØ<3RÑàF0¢ÍíO^p7æ¹Ëm]åJœ îšHßZÌHåd›�T,wl¦_ño'nh6­6ìé3ŠâD„fwž˜b+T¾mÒ%¦%‡¯Jtr�t…Áå“ÙáläE‰¦^œ²Ï¢ îÑõ{úkË´@˜ÿ¾C` ûc¹­ l ­‘ï¥7ø Ž¥ø% Ã9Ù�¶sr>¢áÒ#ʉÕ^� d$¬�âV-yµ.#.X$ Ï`oþ¥&�´öyc¬å‹]2OS[[<Ë÷MŽ:24}ö|æö?ãc,Ëý#A›X ¦©Û®H�y¿º«ÿך.ê‡?hùnìJ£&ã% h.[YÄ=‹Ç‹ÐÓv¼ÒgÊó—±\¼Žp-VÞ÷.Îyµ€¦î–YéfÌðKžñˆö!¡„2œ8“¨ýÆÏɼþÍZ䡽¾¬ F"šƒgxË«:ûþo DÝÆÖe9ÿ;‡ 0¶ ‰ž±oX×,¾9éäå@±êûÐÇõÓö>Ë—¤C=öo×ÇXUÇ[Ó)m%ãæš­��h h°¨/Æ+ÒL¹üÄ„±(jx(€„]a߯�d—ï.¸s]›¡Ÿ w@á2ÎO¼.'÷©6t?F=ìN9)Û1»³"˹�ŒK`²óEíšx™ë†ø˜MÉ|¥ Í«ôæðשá§0cãŠ9£ öÄ8sïÀú‚ð�µ$6™-b§%³C#dö.7y—^ºO ïI¯ÊAäþÉ 0[ „g†i Ť“À,ŒVbZ¹•ÿ•0zH¤°ÿ�#ŽdùÂHo…Á8š<�"ïç(&¬ŠÍxÑáŸL­°†Ez¢4œ•UÇXs'ru ‘LǤPÙõíB�\`ª=ëtæpû‹ G~ÑÏPD‚ŠC9ó{ĤçÒœ'Jã95†œŸYaD£~Ž=T•·}ŠØ¥{Åžû¹‡²ÜÖŒuwIÒP›1ù|&Â¥(Aÿþ¯ÐöcžëÎ^ÿn¢µºÿÐ>EFoº1¾ŒôyÆ  7ì¬B¢TiBðOdËÊÆ¶Rй«É³‹Ã’T:áÕì[6aå9~‡mPti‘ês8×k×e‰Usdí�ú2\'§ ¼V#=©4ï#ª#b†Pÿ6áÂïôðn¢šÄxÝïÁ 8ïð5¦ûG9‚£h3I]ÁV�ŽØÉS ÆR_ZEÁ…Œ½}�ÂNÔÏß�æl,Fyý2J�PeUÿ ©èrêϯ ìæŒûùç˜�žýUêÎ5Ãì½üŽÌùl�^@^ï«à¯ˆÁcâˆ<çOQq=ÙÝ×i†S}�:0–záÅMÖ$5J¿c�hWÕ!åtÂåuê£Tdø$ÏØô œ4þÇí ß™¾fÌa_£"(¬I…ÍNý»¥ð¬­&·½oäÂŽ3Ã|UÏ�~Š�Ózb]J¡¥²Õ±¢U¯ÿøÊ g©×sèYI¹®£ ë 9ëUžM=ë;ܲ*‚)ŧ—Ïp»ã¼ðOÒ©¶²c3¿ù®+Âp±¬�@ î¹°‰“EŽ«$)Q7”|[ ZŸÞ¢ãwóBYÒü*~ºû¿ÍwvadÛðRDý4¢ÜÌ©oIÀ íÑöÞ·\3QTÿºâ4ì:õ›t'?£Bðvªã—5l½ÄÛUôɯ�ï.ñ¨�B§|»°I ±zS¶¥oꃿê:X}±̦ñwŒLÇb ‘i¹ÌÕ•I¥„ÙÛ†Þî°Öe¸¤V s§6Èa•Ïp=ç¬~O bÊ¿Ç& ÇDÂÜ;–UŠ\LÌ| �€Ã·#JÆhGÌç"üÙé °g&º�Ï)½±? Ùžu‰€ª¬‹`1CÑ;Xgk K9y*ns ·ƒ†GÁl7e±¡È@出YÅ© hð.§G>N)š…nûs)Ùgýa1Sý0(3cU¾g™©¼Ä|Œx8šðòñÂ'ªR�yò[æÚ"ÿ—œ?_Ÿt=‘bÜ�R%)uª"ÓDcܸۘD†øì0¯kð†÷QEƒé¢Ê· â©Ö¢%*•›í;]#4$KW‘øtçáœî”TõýŠ>¿âöd,ès� K=º–Sµð_sð:–÷1'‡˜ËüÏ Ìû?HG(œÂ‡×°÷Åí©i{ÉŠ5ÅÒñ®Aü´ä™¿¼a¸°q({N˜Hëà¦ëÕ€¯¢ƒèùÿo;mc}ŠÑl¤&ïÀ�â¿0ÕÇ_į¶ò~h—5íô}èê5vrº~A’cŒÁI¤·}®0¿Ÿs°;"ür)‡þ¯©|3@“W¶|üäl�oÑ%è±§$L¤¢à¹àqô• EÕ‡À›ôa5˜æ¿Þ„‹±2ÆU:ô�&ä“\IžCš?þSiߣŠâm¿ŒáGÈÉ5Éw>ìnjnó±0¹®/v…?‡h" J9qÿÓ’Þ9¶‚ܤ.u—ÄF©Ì/Žmκg—qßš!•ót 9n‡n‚^½öYL±Úÿ`Úxí9ž³ØBô˜ {ã!œcm¸.À-Ú�LÉÂÞÙ´÷îƒ:?hyábÂú£dÐ5}Wm@x@Y³Í+=ºÉl²òÂec']>py�ùD¥PYâAÓÓ“¬J�tªžÄ:º]‘†¡°–s,”b—�À•Û•=Cö#aUk,˜Bµ(Ý�ª»¼yž§ðO,[èë@=¶À Þ5õã4ËŸ�²xÕ|“œ Ÿ™x“Û¯£ø¹"â“ψ« 6ˆg ò~Éè  ¤$š]½5xÝ©ÙaK2À¯±•¦ä‹Ä��p€"Ø¥¶`­ÅP)ôÛ‘„H¨Áâ¹ìzÏnD;»w© ãÖv¬m�NDùEYDŸqFTŒ/E2õØ,o¾ ²óSRÞõ9ºëšor™‹Ì— ñ-´©ê¶òÂè|üiv®èÏ Æm–œ}jyL=Åèž®p¯ƒÏâ2ÛW üBP±FÞJ‘>ƒpÀŠ ôü�]ŠàF_>ÎISû¹ð‰ÎY$Å=f]4„î"ZQ[6ßO²–Ù�ëƒØ‘W©¡"- Î{*åR¯ò~‡×^’(6êß—Ê&-Ç�Ñ0Êúcùy·;�ˆ-CI‰æÔÑ�?±š†ÚbZNÆ€Öã³Öø4Þ)”�[‚Q´“²�üq¡äÇ}„ASL$É?*ƒ)j ÓøVQõÎwĘp`Â%gØ ½"?�ÒZœmÙò–¥ÃõÆ´‚t$� äT¹foÀ~î«z™V‡™á~,ï¢ÖÍæ«F½ŽÝ�¤Z„-'¬¼–Y>I¶È¢â·²0õ™”TXò åƒ’"« iÉ£o<¬Eòy‡­slø°ž«&*6s\ÿ BßdÉXŽšlË..M”å¿õCªL%'Ó¡[%Y«�t¬NXÁ¦õsÜky—✞–�!·Ài{‹J>÷«ÍvßÏRGjí`£²Âµ†¢ïùè¦ÛîˆShw,ÜKr›4Ç}•^`Hz«H¾èþ�®­øqS$2m�éJÓ”Ö&´Щ°@eúš`E}´;I™iWàƒøz„†ê,™"æZLR=zµD)ÙæŸ“KZ°XÇ{îý¾\ó™6ðE—ÊúR—§ ¦ÓÉŽÚ; ›Av8 )jÆõW�:æKØ’¦,¸a­“´Ónc†•…·º+‹‘Qùˆ7·çþ¼ßRÀ_‰vЍîÂÿëP<õSd³”`ËTsðܦ÷uù2ý3 WŠIç ®_ˆì·ÛÕûll§1׌—•?¥ÆíÁö¢ÕxÍÚ¼ ÑL“^ í nµ|K8ý„î9vAßL¨� ùPÐ…ÛÖó¿¸aê; ôÚ¶˜ +%�Œwé¸xš€xŪÁ?㫇ì¾Øj#ÖØ"y¾o*H‹ñ;SSˆß¢\8¸�@ß»rˆòE*Äð“wÐ^ ~Ÿ=%Ý’ÂÔŒqÑbf˜á§°s² ‡÷«zW'’Fg+\Î&ak¡ üô`CAH·2×à�eåsÄSšæÑnÑì˜ ÉzìÅ"•ßz55¦9ÀäCýAÿÆÚº9Hx®ßÝuPÏ¥‡¸©c/Ý)ÔÌt†à�yœ.$Þ ¦þº¡g.S0§Ñ7\Ýø¿@R\ïÊF}<í`PÆ'YÛcÒ0¾žø{fêg{-ËÊ,¿, ñ�o‘+”Zb ˜|ª1,ÔEºÎTÈ–# «ÄµœÂÜ?¹Ìy‹ ý²ÆmHÕ’ýRD꺎jÏûµµ ½‘Òˆ¸I\ÑK—±NòL9‹§r c;¢Ýc¿Õ.ˈ¯?$[ËuчõjZÙQøaE2ƒñë;Œ’Ù{RÚ„dîÞJ\õ·L¸#=†ruj°S0÷˜bÿxJýÿO)Ä ) ùi}™ }§zß^Pó¢ j¯‚ú«o&î´dýNÕ„3ø ìª^ƒÕi~þ¡aýÍ%×ñ[èc=ŸZŽE?E妥7çíà-ÙÑ„�_=�Í««A†ñâwx•î` %˜%Sà¹.ôþÄP¯¾çÅk¿ãìÍEÅ/ëþÃYYu´ Ï‹Üû²!9š–d^Î9Si«î(¯ÝnŽŒ3»:ݤšS³ÒîApõ{NmflÙû‡‰|Â!•¸WwIñ¯ßp!šo\�Ò7Ë<é‹’ÿ9¦YÚ¬¸F¸Ð:‚¾á9ƒY7ªÝ=þl½ðÁ‹½wæ,i|æÒO8îgAØ 4)нl>ãÆÍç'‘Ähƒ’8ãÅ!®ðÇrUf8͇/^÷@”«2Ë8ÊíÜŠ¨Ÿù×K¥a²ß@¦q왳.µ©vqýí(�½uiñ—¥7"à(Ì’iоy°×å¹”FX½=ßD µ °‰¬Ä2ÏìÄ€ Q»l ‹Æbû:ºÔ}‰¢h"ßE€h Q•ºÜÆGí!OòKãõæ9ø<8KÑÒ:ÉäíT»Vô‘¤–Õ¨}�¨Hè•*˜}fÍÃ…²„ÿ®Ð#G­‚ œoˆ—¹|бõ�(QUù* ѶB0©zC’µ�ßå*Õ¾éîROÛ÷†lÏ!%V°Mw OÑD[[o4ú’Y fo;)…¼b™¼¦4’0Ã"3?‚熂¶Üh4üRîZU’)aVXƒ¹ t¹ u4ÑÂn²lÃo�-ì½Õ§ Q~.R!‚n±Ê`8^6ó?óÆ@-HüÆ ‰Ë¬vúÃá�kž®ê¸cR`ª–«3aúÒÊ“ù\Š:¡¶Ä΀-¿ \ÆÞÝ©µŽÌGé|#úÄ–vÞìi4?Þ%œï̢ãV¬ˆµæô§•3›“Ý(Á† NÜX³<÷¼‘ñuÖé­;R°1y´Ä„’_ù8SÐǃ2ŒöelM�AõG»÷àŸYÄÌwT'?8Útqbê$ A¾26ÜÆX0ºQÃ�ÝK�¦Ô Ê0²®°/ÊäÏíØ…cü÷ûb\òòxûa†ûMKü^â/íð×­¶CB¢Èд˲ö~.ƒ�=—åMÆaÅÎÒ/†>8±1ˆcSÏœGéÿù÷ÐùHEogåg -¼X×=Epï„Kv`Bäur×­äѾýÃ�þ©séÛÊr�sêå*¸vqù¬Lðá$›Ë±3ìvé>ú˜Òïtœ £Œ»œr9�¨˜èO,’Pá�‘¤¹G‡ØÑmWb=ëþI_1«ÿ@ë�¼Ö(üKØTo¸ƒZ´j6ýÖ°ÐïŸÌ'šg=o̬-›½³uñ`7V™&z³Î:V3˜•°Ë' V{cuœ0€óGÌÅîÛ€ oþ fYï{@©‡>ÖÒƒŠª¹ä ´ ¿yœÌc‹ÈAYÅÏmK<Ì�ƒõWïoˆwZ3B×È)¹ÑÇcrR$?‘6œ1>Ç*í—Ž«…1ºÃI¬ÿÿä˜vpZß\HgZê¡£•&'™ì£Ï±¶5�reün°­’¢>Ó�z_#Ï=)»4 �¼Æw~z[É1ßjŠƒÏ豈èP]”¥®¬8’Ùº�I-²¢y£ìÚ:̱…^3Ö¦ÞV¯\ndœÈX8æÞR(-k‹óO°tr´i7§CàšŸ’ Eõ‹Z·|7›ÛEóúd«ÇW_l’n{o䬲© (aa›mµ|úp_î–â.V•&¸&L{jFKð“u¬Xç”̼[v¾£Pý'ó_ŸidwT¾.â)ž®4�ò÷aöc N›>ëêP·~Üg•€­î8Àº¥._ `¹dÙ¿•#µ }‰°½á™¢Ë+ª(J)'~]%[¿�ˆÒHû¨+AˆÞ²ï+vëËC�Ô¸aä—$x ]÷n#‡-›,¥²œ+�áKOcòɸtÍ•3çWʰ“ëM=Þ[žwìŒGÂWá·¶ª|eO,W~L‚Õæº8€¶‹`Z/=¢A¶bàYcǯûX$¡¨c6ÁµË¬[†I˜ÆÇœŒë3•øÏ§%ÞËI�]y;fãov³�õQq˾ӆ �‘µ€pç@©”„Ê–ëŽÜ 6øÿLsî�¦ø:¿= p?Íšs3·š1NIå@™o¼äq&•¶>rçæìÂ?ɣϞaNŸ¦ ü—;Ò6\5JuÛæ3y2ÃáàÕÑ2®Å¨ŒØì�i/>Û¹ìx³ç�Èp #=᩽¼�ÍÜ5 ’ý¼#*+&ÐùFGÚ ­âþœ°úwyC•áPä çòމ³¸¶ô69I®‚?Ì—Æ6±c�®O²:dúÖJýýûÐ~1ßýãæ¾4Êv‡ySŽF–3&ã}©±–ë­Ÿà—” רø±ÿŒc«¸p¡6JE°”¦¡Õæ`ØŸMÞdŒ=+X:Z$¨ã<ºŠ!º–å:Þ 2m¡cÖð¿¹Ü ��y«,ö(j*ÝÐ$È¡8zjþ÷úVz˜NX |mÑ< Â0Ñë57So‹�!ôçJøÊ£<~`ˆm\YPN‰ÖcŽüÑ¢Abun�g‘ò&2åØš—€{O4¬ø�/:½~¸Œéî^÷ÀÉ`¨Ž¢3\ß—ýßk½îzxÙü´ÈU�¢Ç ·®.,†ö¤±²AÕCA÷eJ™òXiÏ+ ¬¼±rä;üÂSl7ó¨ùF¬�8¨¿k”?Q(±üúr]`¬tÚj�]"Æö” ekÉü‰l�ÙÐÀNe¤²QŽ]yqB/›òþ(–ô¬1}e&·›�±ÑšèÞ|_€2°„„´à’¢äµYÀeo3 4š(ä‹Ï¿ß_EL†[D¥Ê,Õš¬µ ±ª>ÖKq£êö®oè8íhWeS?²F,�›S½oeÔpÍËç�Av¢¬�}�`ÿñûÎÆÉ‡ç“p}¬“=vJ»t\>7…Å¿¿;ít&OQcXÖ8¤’ï{èC¤*tÒÊÑmúÌ¿O‡7 ­°?l1XÛ 4VÒù='œ§ó÷€¸¼Oa<Š•°.îVÆ}ù=)OHà1½Ú´Ï•©_“5 DUó‰F·5$FH×} 3�Oº=nëä0ê|L*|Ê´zt­‰¿þßT28ƒÛ€DjGšÑóÿ7£³}Í`#Óq¥\B�Aã*LV"gnÍÇ^g]QÉýŸf£ÿ�Ÿ|.GÑ,‰óºyæ"vÑd„ çÃQ¼†«$EÁ\n7LY±ÉRThuïò}Ñ TQ×Vž«œÚ5AÙš^úN=HäPA(å;kô€¥Tk®9¶Ò=€ÜÝq§‡¶™8â—ÿõ¾ãíôÌÏìÎ@)ÛŸ/ÙŒùv9Ë@eÝž4hXš£‰-êF‹°§ÄQÓ˜yƒŽž'ÛÓ~à¶ÿ#[%:rƒ°[Ͻ!ßíVå¸8¨¡ ÌÙ¬ R€ èG0¾åÝó H1S(–¥bK1î- I‘¨ã™õod©‡!¦¬^ˆéöïÍ| õpÙØ ›ù(Š1Q·@™àÁâ!`Q…–{VYM\œs‚Þ(©@¬¯HSþ›˜þ‚ü}_BOFí^3øx2§Ìý&ëôÓ ;h•|ye�bƒ î8ñÛåï:¯Õc…b™0L+‡fZùüÈ¡¾Y~ÕWÜG¿ñE ݽ<³(—/2u4 $;“ h§Vü†üÛ LäÀÁƒ…�È(bú×B€bX­°4:¡ùúA×£áo× “; dÙSë(!bKRFÑ´[[§b«ºéæaŽ ­�—Ç«(ûïRu*«je'Üm+ŽH~°S]y?¸ÏãA÷¥lqWoz mÁ´–×�ÝXþh+â4¦ßŸ· ^£t@’+d›¯òˆ.¼†óĹ¹Nqäåýh@A�¬d÷à24ªWf¯»©>8±Ï3|Æß�´û5,�æF`€@|&ÍQS10ïÜÓŒœ»ÎX”Æ {·‡éÄÁM\ÝÍÌrhièŽA`·`ç aã#W±Ht>Hqµçë*Í­ç{Ì8q?´÷&:©Ÿ]jš¶&U²¿ ÛcÞݵ)³Š¿š¥�ÔÊVY•ëòti^] ˆAyãZ¾vK$4š°žáÒpl…6Z�Ý÷P·s£l$æôº“Êh�“Ùæ�‘Heã÷gVXyÊÇ„FæZ»L 8n¬|ö˜¼Eú¶.4‚>Ícùjÿ­—)�ÄN UÂ?)ŒÝÖ1½2—^°‚Ï|¿LÛ½6†.µØ˜Ò•Üb&ÿãm1gÒfñ» ›I-­ËbKè7I?HŸù¾gÏ€}IC¬»ÄÔL¶|Ì"ùôi/œÚ�kéùÕlõ}ÜÀÖ0‘-ïX¨=Í”í$&kZÉ{>•Kú(+±·ý8dË6l¬øO£bG‹’£“�Úæï ê2ÓŽ€Eù„·ámüPD¤u´âþæ¡‘{‚¶gM>eÉf¨Í\—ªIôŠíâ6ç~äÆzÈ=–”¿4&ƾ2—ÓÅ‚bŠ�h¶â…çß²�tÁ ç®4Ëßo´›&÷ôÍ_Ä3?m[üM ÝG’ît± cç¨kÉ^.ñAX2–ÏsÅ¥NTÈ¢c é*J,9pNEÕã$/ËvG—ÿz¦‰.ÚN§ð ðÛÐ{�åL˜t>{žg‹rQƵÝQT[ê1)ÄÈc¿¹E†ŠDË§ÑØ ËÁ],q\³k#ÍÈósD Û"•µN­'“'èÈ?v:$åDQºvUlÒ‰šhßÄT5{ªÂ›ð釗d*Y`]¢rçJ¿a-š:uò?êå{›6ÐξºQ$�-óeá@qþÞH^…•:wQô×ÐþžÆŸ¤ãˬÄ`2›ŒzÂÄJÕ%ë8WO:êoq� ‘ùNVwÁtÀê½ 8ã‚S•©îßÉ`ü½P/niÝì]˹Ù ™‘¯‡­Kì«ä,Eùøá¼g%u½oq¬õû¤{É‹—Vó:^Õ²3t*&€E`¨ºÅ³æpKl^Ÿ�›`_¾eaÀDòT[ü ’ê€�x舋I(Ú‰¹�׃Ÿ"€‰¦Y4Ú,ó3sþY5€âIpÝhÚ~êþ3±¾MÒŽýèué¹Úô¾]¼“Ýj;{:õÜ.»Q,ûÇ'Y¬HÕ¿ƒ‘‰ËîµÚç=æçý�ra¶ÀNÊÂØìËs ø$W/7ãCr•Ö«¬\’Ò]ƒìWŒåW-…l©„7ÅW>µûy.š%D„}‡$‰zÂwÓi•n暨BÅ0žbr}=¼ÀUšÅŠƒA&•{"ÔÐÕÇwy–k#ê¥Àó»Eí™ žµÆˆÉmNmÀfmmÍ #ÉÌ7;˺·±(§Bb„’ÎdžMâ^ŒÚ|Ãzo‰·¹ø&4üà‘M}¬ê,•¸€Å©‡k/¬DðO3ÿnCµyvZ'uþÅCÉ)Ñu6qÊ!�ú¸t ôl�ó¦„Ë•Õ ?ÃÈk�~€«ñš?šØP ë–¾SÑ–Íý‹Ûf3IÑÔ�3K&¼§«xF>Îú"Lþ„ë§`£çå@âÃíä;XÏnùCu!–BµÞÌR^ÏkÿžŽÂ{Ïï,lž ¬O�¯+µD»8¿ó“aÌ݈ I9Œ“gû§=»˜§Ð!þ²sárÂò®ç,`ß·¸~A4%ûÔ!¬b5€žƒ¼aÊPõ³ž³S5˜Ó�Õ=ÆÍëLù“ñ,ie¶:»"\k(õ)ç�£Ï²Sø2Ü�ÐÓÍuL‰ýÊ•yû+¸–G` TïÅPƒ“(ßk×{÷¦ìoÅ<ðý6xƒ[1²Ve–X@<µ)Š—´9ÿVV„Ö}ÅJx›uÀKh*�Fµí}1V}oGZîo#|7¨»‘`ÿ}ºÕpkFÚ…êöšzáß”zžx€Ã„)ÚXÌÓ©'�|A?Àºò$ \Õ@4±Ê̯ ô6z]¸Ëˆ’>W‘zÑákÜ6DÞv S@¡#-b1}3má÷³é`Xˬ8f™ï)¾Qa«÷B~›Æ|R· I 0Ëô=Ï&×?meë¤06Uª°óáÄÏ‘ eà*ßÁoxh~ i`6«Y—ðwzï‘ÚÁL12kÔ‡Š¯aÅ»I3�!¹äL”ªÁjFá±TÊà!Ó®uˆ2çåÊ«k0*úFÏ?Šäiy…ŒUæå5ÚëàW@ð° Uíð ;Q?ÀÔVB{#’QH,ZhØóÌZñ7•n]>Ð>@/ÂuÆ<F‹îSã즀 ÷–E6w-U¿)_©F!÷V¢¡ËÓlæ¿c|¼gŽKƒ>‘銖û±~ј‹ï 3®`– ìá÷h%¼þ4£ ÖgLšH¢ð•Ûp勉 Ú2¨íµ!De �°^pª‹×�½þ¿"ddÁãÊ|�{tc¢6Â{R1ãíÅØÔfE>‡©Þ°–•Ì@sò¬¬BÞBÅû²»’Kb5î#S+ÁºG™"J `cîB1Ê6qnð�î— ôiÔ<Vá© W%J_z®ŽûÊÌ˸ÁT)•[B“Ý®‰ Ü‹,$7¼ Âˆlí™§Ç.Òt™Ñíª€ÁtþpŽ–o—HBÿ  VÕFœ^Uöi_åùá9h½g†¸7íá�Õ+ãˆlíú)ï¿…D/ÒCì2¯nÝ×ÔÅ77ï­ß¤2�>“dz£�tdˆÔ™Ë¡MÇÏA3¹‡—âsb˜]¯BAA¿v>l»®ùÏšôW!Â6,²†gã>Ýn ”¥e|þ|'TÒ…¤x7i ㇟Uiå2Pñ˜ÓQqGrl…ÅÉ_­€÷Øœ�û§¥xX¦ÒÈÔ÷akd͘Ìz’µ¡·2Nü½tÆÒ‰Õ<-u«Y;¬?ŽÂX©ÍfÛÌ ±ÿ¨]íR52ëê…>tt57ÉÉDÊ…ÀAé!_ñ- r»LvxlÓÍFœuS«,M+w76¥g"€¡ùcH~Zcn_ ˜Ò^ûãöáqM5�{$P©ÜÓC+'Œè„zÂ<'„ýí‚Õ<†! ô/µ°ã¨}!Ô€*9œù ØBÜ·}�z¾lÄcïz¬¼nÍ.Ô|‡5§8  ü+| ¦™¾%dH…6š²Å^¡”ôq.=fà3ŠÉË Rß……jgdžÕoŽAO�:êxMœ} Þ�c�ÖZdÅGˆôLÙw^RçôrŠFÁHs̬ç"ˆÙˆü>]¢Lùc¯=Ä 3«;OK8T÷§µ^rz´Y½?Mx™‡®•I¡v¾HN©1ÛZ†BWžý>ÑŽA¦Ç®=î×’Û�ëg–²¯ÌšØXÚÂ[œ.Éc2!Ž@†9\©œädðU¼éJ«ˆôa8c¦½:l›«ü7Àž:¶Œ¸¯lÿã<ŸÉ�þvÊ5Cn™•\†úÕÕo]|T8¨AH&–øgyžB[:±RÕßO±:´ âÁ' ÅÂ¥¶ëCË äòÌÛn•�˜{ARj\È6¬Õºx–R­£‘;…CZªW/7ùëœ×B[_æ�n�¼”mšát8ù*“”qÛM®@ˆÏ?=�M�/\pe­GsÂàµ!ß±¡¹¹Tà†Zø0áH,Ë£[¡Â X.+ÿ-‡oª%Áþ7¨_i Ý=ܪ°�÷Ãü“*Ñæ6æ:×7šUwf¶b·} ;çx;.ÐAW|¸þÖ2^³5ŸÀ á⃼uÛÇ@)2®ŒÜuoÆ |5‡f¸÷?>xŠ(õ˜ÁÚî6cøÍm.žK {ZÃy',vù?z‘ O�h …?!¡Ÿ‚÷¢5P¬ƒN÷0t×w¹´`§Šc3yÆ5‘§ W Λ[®Òh|/.ðܹ4ªÚÊÃì“Ñ{[à9~ÓbB Jb D-TþÃZÊmY¸¨ášCêôË0C’õ'e÷ŽÇÃSY UHë�©�pG®Þõ÷±BWeþOØ¥§†ƒqQ·lcÔM:PÙj¬0Ä+«Öèœm2÷J+Ï«¼ßç¾^ý>Hæªôâ¾÷êUs`DQP[ú5`aoÉ�šKRцþ)E�&‘ˆåxÚ28ùÉN­úo5sÞd„ë‹_'WHgК¥ÜšŸQg ¸.ü9¹ÄLKM>çí¥Ù,5 NªÄ=¹ÊR1±ÇEO(A­bJ¥°A…2–y=ñ!·r ýèšàÚê‡Ué¶^53Y«N%éþüG¢AÛe1½}y¥y0J2$v’ªiƤåW£¼V%¶oèô?òÔ$^¢¦fÕp�Õ$¼­0´ßˆ›¾Å¤EÍ» OOEXÎG`ðîÛ³]ñqÞÙ@Sâ‡ý��K1ôØÝT“ÃnL|ƒ‚­s.R²õøÙ ý¬©×è‹n IŠ}_=>‘w)³_ÙAOý§�/äH² u©‚uÝj⟜†1¥ñŠ*×�$¶3¥sµ…K)æþlÓ€¤9*KMŸ“ѹÒ;&iê@8—Ê_9ó·|ÈYÐpÍò·|8{ê" ŽÏ›×Ò¢dÑL3a §Î²ŒŒ«¥Ê“§›/‹J„-7>¹¨ÝÜ[mÇ6‡2ÑÔ!ðHÉMÍ{XáŒSñ±'È|;¥±¡½·â¡»u:ͻ՘�IúW7‚FÊ ïTI~*ïì àÉ%4uÑÀž¹ ÙycUMî±³¨pÇ"LWé¡ކ:™äõ5Ü)¾YÝBèx 4ÿ×1ž]_ÓÔ¿"ø ¹{æÓ#¿ïã¨4ÙǾiÒ¬gX®åÉG]1zúŸÞN7 ª)×ë5Ÿ Âëoთѳéoà‚mpU'×À^Ö­¼¨ ©MW^\Pu5;;¹˜2tOò6ÃCùPÿ @·›4ji 7V:“T#% BÑx¬ÄŽ ¢±ÿO—ï)ôt:Yü%Æ7ê|’û#ô,j;ŸY2ÀJ¥šå­=&�t§… âKÞ¡ò ÅjÒRXØïtÕ¶æHQ~^ú'wIXü;‡PØof@‰ôÊ{û«„Ñ—&œ·‰ññ|×R!¨Kˆ¡6Ûd3oÙ3»BÒ‘Y†°‰º zO�ýD�´E‚lFsÁ×Rif‰s}ìÍ Ã&ªšš®ë8�AêÒ]ˆ¤ §B(7ö”ªn%Ý�®�ÑÖk¸C`¿îÙYg‰wB,$B[~ñðÿøÊ n$ƒ…£oMª{[Ò¸»?îÝMb‹ÿ¡:­”!)_¬€4•Ñ+yûò!I¾üÒ'¯}YœsEmT‹ô  ¢Ík†–s'­‚ qbš:Y‡ËÇV´…E%'Ø2Mîø©çÑ�T¡ö÷G6Ò¡¸ö ÎÎ3èÊ[d’r8 äJu43 |ž}áWÐk8DD�ȉÂ1 ÑG0 zYgÑI46€Ç;Úcú� NY!\ Ç9©×Ô9àõ™IæŸåË”*V˜Ï@Ð-�[]C¡(Æëuå~î3|„A�e{nX¨6 •/ÊëóÙ™6Ýfã_U’ßþš kWnñ%ŸyzbÑRÊ“:Ÿ–”BSO)Ú™K,{ÜŒð¶"z´h�¡Üb¾Éæ¿Ðz9CS±PàóµwØ}µ.BJ4žù�R@Ýëéºv˽þå9’Í%=ã3x£nfgWi�·LùŒÜyìªUwÀ´¶@¿Ü{_kýÃçÅ¿'CY®gªLÖ#2ö âY@ÅÛ¹2h3æJl¨ÖWä@èd¿Ý”‡ØFÔ“ÚÐ=ërÆ8”Äóó$¥D ´÷Å[v¦q ƒcr°:C¯@L¤9š9,²XÊ»Õß[ÀMè# ÷îÿ²‹ëµA¿WX‹J VXس㼫½GBm¸R\™@€TÚþäõÅ÷Ÿ�T�HÖw·ý!£“{}5§p&ʱG¨È­ ¢ã½ AšÁtºQ£Ò2$…?a�.5ÿEvè·êÝE ãMñêÄ=Ý¿Ù�”bÎR+Y›¶A hCéM±WÃy`ÿ¾ªêdçž»LSv­¥³öT7¹Çô+3ï„á°Ú%ÌN&h ª6ž÷uÔÃÔÉ6Bzw â�-·$4 *Ywò‘ŽÔ£º]ÊÔ”_²?Id¤ ÅØÛï¼NDžèC„9É’F—û'p�™J¼Ê£~ Èy&`Ï=Àh>t87ßÞõ¢Ë[*gÒž+#…ÇÁ[Tž±¶Ü™¤¢�¾¤}¬ª¨f¥æDM²*X�Ñxôw~Æx‚¤�ú[É­!1^È+ãÙZ 1Õ{åúlõO? œ¢êà2�^$›Ñûܷ\ç û¶Î™¾ZpßÀ |vÄ2¼«ïK/S±Ku  Ð>f–ü‘“†ÁA˜côè).Z9™Ï)ŒFÉ*^ N=üs${©åù±·yo·&›ý•@Ѽ Ç­GR./í?bP:ðòš3tEíœ!¨”•~�ÎB'†ŠS?õè¹CnH®³~Ùƒ,,€ÂüÞ–1*„ïM} àòƱЄ,XG™Kñ·Û¾hG}CáŒ8ÝÛóöOnˆânÝÒÚ¸è«w‹$þl3ªÃ=Òên˜Ž–i©gGâqJ ßI÷KRÐÒ´Z|�=iÊéê…É{?jÙ9Ã¥_ó“vŽÓ¢‘îºu5s#Z#[^Y6ßyñ­ùý­éÑ•àf6z%Dçà‰ëâZîàŸmбGva Ë®©g¢LšŽtˆè6ïJz]Ú€à•Õ&?1%ó�–šØ¡;-�\åcI‡&ÑíźH ³nQ¦–h)Mœæ1¨Iëºø¢AàUcLZrExÈgb�ÂVLÈÂHTssÆ¥¢tåŒ#Û7|áÔ i)±7_^®NØé'íÖ¸­ãÅquÜú¾„¼w‘Ÿ?C)]ëxR•£ôgáö¿¼�ýY-«Úï^˜O}ŠÈˆß^] QÕnªÀž×S7/Þ,6 ŸùþH@È~».䦣Eiøu.~,ÏTí­é »=¤@×¶P+4O}÷¡ÿÚÉ­Ö©Gñö¿nºâë(åÚˆDÍ:5‹LKýxZaâ|žœ JaJAê(=èœeM×?½ýÝÏq*ÔöBjð¤–ø¬KÏ·?õê‚Ù¿ùÂê˜` }pK²öª2ψƒ– B m�ˆZ–ÉGzGŠ0°¿87»Ý{‰{-ëoÒýÄâégù�ïñÈ?}á83B‚δÁ÷Ýßlé�ßÿhw÷s-çEÝâ=J€–æsð;=c•–%³]v:ÔJ:4z¡§ó /WŠ÷3¤–ýt •óG´Èz,9ª¿Ël‘�Aq�ÀJµIlt¼²™5tFSnF@Jbè·Ý$4õOÔ3ô·I3+‹[Ù|gìòéÎæû=·#´N<g2#á�o¶­ŸÄiÝU«M!uô[ˆm4¿~9æ-6m衹� ë1Bhbƃ6uò  Ôb§ž}V)èÏŒonÒ¡•[ÖÅ‘û· ¶#(d’žO otЊ¿ÇøñShÛ£µÝ�ÇE´a¸LO³].Z¸äÕríœáÔÔ+b>²Nª"yY`Ûk×Tê¾mú§•drê.[ƒ•ßUY¾ëöˆ�‹FpFø<´ý'$u¾p¸éwM¶µ¥ªÃÓ=glEQà3 B¥‚G2ã]k¡¤Uˆèí‘çÑ  ÈÆ5‘ñÍ(EºÄÉ3e†ÝºËßöÛžÞ[ø@‘zv;YšÀúbªã“�žÎÁ&nŸûŒ«…ˆ¹l♕ӻ³0À�ÐPŒ,¾¨öx­ú¦!Wsüm¦øç„ýì9̑ҹÅ!áÄf¿-ý«Ìyx]z;ZõY OO°A~²xþ$0Ý–§ÅìhŸš§|àP !aª&ìœNÄÖ“©Ät÷éÄ#,†œ¸x!ñrø™î’ö ûdÚ�8|\›zÉqœ‚Ã'K·0Çéµ ìí³ḻLèÓ‡±5Þ‡aù˜­1£½ü´Yô0)Èh™ö¤( zéh”çƒ_gôÂܽúã _™ÆI£=|‡]�ÀBd-Ÿ6¬¿:ªï…#ßž²+IQ†Ê_ïÞÃ@ªíÆìŽj›N&cæpEÇmŒU�˹ð& I8oF#è`_´üþnˆµ-ô‘HCk§¡­ Í–pÙ�ÑÝŽññ”€1;”ïØZ¨õÒÄÛâ Yp. dfÖZçÙv>NZÿp…«èt :iú�‰àvÏW�[/TóŽU’�kÔšv“ä'èøK.=‚xª<¿TGiµ#?ö‡÷dÀ®÷Uæ3OòÙ­J‰vÖËö^<ß ™›y>vó™VWN¬þ²Z‚úÅy¶�¡àT°E-"2yæ5v 2çdžÜÓðÚ@Ò7µQ)ÍZù1ˆ„z°¥^A�GÃ_€z1¨ˆ.d®¾{nÃa{”]¸¶iUmQLTðåípÝÑ’wÚ}Î’Óùiå{€}ùÓÝíìð"ŠÔr¶Í?í9O�äHíu“Ù›àHG k´gBÉ¿ Üò|ê%îuM¡¬E½ŠŒ°ðžzýQja¼þ}�¹áÔLD)�³]ùš°·ððøù®\¸ô„¼[Ù{0Z¯ƒž\ð ‚@CìWÑ™ŠæÈ ýf™øöl‘&^–ÏbaêBDlÂó3+u''§p^…_xŸ� ‡¡C)($¾~Œèˆa{ýpGΨ¥ÿ9Êš¸)(žõçæ™`N3X½‘wÜ—õ™Ò‡Ãã„Åç8 cr¯9ð ü6Öåš{iàZØ-¼Ò´Íý²ø§SÞT Ô�´8, � )½¥ñÌ£Z¤ù›ñvÔ¸¼·Ñnž´ö¨‰õ<¡…¶„„$�¢3ó)Í#LÎÉf¿ŸÊéä——õÁSÌëVÏ>¶|æéØDõºw—2VI·Í7à“ew¶ƒËÕêà‰Ù1�Lª‚�[ÞFÈB³�ˤ¹óŠp9¿®eM9Á•ý(¡7†—ŸÏãàˆÈ®=ÝP‡ÆÊZ²ü'�™ô™j–¥ÙK�î›,tIÜ;ðõÛBŽæ˜)œ úöIú£â �͹�WÜuìxîæz'É[jŸœƒëó–7ÏFS›BmÏ�i^˜’ô*1ˆ$••ÚÐú\”j ‘Ôáïé ÅeˆÜf'ŒäŠ…ü¡:óõ¿<9²­'?ˆÍR¹šy½ynKÔÔ PEUC‘`ò™ã à?cRúÓ‚ÿ qÍ%\Æ-^�¹Œu¦g¦ŽÎ²}«5~Â@ôæ~k·ÅU{q´y¾ÇÞ³=ë¢=ÇRTOÉÌ«Y?ÄQ˜—²½f R<=pB5…À#ðu¾òò÷êÎ~%:5}r ÍSÙ©?ÜÎÚ§éðî(ì® ña &èiÙ¹z |÷À'mV•Qrˈqu¿µB§f>~™·=«ŸjÉìØã@‹/eæKèÆïS»2Îb@ÿ�#fL‹Sc#?6u‚üÿ²�S• ¶™O;¾ÒßÜ.ÕŸ ³$MQsÚâ Îâ\ýxevM~ˆÙ®Q«…4NchŽÖvÝ7÷�¾—œâ Õ¤7é�ÌWhÛ·÷êÞ š.©CÑ8î�ăÚ Z´í‰n›ôà¦ï�kBñxCþÜ\#€•ù6½»Kè’­2‰†Ó}CËâÿç²d¼é â/pCÅ1<€`oT°=ö±/ú™<ä¯V)kDtÉðÏëH,1]Ž/MÓx28!nPlm@=[Ž_èø³§ŒÉkˆî†â2[´èœK¬D«¢¦ñbxt8ægå³ïŽ ™”ùìåû ½w,Úqù¡6ñçýµ™u;_3¼åyp‚ׯ+ky #P$.@…&Q¾¹w/ß&—Ö“pà�¥õÙÞ4Z¦ŽU§U@éŠ"~ð°õ*þWîeüñŸ ÀD­d“x´Î–Ûa±ÊÆUqô¥~ëæâC¢(ShÅYÒXÔÖg£X}ß åþˆ!›Sã£Ê¿ïVp¶Ûjv‚¡e~Áסëœ~N‰_3íꬾˆÏ4Ài;¦zƒ:É Cfb&ªñ§”Þ±pþþºë ˜-]þ�Úâ¯w³Sêi1Hî trJµ}Óp.²ý|XJ„uB÷Ggÿè#Û¸ŽÓðY©h„DZ�QÑ9dÑb]0IT•ÙWI,Âà‡Tõ—‘Ò{nä”ÇŠ�麭ÇfS7 ¶«-´òNM^9gɱ-VÚ< >6‘Gƒ`˜‰™²b€JÀè|š±–}kú²Í cŽÂ*{,Öïk;ã.WÈ|Âö`¢zƺ®rX"`ɸþ^>¼DavBu3ϲú'âälI<Á Ù£c~V óÏW‡G;I—À …8=+KúXÝi€ÿ¹£îÒ<�ÅA´½ kŽs—óÃ�ÚÙOäcKvÛÿƬx¼uıì=[•EƒEm†yçÊ„D“™¥í;œNêB× ]·7e–¢F¤mûiHx×ÏT}¤ià”1�rG�«Pémo,·˜(ªèö…*ãaÆÉJ®ÝÞjteÿ±}_DÂm±Á~ æ=bS©£ÞÒçZÐ? ØwÎqfáF‡Lï¹·ÿÖ*Û‰Ššqœ¶;z‹­W�dbÈú…1TŽk˜,ªPÛjðQYÕOýñ«ŒŽF“åöÀì`âñ„ÓfØ]¡•Y6tÈ F𪠄-}FQÝö@æác�;P�êkïÔ¯{ðNå6º©ì{Ÿü‹Åü¹Â ¸ cý€Õy22èÝ-T3ÑßBÄWÃiˇ‚æ��Â&)Ú%fþ°P†a­Óéå�¥¿p˜çn¤J‹ò}*`)¼/åž‘ÇÖ5çGY&ì7cœ×_x¶ùo¸eKÚù“ °IBÍÇ…�0!œ%ÑNÝÔÅ@8•¤_‹6dÚŠûCl€uÍ4‘Ð Nè줥û�Fd�l|§½)÷«h%Û0Wš=zªâ¢s±Ñã#í9þ2X©6øžØ;ªùDÒ±1D\ÓV»ë‰ÁÓûP(Ík¸”^y3‚_Ÿ{Š f[Ãawé!{cê¯$³6޶ž£ßPš ³þ•K]ÁPe.0ÝtIIlÄFÏ“8„¾²A~>KPHgc×ãV�NÊéücPŸ 5Z­¡»RÅñø:Md¦Õz¤Úß‘ ĽÚ6¤’°¾§ëÑ¡?«˜Ð‡/|T_r<5Ü?šI ˆß»+dTCsþ»æŠ/‘ ÉÆ¿Y_ÁÛ Ý VñF¹Ö�µ{g¥4æ)ÜÁ\OÛ߸ó�9WûÀn÷]»›ð4ºUÞ´7µŸ/v©ùN�ÇXÞ>n*mm)ZG6�sbtk·z—Ë–þxñ›|šuQ«~ú0 ™5ý$25])íÁíVhæ™»yš¨DŽõÿ+›€€ÒiÄŽ<¯–Ò¬S¥þ<¾­ØËïÊétæøÈ–î W¿M¼@svÌ­·ÙYÒÓÒ?D´Zšˆ—’Äè��®p4\ÐGèàJh"™:³$!àw}jøÐ ŸGCC?™r%r�ûÓ×hJˆƒLrz_3`~›1€E0H”ߊEéC( ÅÙ÷D.¢'oÈ]”�¿É 1/‡êµc Þë¸õ<7ÚTBÿ;mÿöMq¤«Üƒ+Ù¯PÁ"¡¤3Éöu_1ï#ô~Ú¬¥a"’”ùLQÉZQÝJ ^¹-’Ç{ š.O¦‡!gm?Qó\ö¬»ÈT75½¤ ^‚E´Ä�£šÈ%ÛÍs9ëÉGL¥á6öM²É›ºÔ2%%„þõîi�=ÚÁŽQªgiRHßJ(Ïpbo { ûEƒ¬ªF¿Žøôƒ²ôö:„»eL8²W¦ã;íØ&ºÓ<µkÞ˜I8ˆÍæ³Ó‘*Óà°ybà�‚t°�7­ör|y…¤cÁ: ìÞåÈœ ­´ö'%çs  ÎAêÖûÈñºŽ·Ñ � 25íä~uÀ�6mhA0=Ä6Ò7ç¾µG ÷€”‚ûÉÈÏòÝÒ¡eU2'[âxêÕ¢|~†7…V€øº L2LžÜm´ýìœ!Ý4GL³F{ivßÈ·¥¦>ß7WÏÀ• ÑS¿%D÷3Ak0õ}^Ø G W†¯$†þSyº'n§€±’½4‚vã‰eå™éK Èg�rm8ƒ*Œ$Âø#j—%Œž3b˜Áo|+r'¹â\Ê�­WáÆ:ÑñHåZ®e´ee”¯(|Ú\”×\�ßénåt¥ ó}rZ÷HKÞýŠ&BBn3�7OOÑ\»o­!\ü£úF ¶Ø>lƒŽ¢I|q§Q×p.^ØÞ%û˜KâQ-° É!1÷º´dÆÚÍPé }8ƒ Ó�¼Ï}sÞŒoO¡Û:vžâ lúê)AO…<Šàn/¨lɲ”ñº4]@JÈ ¢°‰.'n~cˆ‚’4kùxB;³�/^ cùý¤˜‰¹�2˜)1>$þw×é]¤\‰û:_U�¸-Ú±Æþ¨xÐr¡üFÀB¹¬Èv\·7Ö>‹³œ©´%+e¾Q%*AHÒ‡ q›«quj”5!%Șín©Ñþʹ FÖøâáŽèFY’¿Ý/« ×þígÝBCfm�8IDîp0ºÂe † >‹²trýµ€«p�G·%{¢�?öhÞ­¦õÛRƒ [1qœŒSI+ÚhÏNRÙhP˘ç2\…°"ôï $¬ƒ÷¦?_åVéàš��-“ÁlÔ>òu€& %rÐo�Ñò1.ÀnèQß±w¿š³j\± æø�¾²G¢)Âáú¬+¼];±6Æ·¼õ]¡£;3�KØ·bÕ”âo¶ô±UvžSxN íÅ� óÿ¼vÊOèñ'YánÄûl!Üè¤Â| ªµ¥þ‡53û—⤳¬éVX LV+CañÉ0ª´U¿øJ��ÃÝt¬ð±X:�•�ãN² «‘V: $ˆ{ÞÞ óU.1Tr–üÞ蔦ÄÜ/ÎŒh!ø³"O³û7Ê4ì�LkšyüâPΠ^ž3xŠ,©fóʶöB””Ô ¸r—Þ&)Å‚Æÿ¦X—6SÚáJ„2"«T(P?C ,wJ¯3‡ldƒ‘æP&òv[ î 3ò�³fWžK_…#™ Ú¿qšG¸€ä¦3Å¿S –bgŠô1þ^Á6_R@"<àݶÁlˆÌEÑ&Þ5!ézmv¯«•A#ËÓçbó¡•«6TÆÄ¡cb[b"{ AÃö%ž ¿ªÞe”k 2Dl³P#±WQìÆ†u`µk;J�‘h‹ÿâ_+7ºþ䉎Ëð+ªr¦¹›²ô;° ”ƒ¾õ�³�¾XŠø}O„UKB§ÆÊ_¶…4ª2ÃÿÐÔì.¬K–¬~ ¾áðr TÔ>t+¼ð‚ð-iÌVky—Ù1L7%#›}hªí×ÄcïYÄ$~^uÊãk�0„»ûjA=PÚ6S).±› �S˜UÀù�NÄÀLÚ¹tJ´MÅ“ÁLþK"¨hN6¤ w!fŠ=�d÷ÜI¸¶ý]ñÙCÂ’qQŸûW»Ä5ìé¹�û& ±lt,9æ2w¦±Ó#ÏU çÜÅKi«>óì‡LeÉ`‡âfÆ>„õ91<Æ's6Òè¶øPIbµœ“4qeô΢Óô%Úr(°‡JG²ÖvT™©iËÝEz©[~‘oØCÍ]¦Is&¢GÍ êqÈ@Þ’¯·•Õ3PŸrü*[‹x¢‡cµ¡0$Þ�‡§ü¢<ã·× ?(vãÍÃÿ¹”K,†ÜžÑ"ôU¶­…ˆþ›½–ŠR)[Ð� S'=e‡ð�ý&{u¥OØÊ*ßú)>Áû6j#²0]¤;ÛІC×J¢¬yÂL›|U¶��àJ ^VØ›'¦ûRÂ0‰$uUR\¨ôñ)\¬ˆõqs¦ÄÇS�ï-_¿Üî@«Ò|UŸ4ü¡”üig¿�:†‹[£»ÀÇRq=ðâ{ØT Ûz ä&‹ÃZ`‚oVŽñUœ“Q+=–б[‰ÇA»NÒ8¶:o`orÚfPð L†Š¡°ntéÄzØÐ=beºß1#‘^¹cn 1‹&Ĭ]ØEýð÷FŽr¸Ûän¯,úãtžDî�ã.`Ÿ¤<ŽŒ~f¬jöµ¤wÊ;¸H‡¢¯À0áæH|ÒžúÊu�G¹ÎÅŽ,g!.¦ÁDÚÉuŧAx~ò`¬ME†êÍ›%Žß*Ò†~«GÍ�`ÌÒÏVÀJz1ºz‹•§Tk¼„¬pBÉ;2�kVù®›èÙ¾nâúžYFЂš…\ å2a�Aó>›I†~’ȶšb—"�"´éì¥å�=o Ÿ£[x3Ê®þɪÿ½µ7ĺ( Õ—±!flRÿ¿ÝŽM;˜Îg‹†É‡ŒzÙ~ClÏLަ¨5ÊõÅ;ôóºeÆÅÃ%ÐSTXÞ;ß:îA‡øÿ+ÏÐop%q|nÝ'ÔžÊÿpêVmd þþ6�Ë]¼QÿŒt…¥`F‚y¬‚ʈZ¢ #¬?˜(‰ä�-ZBæ»Ô ¡·Õ‰øKMÜœòöû1Ô–òù»{S½øIÅG`ËÚ•ÿ¢tqÞ�@K—¯ªÑÂ9°@m�jãb³K,á‰e«^¢óÒE#þ +Ç4ß´£OûkîPZ>ÙÒrGUÕ‹Iㆶ–o ¶£.<øî¼¾OUºuK%Vc÷1¨ƒ÷×­KJ:t†'°pƒö‹¼sp­× âNßþßâ EŽ9žÓ Ù¡vI�b¼îðà<”Ø- [(Høé·ÙÀNŠu¯2#ž` E5Ág&(ó8n°näð›iqéޱ赚~]oÁ¼„©³ ê�l Þà�k÷Ú8 �ÚDiô®%JkI;/2ÑH9ª<á¹¹nŒ{/­Ý� >x†{–¤¤‰&ë2bÉ7wÿÖ´éÌH¶ÄÃöO£cí<´\õY¡åÈ ÍÅr�׬Œ¢… pb|DañHå k|‹ûZWˆ  j-ñË�p§ŽwJ•ƒ†iªµ{9ÚþGõͣS´Í“Ó¥(FŸñ“ÖMP;áÕ-£&¶†eí-Ø�Fœ—«Þôjøb5í;ôŸhWp/ú |  ñƒÅå Rån6 áõå Ìà¥tÙ¾f zÅÐé çPàÕô¾±<+ED!x¼y[Ó¶û]á‹£.±Ø—8)C“nÔÍjòrÙvMFÂNárB™¤è£uï—y”'¾Lƒ?\Ös§ÐA覄ÔHƒåõ¯*@1¶.'œw1m÷"®ùÐæÔ�_ãÛFöàƦíNü7¨“˜Ûx½…s�š÷¤G/ãÍm;sµøŠÙ™Ö¥3ü¾,B=æ‚ømÄÁ%5 Ø@4™ú±Ð‘xêÒMôÉX3™þ­go3ÜÒ¢-Ρ¦þþ˜¤îâÎÜçù.t¦Q!!=R-ëC l‹>šñ¹Xt+qÑ06i–K1�Ë?ŠPÛÐe>6ß}WÀCÚÜM–ßå»�`u&`Š.^=“t ã^9â>*A£spÈ®<ª_ŒœæRçtbàå·k¡ç�b�ÐÁú °f.ØSð $å÷s.7¾ù†ï6›!ˆÄŽTHITøåG”X—È‹Z£? •Ϣѧ­U-PfÕ¿D 4¤@�:�‰ÙD¹¶e#ļ!×:f$Í ïÃ%•9L!O&ø½Á ïYÄJ²R&í|ðµw\­åq¤,©´½�Ží¢ûG Zw˜®6§µ“T‚a¡ï �ò%=MzU<*ý'*èõ•Ë9¢ÿ#�1²x5V\ÈžLBî�D:Wk4Ù÷=8R)äm<2nwàÜ}œðË�Š eÚòE™’¼Î]=ÄËPÙôê™ ÐÐWf‘“>H ŠÍÔÉk¼½VŒÕ#²Ü;ÊM|mF� 7ëÏ1�À˜÷tº¸Ù’Aî)îF#l�æÄ_~7´‚ú!SR»\æ ��fF­ 륳¸²MåÑM¶MT•¯N^zÍÇ é#¨°aHîªË.¯Ô_·JbÁýR×$¬è—n„:$–p�z„®·^ôëAM~ÕeõY¾–0àÑÙxìÀ‰¶f·9Nåò`_1;ßY©ŠÐ¡]8òÐ=ºƒžßýÃæ—Ï–Djb�)²©cc$B(”QIÄé ÷]M©yg‹D²­Öú”+á'<Ìcyè:‰¶;‹X´�·¯§p»ÏLÄ|±´W/ßÍßXè±Pœ–1åI·bˆ$AL@“?‘Ñ yS=6yïÃØƒ}À ˆ4ê­&�aR!*^Höò­Xk˜u8Íëˆá²ktíÖß²¯Ó>¡©§[gýòçíp]Ö&ÚólÝ€Ò(aQê´ÙO¸2‹oV �9‹´p´ËÞ~{ñu—UˆpîÍ-ukÖNÆÜ/ŠÒBœ¤]<ˆ–Ì,GíDÀÚÙf?9ìä¶% Òm-¼ Wfª4næ—œxñ™nk‘Ê–x&`¤^ßœƒÄºRl]ã³ÆÃZœlí‚%â*gü‘_4J2 â)ù |ååieÃÈ4ôôÕù£&˜lÿOõ{ý‘1öfylaýEÄÃHd:”dA»=øy&Q˲PqZÿ<ú˜�ñë¯ÖÁI?Nb:jß/±Ùý\4RñxzgB꽜³úB N�/Dó0]oðûÀ‚u“Öº_´†”"*j½«ž²Á³åðH¾äaX®§µÈÏ#ÝyÅ=5Zn·’W§ª$.ÐÔþ"úŸV—ˆÅ£†®¶NYäZ�O(®*ëÎF6$È8½TZUÔj’^÷�Šë”ËFï^ká7Û�ÏZTñ0þ�Õ CªZ7€vû‡ÃS„@6šÐmÊ£EP¸v]Êçdë2Tâ¸7L{¾ì#n8D­®š�Ž$Nª¡ŽÝ¼2_}Ú–>•Iµ$¬*è@é—Æ`JKªÍÕÅË‘&|ÎmÈìÔWV;©ãXã«Õ ×ÿísзÛ‰X]ŽÞB(À4·Ò9ÒpzGšÓ%ÒˆJxO©š•¯¿|*›æú¯lam‡…r%îgt-:Y× qD¡±ŸCëÐâwÞ^À&Ñ?º+*ùã"´28ß“÷ž§u`Ç‚]æÙ2x} ®ÅÄx´è¡›‰Æ( X`P=+í.`(¯‰™-Êí¨œµÅN¶fvÈ.ÅDÏùø®ÈpÐWŽy‹'s88€ Ùï$�p„1oç†Ov�FUêé–(Úsè.ìy´s…hN»2÷¹—†�<ä‘‹£�oDM ^ Á ‚‡²‡a¶8OtÅ0 ž%Ç®IO ’jÇ$Š×³¦ì¥;fÒý¶ï㎜.4£¡ Òê`¦˜Ÿô~€�¼Æ5)k³©Þï<ך­$kÄ9¬ãA­½MB“C^ÓBµà)œ½úK¸/°„¾ÎÅNó¿ùaEïfžZ(¬ÞÒ¥”ÙÒàg{Þlù5çûÚ§zžû̆• ‚=lÑ9ž»<²÷4ßtzìR°T¼ WéÊ ü;•†§É¶ Ò iÂuýXì){¿|Þ^«æ 2r+ܨZj)· \.ç4Òù÷œA[d6ÙÆ"ÜùT¼ëÔk>Àä$ÕDYòò�“LémPþÁÅÒL{Aüø�wÌ#yžë,e²Lf¯ÃY©Ã(rÓÕ\’>LáŽñ¼MY7F„ bцwpŽüô[kŠKÄ�£—¸ÀèìgE9JÉ\ūѺ£2-áĉ[ÁÎL8.û¶¯ð&ä-”ÇOÇHËÉ$.ÿtÏÿ N¯1ý·¿ruïöÁ—&ïÄnGªÕòg¬~ïâ[ûâSÄ�C[&/¼�€k(äF˜zÒ%çw¸§‰-›ìÈõ†IŸÉ@�ÐŽ'ôB Sõì¦÷àW—�"�C9È£ÇÁãâ5þU×MZ<þbðúZI€¿í§5«©å�5¶ ò�"?‚D K&\ ÙI64®6oØD °‚t.£Þ|Ç¡ìïhÖz%` X<À/u_¾‹M婘CÏ?c~Ð!¤Ù»(MfÆGun@g¬çóòy1”t´Ù®<)Š_��ý—© â(µ¤ð”«pÀ“ZÄW2<ˆæÖ&ˇy_ÎCáK^ÒðW;תÓùÓľòÌY³žüFJQyi€ b9QÿCÆ„ã3páÉnÏØhåpî‚Ù^‹Þv��±Ž^k­×a üB†cÆEõæ9Coß£é­ µÇ\ã|þÙh@ A~Öþñº‚¶ŒipIöºwÛ’ÿwÞÍøÆ ödØ Ã’Ò §Ç4I\8;½{¹>aC½¯Æ(KŽbdy;+1ý è@�¦Z¦›aYÌäC;i›ê÷ßkøÈM­4Ì~¿9bW«Ü¯Öc4ôs=/íKÄÈž�®óÌõ5 Èü²_иþ†¡ï ´Î¾­zö5>�¿·ÆRÀ™JÖ~ÌÕ�±¦Ïä‘åÓ\ ßð�Uú×Ñ MÀœ<„Ïu;½b½C@ï_2�ˆÚ…uöö•‡„ºqt3/Äl*Ô£žç‹ï€0ó…ÄÓÿŒ´H5×¹þ|íJ[ì”8ÇÂÆU–�‹‰.o™œi&:„0ðÒ_)Øûš€&ë¢ÒõLBÅ�ÿøÊ i€q“VìéÈí;¯õ¬Ô,Œ7‹?nðÙÛ¦�Jc1d¾ºï¼D„ímF„I£wƒä‚™ÓÍâ­M¸Ç,KVPEGdû�Äκ0 «Uz!NB�ãÒ‰²%4J(Tœ2Z—¢L2š5hµäWÁH(…àˆ»qÛ×¥qò í0–¹ÔŸÂZ”s´tÒGö$ãŒu‡½„€çŒ³ã±NÛûo ”s ä‘�‰bzãZðuiyñ±Æf‡Šõ ×Âe/ì‡,ëçzS°ýÈÙTj5ñ¤Äy&6¯Ð]ôXú&±¿JUâŠ5òÖ�9Lî4-|,¾õ‰F=bäƒZ•’* ìÅ&/ L"œÙêÔngöÁre'€³ÿ~Ú ×ogjÑ{”y�?ªI®KÒ€2(qþby'ج^gYç �,Wÿ#Ëá)°�è®)†®üÚ#xI;‡è=…I§FWH«½�ÍJt�6É—yvÄG9$ÄÜ�,? º­ü‘ÑSGë-,€Ì|H­· ~·>sþsà\�Bó~r!XÈBŒûûA &zÜP]�™sH#O„êÛ»‡©É_³Bµ`ÚðÌU&¡÷Ô““Ê�û™?9ôôuª'™‚1KÕž/±5^�9ó ÿ~ßtÛ„sQË'û=‰lŸmi?²’µ§SÉ–‚íÉ/=iZÊäõDN‹îÕ>¥_�¸ØO�ǘ1l�çïÆ÷Ãu(åÁ¿h˜~ª2_à ¡«NC±LáÎ�‚ŽP!:þKNÕOS#UŸÒÞëU�EèøŸ›2Þâá W}¾PM1†`BÇÉ>ÎàWÓ+zwÚùœ€½O–Å£zÇãCD8Vÿ¸ €Ù¿µ`Vu XºlÚÕËîý©$ »Rb˜Úu4¼œ6…ÊøiÅÈãkÑê3 _ñäл‚4Ò­¼hUè4 Œ’/ša”[BØ©ÛN¶¦9îÀ+Y{•sM7XÏÉc¨úN"•7Ü¡Éw�.AvÚCO7—\»“žèd£;†Py3¨GQú�éixÓ6w?ûPlá:>S¡xÆ ÊÈ3¼�óÖØO¬´Ò®]<ò÷*5ex¥5^‡Vñð�—z·ýÒ%W¬×ó¿ûl6µ7�h Ûiá€õZF†Ù Éä;)­m"1Á«Þªc`ÖEç|N –²‘/±óK”y úI¹’ð—9¹ðAw×ô ½¾µwDù(›Á<>qã*ªˆ�[÷å Lëž‚í�‰4KXçjUÂÕwì¾·­ïMò=Òª�Úæ¦ŸHêŸÙºÍþÂÀÀQƒ^oJ…y%åÙñ%V¹ÁÔ‰yXYÁ«”éö�qŽyd\_bkÊŸÿ`˜ŠÉ?�ãb•a8ã›ZÛ< J:,ÂÎOwúÐhþMù‰—_YNVñ3â;hÃ�×dàA“y+ÅÊéùT“ìZƒ�Þ:Ë¡0DdXàsgiQJI']6ǵû81 }ûšÞþ¿/ù~<ÅL`–TFܰ÷o£9e½4­îg{öÊ2Û3)ˆ@Üf}kÚ Ñ=Gs!?“"9Þõû_˜“j ,'S€Uú.ýž~¾«j±Ä§Éþ`˜•šz8 kOÆiµQ„S.®)H±÷û»ƒÁ2·”º‚¥Í§aÙ�Ú:oh·?ÅÔ\Ô÷Éo%vSÁ�b ダfùϼí‘p,´ÉRžw•w厽2««©s¤Þ–Ýv ™°ï“ëR5�ä‘ÊžåW"< pœ¤•Ïp#¬ýy¶\Û +Í]hU‡Ýl�¿ëo¡5ûhòœzàÑ€W @ƒj>3Þ¹òàGh¯´c°L‡�°ó^\Žò“{DùK‹0F5ýÐ� û.{-Ø¢½oráy½u£›TøP5Ñ©n—J[€OÀ�§ƒuÿÂöV¥û?ã]FÃ-”ÐêÖE™Ï®Øy(—ÕjLs¯”_�ç&2zFÜ ­¼!?�—Þÿи5Z6¡W•3¶ k„™z¤åíì¼c5z¾"¡©-5ìöc!î eÊ€ï°Å¶, )Þ0õ!›%/ÐJWc{‹Ôø6ö°µ4GžàHæ ¦cÇ‹XÃ¤ä‡Æ,ݽM<}qÄ´¼0_ÌÁV6¤Ëi粯:Œ×N”8h´_�’+!¢«ðKýšé‘­ÜY4B_N/ÅŒ ‰>œæJ)ôü¢bb5v®4 ®8j¡EnÃÒ_?â­·ìS óYÁÅ9ü˸Ý¢Ixn'”$Œ”¸ï¹¾û×Á×z‰`¾êV˪ Úžgr‹tsábB&øÒƒŽ)–‡†T¿q‘6†f†z>jè±mhÿ„žyUÌŒ­ôs.‰�\µ ÝS>ÖɤO¼¤…»½Ç \?Ó n�£:#¶´K¯&†Š;r^¼I :‡G†«äkmŽøŠv~� 0˯�…wë¥s N,´»sT`2¿�¢c@»cØ| ŠvJö2TÐß2«BØ”�3îŽV§5~<ô5+ù�MâÖÂë²ñÞ©m¿H/�Û…4…Ôîr%8}iZ-óÁ°÷R $©�iÎNÆk *u)Î;Bù %÷­½5ŒNçTo`YÈõÒ}{äKñŸÿºe,T�MwØ^+ÿ|L-Kp_U%šSÆE¬-ÌYV�8Ké™,vÜØi³ &ÅÊă•6Tx5ö¿.»ÆJü¸‘ÉWsƒÕBU•Xª5à(ñ#Û’ eäÊT>æ,xHÝ :³‰O,yñzÚ8ó€ÇbHQzWö–“gœùý}d€2ˆ¬€ì«á¹ÇS"r,Õ “¤fóQèð²­�+ðé4ifÕ©ÿ¶û ©oYäÚ®ûCb_yëg¿ª<êÊo²tØì-Î�3ôµEñ¯ÄÀÎ-z+k«¼…20£Lôó~Ç‚îü® ß�Óò™ë@Þ¦y¢€°¸¾Rkúì}бb3ŠG%›ù–Í$ê+Ì·G°C�1Œï{Ân8€¹]«{Ѱü�›\Áèâ­tÀL}%¨æ›Î�OÁ)R‚ЉOú:¨™´wH9ºSSñ§“˜®ð+ýþ®Øð'†ä¥ýØÒ>ÿëÒGòKQþ ·_3§Z'ý}eyÚã{þ5͹ÙÚÞÐb<¶0:ýñ= ¢Ðú0Š8FL žBRùˆ¾Ö5 ó[yÒôœ§°£Ìë ÷àœ%¢¬óxôίî ÔLZºð¬YmT‘˜ë‚†­dAÔVûsøÃMþËuy=•N¬ê¿¤~.ÎxgV툗¾0g9fdê:h„}Œ?xQÃ8[«YÂîº�„¢ñbí<€ÔáÉ”åŽ Vt¡�ºœºL¿F8Ùõá¼Ó�ö7Úa’tbäRÚÖtñc—JÀa.f0÷´±d'ãäø7[J¥A„‹‚î¦÷êC†_ô.â-PŸ£J¡êZCJØ(ôUHn,¹¶MŸKúc»üÓéM&q�eæˆWÌýÑ�®Úß °¯ˆ^Àußié(|¬$³[F|H…vð.�”-Ú™¨q*ñžZQ xQ_Ó�xÓkþ+ƒú%!t½äüÉ6[(BlÚIÇôx†,!ïêg&\r¹¹oIp”¬£€¨PÑ\ùýaŠrvWɸ?ý½Ôûq6ÖãÎýG‹0¾;O+ÿxµ6m³úǹ©Þž££@v¨Åδ8í9nÀdå!íüp†_Øñ}®dãp¢ðSÎÝÕD$ÿ9}ì`�¹¾Ë~JN�©•U�À\+Œ-ÀC¢ÂÓÍ~¨Pší˜’×�Ù9£-ר@v?ï­¾2=Ä—Zëè€ÚÇ¿›ˆ,ŸÎœÒZ’I�ào©µ>z–ê}ê,Ñ´÷H_…Æ:ª:TV»Ã‡—»Õ(xÝa.¸#/6‚¬ïŽ×D=8¡7�sax¸ŒË�ƒX¬u‰Ž£øS»d®áT¶8jïãƒï2¡P.gÚ¡b<…oMBÔ�>Üÿ«?¡y@,C¦{” †ì« ­Ìì•�0ýˆ.¢M¨†Óc¼›#\?µ¨ìœO ê:øIS …yxŒ ±–P!Ö®jKwf¸„ì^Öá”±Is²Bºú�œ‘Ù­ÑËx[þæÿàc@ß&'€F'šk<àTóƒGÍDå~ áÕÓG&÷[§)0ÍãA”/zŠóëlÂp?ÃpósHÙæxŠd ¾˜Š 拪+x#¼•ÌÁNKz š›= í;^–ž#B¶¶Þý©“òv×Õº÷|lÙì°ìÁRµÒk_ç�¥gðŠÖŠËÈU¦/ÝUh'ä¢|´’7ÿ¥·Y,QÍ,xœB ß«xk`,_vk®ë¨d}ùï~Õä=0*¹,yúšbI$áLÿ;ä•îZlè+Ý¢•Þ: ›˜P”ÛC!7:Æ�ÁVI•(ɲ-‰Òþ¥ô��¦+Äp¥‘³/UÏ«KûßV~œ_â¤lb­þÊîgv ÎÝfA‰E%’®™„#]º˜üek�„pØWª_�»BM¨Ó$f4\T"l×ÝaÞ=�§±™cr�ÃäFçZòä2N„åd#%ÞÈ… y;(Í£1�OÁŸUöy¢o@Åü”eÂ,y¶Àsn¾Šß ǵGýÒœ¡±ÛŠE ÒPº�Á² TÑù–Þ(Aa›–=5kßwjÍ¢q\`åü£�>¸rQ\á2kDÅe+L Ÿ†rp–¯ßªD#j�>4`Ý ÛÝ&+êúÞÀÓÍkN\­×Hõa2ÔÝÝ~dÞ�&íˆÇí¹'Þ¶25åZ­¸§ç³bœíþ�aq1ÑAÎêä<*å;ÙìE#šÿ¶0ZVÓ‰UÐ�`@È€¼•`¦7Ä#B¦å£óŸÂ9_.N÷2�4Uõx*†`{ÕJuP›1äARŒ,â?×w ÌÒæW»Ë®Ú�"¼ë@Âæù€Ú&ˆúÏòjåüè8�Z oÓ¥ƒ½3YñæØ•;ó]턇ãÜV”  ¶�©IN€Èç5ÁFžŽed’%¤ GpºÇÎ`Mª«„1h[7Eî©l�/ã(uLÖÀx™Õˆ¦I‹ü³~·~à6�¾Š$ oE8&ÑtðÖ:Å¿�n«Kd'OB²@®@?{:5†½*=�†_\dT|˜có6_~ϰ¡ÖÂyÔPø‘x2aã#-´#Êp”ÒÁeâ¶÷§v 4+ÍUƒô ïñÜyrúðâ€)WÖE­�ŠÎê†çjMkô&N†=­ºÎšæqÊJIÒö0h2V啕GA\díVaÍ¡Õ|ŽQ}G®â÷çsC¹þž~Õˆ·Fò¶lÁ™ÃXL(òcñGc[¬d¸ÚHp!?hvxˆÐ—Ñ�ËŠ`gr~/Øe¤´N™¥1ðïŠÒ?…–Ö"yÆum–˜dyÄ�|¤G4{Šøƒ®’Á+Å£ÒEæðGZ®©¡e»0®?)3úÐæÐ²Éjâ] p¢˜À“☰¦''‰&ŸÉÿ±a )¯ñÖæBÑ{ð²¤RÊ>Ní1í-Ù2€òÍQßýÈQáOó;`f¦Î ™Rn™k;�_%“(ÜoW¨A��íë5}b~‘Íd^¥"¯…>—'ë´´6¬!Gj÷ÌR˜�×ÞëûÙÓbÕ–þ�šÓ·#W×ÔlšªDÕª‡*c ¡œÍ‰'ñòà«JL@è_*¶¼œ>+ÝaØ-f3N�ìEÜ“ü£J•�ŸP©âˆÔçõè­q›Æ’wÃ�V9"Ý¥0 �¢gPFþé-Çåt¡ d{º�é& Òú5ËMº SokaUÄòwt0MêPa_Á:þ-äIC˜à¡8ÊT÷¹B—ù‡µ©:Ré*Jþ¬¼! Û<+v4«¥Ï(ù·®nÚŽ›Í”:z¯Œ)‘.ªÞ&7÷[Óö]<{* ³'7縆8�Hq,*Ã×1¤IÆVw¾¬™6Dˆ¬”«˜"æG%›ôÓ«¬“‹MSÐðlEF ©xØõ‡ W@d`ï7ÓûG é5ÉÉœ�ͳ8úo,‚g3ÓÈ}úù‚L%m ms=ËŽ�”€}Aö£è2|:'"U7) ˆu“�Åcy­¯´áq6¤S¤pÈüÈ‹ƒÅð2.C½k³îÊÚ�Y%JWhî>œ3D=„üö­¶J �e°ìn¡týó%«:ßLxn`ÃE$ì1ýàqIHW4¸5 ª/àâÓ¦8´¬ö蘚á¤å]üžTfò­—o•#Ó”¢÷W,Ö+Y ÖXç>»Ab“1˜Ëy¼þ™{0¹RÒd˜­L�eTº²‘ÿ7Ì;vÒ‘X`1kXM¯Ï›3:KlÍ(âk –Ia¤ðkGJÿrC‰T½ þOî+>� ¯t£–(ƒîš;˜ƒ 3�Wó ‡Á¶M*±à/‹ÎuÕ?ny†:µµ­šQÑË8ŽhL[âê+ažÂØûo¨ƒ\¸ÑtL‘¥¢]ô´…Œ4Á½�ß¿XË ÍÏ®aõ'µLïäQUm½ÂfïtéA1lÐéTõ]jDœ!2ƒÜßá¾|,|Íw"V®T!Óö ÿº°Ñ|Í–á¥á�zϸ¤u†à (ʧW³dûÁš&DÝ‹NŸ[¬hwÄï ZáÀy*Á\nƒÁ$sÀËY²šÑdû/Xv�ò¸¢;ÀL£Š$ÌËÚ>OÑÁ�—ð¬˜z¦ÿÿçî2ÓNG„†Å9�É*¹|v‘±›lIY Ù5®w»ª»ƒ ÖJ×òÄj5’6zâ¶£ðbÖºÆé_X£å† ^U³«TÌŽêdøêlŠë®Þ—#¡ñ #´ð+D)‚ìZ”Ѿ}TÍoCݘ(xÇÚ"Ÿ×Û¬®9€nÆÝ·´ÖxxùìGÏ™ÄɽƒÉðaÃ=Ì£ê|�æ9Šìòu£S`EŒñéy˜fƒî1!#ô0ýq£õ_•c@”ŒUòëØöJ’³¥P늸ü$”˜Í“ÜFÙø6m&ÝÙ‘0¶:þÃ×=Bí7Š`•’\óEzÝ-Oš¾ßç7$täèÆ,s7ŘWlê�&%óÄ"ÜÎÏq^äw×wÏ'‰Ù¥ i ØX‡°ä�YPÝšºÝ+¼ äü·=­ù�ÜbË–ÆðŒ'èÕ@Íïp§‰˜Ðc¢¡Ò:µü�ƒ¨½@w. Œ×ñºÖÑ%xN"×§¸ëQbE¡ÀRb ²êؘsГ=G²Ó΢4rvò*çµz‚ˇÒ+óLÛ·³¦¬�Yœ°±Ý(Ë}3A_¶i¬5f(ô–ýxž´m¿J,Æ”x7pÄ&r**ñ}ÛûÚôBR ;­}ßùƬêĽýÍó÷е"q!TèpnØBœÔAš&h¸Þ/¼ã/"à©ÜÏ‚P|EJmŠWx‚+}Ô˜áê½û$¨ù)G©l=RòñÆ�âpŽhç²KÚ·œ†ð·4‹ºÀe5o€à™`¡ Ï]}¬G Ž» ÜX‚¯ÚûÛÍ”]ÖJ˜¬M´ˆ­u¯gEyÎjÉÌú-"IáQ´õÿÇ—~îjÇ‘êoï:©FGÐÍ´Û â@¥×•V—7"+r1¼o4*@Hášy¹€àtÑ»¡_¶3´JÝ 2ϨýŽ-.¹ð"1îÚ"‚dñœ/™ý­Ð£Ó^µ6ƒ�QHÓvлÁ¸p‚þþ6?!\Ë£¥Tkú•¾ù3¢Ž‡ãÕ¥!¢ŸM^;�&s{dQi'¶º<㽑ÏË/ëyÔÃG¿NµØXGY÷ÜX_èHÌë}rVª£�›‘¤ªk盽yœB$6�#·Ÿ·(/vh Ä„án“²OêGä“]h×½oæÖbÛåƒFÖŠRY¼ �ÂYdj©úøð¤…›æ²o×O¿Œ­Ñù-Ñ�p-jXö ë\µ¨GlNŸ«èð"@9‹Pþh÷m%sI>È€Ôøú­�5ªç³¥À¬2d(«n*ä@Ø´—çsv�»0¢F]”É… ëœðø»Ï'Áü0ª+gBX‰{ºi‰&=q®WŽº ´?ؘÄ9…Ű.à­€ìph‡Õhê2}yÚ�çþÃy>7iN™›Í ýÚJ)œ…N?¬c_qX4Jεfìz±r…lÒij=u.��ñ¼xôÙŒvÍž<ˆGa Eþg”nbáè÷ta¦zÛ M R› >�Õ—] 8�&èV0àâráŸ<㙿¯.ìÙn'èûª¤y9¥•³Hà>þ¾�ÖøMøÂTµ‰F.ÐÁÌñ5ȘÌÀ>E ó¦#V)E{¶—·.Vì]ê fKX‘Á»cz:q4^o§ÕÓ4Eá^Ô–§aÑ$HÙÆ\Wéø†^–U ÉFoEñ¨µŽÍê)ûÈy´>»¦j¡åÊQgSW;o‰tÁŽƒ¥ÆõÛä|”à"clÉIá¦$ÁrX‚8”¢7<þ7Êf»í¸f&RÈaÓìj]¦”Ò @n5@õšk–©Ù¦|Þ0!è¾ub៮Š9±6”/¢†«­šAÞ¾žå:{9‰ßß`©–ä\Ðå6y†•Ÿ¥Äˆ$´LŸFy‚ b­&úæ*Â5`¼™£ñI¤ÖU‚éwÕÊ‚|1P©Á¸r¿ïÖbZ‘€c¨*g™«�g&‡âÉ hA®CóÑrñ4üû5WË»†/à)k-O~Ê“#›ir©ÿ²…Îb¥%Á®U¨~î|åàYòø±�FŒ.x†ÔªYÔ“+=ÔÜxŸÌ£ Æà]WB¿Ãï2¢¼Öº(2ÜkÏ’Ã)Ùã„)‚ˆ Âáûƒ–Î�°{Ê7ÃO¨^ŸWp¥æ(tTÑÛM¹æÇ«`¡hIs p·ª<ýÖ¼,g‰6xñøU¿%¼(À:§Úü ¾í‹g AÀ†1s ”ê/Ÿfeùi$QLŒ•€äk­Ó£|ž–.±ÀmW÷_6-�œ|öîº0ªzã²£g1i½ƒöïšE6urTõÿfsÖQUd‰·ª÷{VQ76Ÿ«S¤‹6D †;øêW%S­ý0 û�QÑÓ¤*¨ƒO‰å“âdµáqR¸ëçÌ¥&Óµ'nÜ·:Wäù7Cg"í�x³ÎÆ¡•M—dœ…¶$Û|Í·oïò(¼ú9t$è9”º™\ŠS΃Ÿæý†“  _êN. Úÿ_ÑÅ5V—ï^v¹D»7“2`KÙ~8¥÷çÙmþq@ ph &UÝCW¬Ìyާ™¹­Ø e0rõw³×?Za­±ôPö⣔g&]Ü­05^âþ^†œíù/*Å Å~Ùicä¶¹¸ ' Ã4Æ…„kùe#�ú¦‡ˆµ`Ì8öMrY‰iËu^¸þ‘Ó«M  yH,ÅÒÝ1ëN~f jR~ÙqaœC¹×X{k©³# #‡Í¾¬e¨zuô¬…D?U4ï3F ‘ûmÔøy�w!uè�ã=z"wv�^ Ó¯Æí¥´4”åàÜôF p‹ZM–”¯SÜôÏ›‚)y$$t÷j±—HެïTá¡*XVû”ê'jb-·/(ƒ§�DÀ¨ØT0É`vo¶{°ý’w, öz!3¥W%æVxÔ›ÞROÿÜäx�¦HB—óW÷‡OÉu5e_°‚/(¸Ô3à�f³é®£›¼6R{2gt57—ÆB`¼ce:N9ïÕA£iéhŽ–y¨¾,îƒÃÇxWÒHº ØÑ§â�f¥ËV&ñm•zOóšu»Wp=E!?€¼o�–eÌR¿ŸUÆ'[ŸO©³�8Tãdß•¡óéæ9ôhɉ•Ï‹k½�ÿÞ«°–°jŠ#&äõVÒßz„‹ÝÌ é¢ºYx±y Šó¶Éíh+‰¦S”KrèdS•ëÕîǩðñÕîŽì”É ÿÝRaÈ¡yd¢Ðù êžu ÕgÈlïûï'º>„Èâ/o ŒùLÇMМIVµü3ïG_�c²‘ãilâ+$¸[R ïöà¥m¶m*cT>Í™éë3Øß¾G=E °e2‚3® eŽÛŲjµï%^m>š€UpÞ ©‡$7Q‹h³…‘ ¥Ü$Ö([-<䇖~¸± BÆt¹+}0óÍoóǰÉMK˜�ç@Â<Ôüexç³:µ }2sÓz–š /|Òb>…‚áàµrJ&òSæYvØv¨ÄjnPÒ7ˆGÑ0ö}մˆôž¢ø»l§ÜÒž÷Ú2ó ²<¦—²;¢(uÖÚ“‘¾äì‹©ZZJ´¾·—‰AVØu€ˆ Lh�·LÆ“Oúò³ÑžnõbsNÏUÜfE!A_Ò¶°æCŠE=Q"»ê¸sî ¨’,µQê" ûñ°žßD/ˆñ-§ÿé.¥·©‰w`Ë´˜ÍDÚžï3íþh“–’éýùß�~À²$¡�ƒ@‰ß8ºóc$PÇqÞžûXkOhËy™÷§­1ÄŠâ»çûº³ªÞ)éðÂüÃ{Se™J¦îò†!¾eÆ=m ^ŽEßÄç“qh G¸Pv§æ›ÚL“WRc•¹4A¼ˆ«7ÀÕ¯ަåSank•¦ ®å ©ü9Ø4± ¡ÊñÄàÇᜈ³™šÜÇ{xM«>ƒ;îþ)VûŽ8oƒçdß:ÄAYÑmö Œm?(ŒSÂBi‰m †|šÊ°E†r¤ð7:Tv5~çtü*Ä€,ªXö Sħ/dQ}Ý,­¤†ÎZÉ×@‘µ=¨õ®¯òÍ÷ÇÉ£–iºÚØ¿âꬳq ÷Œ…Åáñ×î1ÔBЏ<‰iÕorÏïýƒ�ùq2dœ7è�JrQºÍÒ&]@”â{èå·pyøKŽ3žeáгX<�;™5t®ï2¿æºí =«½FèuòëuÒ¯¨M¾,A-Åw¡ÇHÅÅøÜ‹M¦x=+ÿÊ ³]Bà5ôó"±(ÆË»Eï ÜÍÛD¦Yö‚fʈŒÕ =¹`óß)ÙD•! ´/ä‰h´‡ÆØ€-¦*3h(ß~GÚý.cyçºñ¨é†9¯2Þ‰‘³Ž'Æß?¡'†øb�¶]ç8+—Y¬© yÙ¶ør’ôuþï:Aé@öKÁh"ru ß,\|9kÞ¯0¶Ò‹Mž7£.+í)/×O*¥*Vf—;¡ÝPBCCG‡]è�µ@ˆŽÔÓDòÒ íÔUp"ÐÃJÛÉ¡f º‰y„�î„­€½Çjûo2-!ñ Xt›€_xHHB8¶uàOÍ ½~—À+&ZŽê‚�ÂÄG·á%9îKÀO2ŽVoêY¡!ìt“ä\ ç¯MÎ-¿±Åa›ŠŠ/ܱ#oHWIhI£ ⤦3ËÀ8ÑKä‡\½Ëâ|±˜1Ç-¨q¾†òIu ÆÚÒ6fÆh·$@=òõIþý‡Š‹~†À/1Œ ^d™ØÐ¥¤Ò¡õWE(&£Á�o)¤�ÛscRÿ;| øånÍ�¾8Ä©ãßeº™Â¡2ãô‚tkšõ癊Óô‹§—ýŸ²0Ââûà+³ [ƒ”"Bã¤̲䇈Æ~€C4˜®Á.�ê†rÔé˜è«ª©¿Kå…˜X½ïñ:‘Ø knåBöMQ]ø�›î�˜ÁWs�÷…B¥ìÆýVžáRà]¸aç$—)\øMnøùqÅ˹McíG3mùå?µµŒ’UõŒé¤�eiéT�iZW` �¶5Mc¨Z3�–%_ *Cf14óˆ™Ëd­{nãèËâTÌ#RK C/(QÐâ›Ú°Äõ4µbÈwÄ{ë�†¡¼Ñ€Ê{g6lµ¤jœ»r½5L°±=(&ÝYr%èËKkÂk¬í˜{'Õ0^íÉyh�ß«‹2;¤ø^=VAèŒúÞñžêûm�& ¾]>qçü7äN¹öø<-¸D¶µSÐ)íšËø‹á{!ƒh€>Büž&ÁÝÊ3uÛ‡²K}÷&âIØB6Ý~øÈ[��vµioAþS ‘á¯eHÁÖqk°ö±zåc¢]ЄÔr½•i LöZ5˜âÄl®$³ì6º‚Ï ñ ÷#᳄<ém�„¨ÛÏKI4N(Í„ipÑe(  Y�(Gè‘]¾µŸàÙH²×²z:.�OÍëYJA²éx º"M…øJ"rYYÿ„ÕÁðÿ¿ LКóc·JA‚Ö˜î3Ï: à.’͘c)xWf™ðDF÷+´Ø“oÒÀ@UÿŒ£&ÙzÒ–`2wNý.==fÓ­US¥Wê-^_P*¨¸Öšz™®Vàå™ÂN’]ª�-z•DÇ•Žì @Ñn¾¼�~`/ˆAFyMtï+§£9wÐ=˜ÁˆTƒÄ«æm½€UDRFUzwûc;LúòÍÕÜN{j¾›·Td‚i›/´ž£û žÜeàðkÞoäj4�^úªyÊä°Æµ»ðÈ¥…�!��Ð8™)u—ùç½#ù|­gÏÈ¥Ö.�§9 ”À•âýUò4xbÆ‘ð¢S¢×]BtÜZT‹yî>!<Ëÿ‹ö@<¹¨öÞo<Žþ)ýug†7”¤£Ç«[]q3a®ÅK#¡Aθº|sq¥fHm˜ÆÆ\´Ò†ÓêJâMÂîUi�W«(d÷®Hð™Ô|ýqžSY'_YõŒìä=^xßE1U‘QJ1ØŠ�Ò4xçš+É¡ƒ™ËQä.S[ÏÜGA}¿VPLxŽ:¶R9¾`¸lÓ ÆˆÕ¡CÌKɉÆ&ááž Ë«šåÈÒoI–ä û˜¼]ª%×àªsÔ"÷ptõPÂÛrucæõVéM$¸ÿ±‘^WJÄ•t\…o»ØnÅœœSòy8Yˆy �Ÿ8]'—½1¥”>|sC˜ ’£ÿ‹sSÒ Çyÿ;Íþ¿ˆÄñ@“óvM^JÈØãﺩ½Á¿é<‡•à˜"Žñ‹Me;OúÅr÷*¨®ŒtVp“ÏżàãIJx ömÄ™ÙË‘WÀJ^pš[oŽŠ.Ô·= Ø”Hœâxo˜÷3Ø�3 0Y.±»÷:cB7†l1S¹6²Æ¥^,u"Ä/`FáS'Ÿ®ê͆V›IPgûT{ Þ‘¦Ñ2tL˜h—m‹yf¦¼R Ñ—Ü^dѬ2W‚MÜE¸nÿ<õ`ƒ¶brh ÷Ò%fÃ� yŸ«!Œó%é|gÔ¢óá¢5@考i»iåÓÎÖg35wÈ7·ìY¬Ô•EÇI\ |D ˜ŸNŸ%>¾®l;ôИ8nÙo«s||yõÓ xÞˆ‘MŠÆÏ³ çý�Q‡S@nŽV «¥Fþö�È?¼õ ˆ-$•hÓ Ü€:±�õC´HP(ÉEv¥2Èbhì'Ù|uÕÙ^ çϓђp&\Åãøçp!àÑgT.- lDVsI3A¡E�i§í;Ì 7@7i�Y”oùÆ>EÛ-מ£²×à”)¾[!^Ò8i€Ñ…2ÃFv �@öœ~iÊ)($rë…øÑu 0h\þ”–—‡½�ù¨ªÆDç`MSj»‰ËÉ6.ï×4ê�xÜ÷‰ÃI$}Á„W�Ó[Jù |�øÑ8U�¿‘è;åƒãŸ%Õâ ﳓL¦vû‰M¨©î°¨UºŸ¢ë$DN즩/• ,(ä©ùWWð1a�'–ôtr8•1T&ßÊ Ó³~œC_@Èé[é®1 +<­Ž»$ˆ>~Hõ›’dâr¿–Ô¹ v¸»ÀŸù�9†{ƒrT*±u­�¦ä¸•ùtç⽊ÀÔ#åþÇÞ¥lÅ‘�¢_"¨çØ5ê,’BÌe ÉTtÒ\®Ó䲄» £Ó ´Ž�ôû�� û&kÄ_é0Xû¿y(ÿǤZˆåÊýr Ž¿³26»lG²�òì’­Üaïíç½S€ÅYQpb¼'à~‡Uñs¨nÓÍS¨ÅhÎ:¾™,†µi�ûñßú‰ß xÓxìû¨@Yb ÂÍÙGw,¸*jJÃò�ŸÔDÁ¯+˜uE7$GÓdèX„(K”鵤xðòî÷É`O’Ž_ N}Xm‰Îø}÷ð«uæHM–úƒ<ì}Ó„­´v t¸Ïy�©} ºm!a£’X|ÿøÊ Dñ¾£\6¹ÆŒË4oü-|Ig c÷Tm€©øi4…G´çÇö¸�`»¨ë6‚äkå­ž…*¾ ùb¼&½¦Þ–jV¥0´™Öë“0zß ý—hÿ©�³íµ:!qwÅ~’ã*™¨éñªêtt>œAb·ÙÊ ¤¹|0k|°šÂƉ6|>é{ø^Àˆ<*ºó£„qFlUMñøÓ:V“·j&Q™¢$!H¸3 Ù+X^ÑÉYÂèmYWË:„…Õ7 ÝÒlß­|ÉTÊú�aîñÖ©š}Š9ŒÇ—ˆ÷>G�ŽOÄm¼`ÒÔï}oeå×R»¯Óg­‹CqvaÔ`6V_¸™§"Isˆuû�yŒ@�X~¡’[Äð%ª å…ÍG»1¤x"PàîϽD™±» RI—Ûê3 ªm\‹Ãª7+a1`K#÷‚u¬xȼ·„yË‚C¯6ÏÕç‡mÙ9Ùt$mž6ç乫/päg4½A©ˆ¸F¶VÜÆÃÒë(htG°@]åɺzk {q LÑû`ôÏže{½W�ie¦Àí¯ëåv¬b–¯UöÑQrjÁ§#Æ`�ùã‡rÒJfÞIÅ¢–îk7ëýŠÍmy•ÖßW ¾”ÉzŸ1PÃ¥EÈ^Æt¤Ê—¦{ä•:ŽtP@a~ºª«ÌMÕHÔÌÆy‡Ÿ³*™­“ÂZæõÁRN\<ç\¸ßåù�Q]9ù¾EÚã6Kèõ°æ©r6 Õæ½i®`Ccèºl³u%]9%žÏY‹@QJêtÀK- g€utÛÅVhXá¯P�š(H#Dz KØqœ—˜lϨԡ7Œ¦Jò;\sþöNTúÃ8õÊ3…¡Ò¤ÁfŒ #É!pŠ»‘ë�y�ûŠ ‡ÊÄFè8åg�6*©‡¦–!üÑ' ˸¾YÑ~­0»ð%7€…±MÞaA˃v@ɯšYR¿ø¤IgÙh\�-Ä™Þ# DÇ{J¯=Ò4¯Ÿºë{àj2*¶lçk©.©íàtZ´Ü;Üe7Õ<å[ÈûIø­b�›*¾ ÉÖãJÀið¨' T g¿þÒÙÊi? òN©eWåÕ³$êšg»g‘+®#LÔ^ö›�"ç,iæû4,ç‘0èò$ ˆ$O«„¸ x`ʪH� Å’9‰¼Ëç–MjÌéÏr91Tû ­%`°Ü= ¥ÂŽÊù­¥c—U§©.¥ô²u¦cì’âföÂzßµA©Ì4„M&g6š@)E…ˆ�ör Eã­r�¿™+R6r\’À%ËÜ@›Éô]ÛÍ© ¿ \Úò*Cðì ¤f!»Eá�íxãÏscˆ' =hv�‘äZx�ºf¡€ØË0.7)üZÔwaÍWö(¯’ÊI‡{ûÇgD¤&Ô¼ã¿(ºà¢ùˆ$½PT¿A)þdû4î&± çéîÞ?ðÏß ¬U·ÙFFØLbŠ3N¹u˜Œ2Y!‚×}Ý‹b’²e�šÅûn‚[ÞeeS›×PbÀ—üÊaÖZþâ§¿ù1jl8%^1Íü~ÿÅë Ú[ í—üØÂË Ö?¶·‹/æì½(â$`ogÕú2Å.Û3ðtŠ@ÂÑÌ=nѱô§ ÒI$î@X�ÌœõŸ…éKB«‹—Us#µÿqÉS:²J¶ÇP'Åq#ù¤¥ZD—ý˜7EN¡]f‘—?&ÖËœ} ù26i½Éh5¼xÓzû(C”�ðz uCØŠpæðo(±c€çEJ²ˆî¤1˜…„úÊ,ÇÐT˜y4V;;0Eæ‡óÓȽdçEQ·þƒ5¸â9¨.%<@-®·±yi]�("03TndQÐ)2׌‹/Wjòd¶v¹í��SéïÖ™Ÿíâ… î'U@M WûÛ‚£`‘ùž'ÿ açjÅîÏÐDc?âÖ?²æ×B3yæÍ,õ«"4ËÄTuŽ;ÆZµÌŠ òþþïc¾®;ÐÐþÙH¯IéòÝ’¼@ƒõðwÛ•|äÓGgä Hœ5‡ŒHOÌuíW™!XºuZ–UÏFDv¤YѲÔr\’ˆwöW^°8Ëéტò/6 íKœ8ÒÎxíÒnä)]TÌC€p?“ÙY !D¤8¤YÙ¬WŒyËJ·þ ¸l(ïÙä3øÊtÔ™[(V3üQ yÎJãþVˆ üÔþI{?ºmi¢¢ëàKgúép¿V¼ÚßÉC7rm\KñÉ(�ÿ›{õÆÚà–qb‚óÍç;ýa|Ž7† SLÿ9ûí©ÎÐ&i¯-ÑÂ29gY˜ å/Â,¬£%CZOf4ÿÜM€‹¾ð¦–{cŸ�zï‘ùß‘žÿܱ5E71ʬg]6 lP£wf°Q\�UK®!�hS—È;|Œ@z¿\C*%ÖiÊËLou°AÝû¬w­ý~² íõ þÓ  Q¨Ó™Û�7«á�ÖÑzˆ)Sò¿ðŸó� 0žˆ) lF ¡†;lêªïL~�˜Ü¶­ ëc_h"á#1Š;¾-i÷ë_™Ê×¢?£ÇÀ\N�Ð(‰¸%1D³¨�hnMO\lWœC…rœÕª‹£91Ò‰ ä­Ë`‘+÷�nQÒ bÞ9T‚!8ˆÃ 8½}Är³“ý_ˆg�¦ !|T’—kÛF–µŒ~S϶[NKÙ«Ù›Â:“Ä;O‰Ö˜ƒ;·jäÚ¡êi L JùAŒ­@áÔáyµé¯<Ýó‚Ôuã7#(æÈWj–œX¯T¤dtïÀ×GP½€Ì{@‹œq šjÔ0èÌT£Œ#ÉÃþæ8X™M_‰ qKSH•û(Œˆàº?†?��ØYH” ãÒMÑ£´Æ’Éå-1¦òËœó`ÉÁ¬òs{¿*1€“,¦£Ãøá„Ÿ_>P›�IÈ*Ú;�饓ÈûUW|›¼e ”XŸ¡ÔpüÎßp©�m€»gªs´û_ÑÔ·‡¸™Šn÷IºŠÖø�ö„Hr!‘šˆü3ïþR­^º2@==á2�×À™Ñƒ-ÅQ\%¸€ŠF0Ö2þEÝtã<¯¬¤"¶Ó³O•-#a"z&ÈAeɧ “1Xú¿bŸe±77‰üÈspÚY¹Óu~ý‡$ºÐ-øI~lb`XµoÊymÅ™‘§‹?n²FÀž›[:Ë(¹àã26—Ûkt’[õ0΋�Ù$‚EÀ˜Y2Nn[{j[×Õçî D (ëà'ÂôÊJp ßy�5Q¶Å#£”�=͸Þýîº_×îiõ1Ä!(â ‹ð¼†[;+ô6¤MûÇÊ�9‚»«D¨„¿M|óîúAy×'”Iyƒ˜¿X¤FÌPCaLªbŸBšçD( Î�¸*å€f³$AÖA ©R;^…<ûýjc\Õîm;r±ê r�ý¸ð�ƒyõUWUºœ ½0±š èT3‹ª‰ç¿>Õ¶»jwíüÂžŠ¼†’'íµ~d—ö,J'½Y‰ò_EÜrÓ _ú'¥Úìò'IU’ýÙµÐ�ªaÎû• ùzLUÐ¥4ÐçqûóŽ+vtâêÃñ¹È†˜ë'k•9Ä;êØÇñùï}*‰2d4´“@KI)ÇR>EÀÿ˜f=£}'+7IŽJ_L6|¸‰–h=XD7ä3ú X ¾ÀÁ†;Ñ2xÓ‰§²\€7c¨òEG¿ûå­E«ãϽ¸�z*<*Nv5�šwøúÿ-ÜúvmÈH{Wò2F(°Œ£"�L}¹«PÁÄÂçlà=zK™Ž'–Ò8\_O&Uxq•š¿ Hç°&~£rBÔ’J{÷ëOZé:œ OÌgf6�ÿshÒö£ÁÖ¦N¼SèdåLgWuÆZm÷â#LA;jëÌg€UíQIwX{�=h"bÓDû¾©ƒ€Ú}WοÆÚo‚9lçȪA¦5ãk0¨­hÙýš5gUëÑF-äB¹qNEú^¡[SË)iü:���b[Ù7Ý®-@ÆZYÁG®¤„Áîe2÷ÐÏ „5‡lÐ!úèû\ú¼AL’Sßî�;áê賈»Qx·jÉoð§-�5(†!øwüC‹*Hte|B¨e›+ü>0,캥³ÒÚ§:à|RÝ2GjmYÙ{·ëG™«±ué-]Ûõ—÷€ ‰ƒvË_ ›è;•‹mþi4&—ý€«Ú„YFOõ®@ÈQIgUuÌa-òô= þ3uÉU‹ñèJ ÝNâ\~Sóàžíë½söpWãQ5ý(ȨÞ[†U¼õûîߪشÒ`îÆäÛàø“ÍóMq_™ùo5E VÌ�7c ®¿‘›éFì}¾æ…™&š—Žh�â£ñžðë?™vxbÎÞDé%;ˆÝb‰wÏw£‚«NK•sb«òk†!ggàÀ( ÓÂN”lêã×JV(Ӝڊ¯­O@ÚÆn,Érù&NÇ"­“mØ{7èíJ�B6–ÿÝ(<©BWX�JൎÒ~Û¬ÈÃdÿÌ3‘·ï:ÄTZå#‚£JžK ‚„$4gaóI$$Ü…em¯ò‰wP°ÄæÏOçÉWÁAŸ$[^¶n��Ô§„㣓°ÁK÷f¯; ý©‘ØŽ´ÈÞ üÓHzZ‚#5—)@ž»¹:6ã‘Õ4þïR�¨ð � ÍÒ�¾ ·'nÓ7 2í¥‰¤ƒ#Öû™¼—Ógøá_•Yá—po/äɈoØ×en�{CˆÁšg¡ð¡ÅÚŸýƒ-é@63#Eé¡¡‘Ž£N+jq<%úFg Gâpg–õX:²JŒ<éþ0:5–¢ÅzvšR«£±7óçô¹‰“ ð‚àq9w#�ÎåS)w+òb‡J(‰Hw£§7w°Îîù�#4ÿhæÅ†nÕ€o�¢Z]Æ—•;âRnÚê7®VSá ÆCWBv³©p¾ü¨ñ¡é¶ŸhÄ× &l¸—ùi±Ÿü"»+ òÓ¼eënÝñŸ.nÒ>ƈcSÍúí„î –úŽf­vÜãlRç€{6n"D=¦w9j‡)³*Œ{Ƽ…âˆ~AÃóØ^jÂŽ* zòhD/wHZ�Zy¬¼¯@!SpÁW ÿÙ× ›Èd²ŸˆÊ-Pæ;­ŸyÎ]L :·5úrRâ&)a%ôÚóSƒþठE`΋cC†H„åIƒ/âš¼¿œ'€zh£¹è£VŠ�¬¡ø÷Æ‚Í;šg€Pp.MÕL¢+{¼ÊqŠ—6»Ž:à,ݲ³#4_6A8v #€„ùü¥A;ø!hÿ$ùfu›­*2�ßòNØ`Û¹ä*¯ãâñ¸Þ‹Ö¸[XšI¥„ãàÉ+?þ6åa*b¦0A+× QFQW}Ÿ>TK²q6QäêH ³€§å…¥òâo¨zô• ÇðßTÍW„™¥ßÕZ‡R9j¥Eì JÉ5]Ç<¾ôuL:äNÆŠY åÞ²Òø‰øW›ªÙQ {R@‹òâ*tæ}ûÏ;–EëÂ}ÞdÅ<ï^ Iñâ(ßÏN.eض‘E§£­ô«·2Æx|p¼hC”'’ÂLrpã32Û€ïÏ…ïÀ<]_ÎÅâ¢}@B‡ö¥Ž <•WB�F¨F|”¿€ŠB¡�œ]+h ;å&lÀô†"W6öÏ‘Ý.ég­_b, ô>ÓìçëÁ“®À »N›#7¨“B˜ÑžîqGÿu�OƒXÕxEË5þεá(@š6ÜRÀ:²~®Ã²Ë?_8Ùç"Z[ç´qó”ŸW Û/€Íüó� ¬”¡hÍV'ÉÝ÷²Ü³U¢8Íô¿r-y�¼“cª`:ä ²4,¦¤Î|ÃüMS0¦Ö@1yRÙ°QAÖ‚ÅBð_"æ�²`+ÖÄÇ÷羞ýOíºá~Ò·�¥×Ž5]WÆ."¦ˆš òÚÐjÄ~op�‡®xneAEIV‡ß’:”sȱٲOöÛ׺d‰v·�Ú.\(20sN¼ÕB8,î¨æS㎱ñ€!��+ / Qм ¥²(spCÃ4’Û³ ÞCh�Ž$è–×E¦Ú­¼!g*Šê‹ç|˽D\ð1£¬À´V:?­€‚–o½.Ü4õ†ÑÈ V®‡P{f�ì»fË´8Œh@è³ÌA Òuý|ÇFl˜ûãuÀ›†*Ø r -ç­ÍCm{ Ì †Y}âÚlOˆC˜·hÛ]©öaàf8qô¶ECÓTPl’þ"ygm%vú4�òY•G;‡¡Ù²¶þ"àªÁ€:Ëå+[¡bÜ’v-#¶¸D•õÃÏ8FûŒÓ¸vâw®•G�jüü1(€ �‹Zý”‘z‡yTª»ì„íKÈŽ|]¼ûáI“ü*óáú³jë.*¥^bÈÔ.Äo·»ýÍ ÀœèßxDÀ…òùÕ¨ü´¯ àéT_È4Œ…³Ø,Wâ_?†z´ç) |ú­$u|hôíS^ý †¸ƒlÊëÄ9ýðSúîæ Ò€îŒ¨Œ~"îQUÅÄ#Øœ’ôúh��1v™­b*¼¤ï_/¨HP5¾\.Ëoü­‚¨­ð2¨v„ˆ c¶¶èZÞ엜″q¡›Œ g�2û-¢áyrÿ!ÂyI `¹+t@ò¥B§|,©Ý|r*×Aˆñ•·Ø/Séãg‘(ªä£d1=ð¯ Ä÷˜Û98J}^*ÁB¾+”²>A)¨‘ã ën¢ û†1`ýÕtÝK¹»À= ¡.ñ§Ù4]µ£W®ÒÜCÉAPQ$0p:Œo 4›ve±t~p9û'JâûÞÚµA»Þ†T4#ž~ÐhâRÇ-Úï!J&n‚ñHsš!혻_•Ìï¶ -Lâîà;+mÎ8�—»™luÏÂö¼º$K#{þ&˜äö/´«WŠÖì˜S iv§_;‘ó+èdÕxj©«ÿ=\s-àD¡=º¼#‚FÍämJ®žz0£@hÂH† Èž¥ÀnŽYĈP\–Šgð„Q«ÂÌ|?’¸ô+zÓ½èBQ¶þÆ-‘r€±ŒmÕ¸UÍì-!` >'6Vïêr:ŸРJi7ÞJí|3ŽÁ‘g‘ü‹Ê'Ï’×R�Õ‡êþ†Ÿ–ü[Lºåìïmf ¤˜¦¢´óIoYú“ü§»ü«Š>ÈŒ®^Éuû¥ž°��O˜ŽH³'ÓÈyY|_ Ñ@Œà©_Y éÄ×ĦÄV‹=óá—º¾Òz­´.›þ)g†Qñ.ÉǤDrgwæHÄ9¯qò"ãn¡�ªØ˜ER‰ñ9õ¹3“¾Àæ-þÙTih7�”ß”!9ŒôIØXK»ñjj`yÔ'ÎÙ‘‹>«œµlÅ“0 r Ùü|v5~cuˆbϲbœÎè‡÷Lî³ cV¢$¸­—乪PUve*ì R#? žK0P±ÅÅÎ ¯Ñ §pǃò¼Ó)ô„ñ.‹+Ìœªï¤nyiwë]ư¥(”©C€º—ÐÅ0tö/뺺ݰ=³&tólpŠÆ¥o’[ó ùaQ–% ÄqJQ3�º¯ÈüÕ®5¯Þ˜·Ò@B=#cMÊR[Ù5Ö� :wàü¡Z[F©ëx�òj‚¤P¥õÈ ¾ ×î< Ú0©*ìWF² 0�ùÔÈä_U +Üíwi–ÕŽ¼'4pSÆFƒ#QËx÷ylUsãèaéÑUaE 16?“´¬PåŸZ%ñŸWnª?Gºuªß¤.\â­¶±@ðŒòÛŃè‡üã�v‘{S>F%ƒÈ-�Oø¾xv¾II!ÌX7|õæY3“q¬Ä( ˜›FÔÿ—áºÖ®@eJ>ÛuÕý:¸té+¤ ljXO͆0ga¢@² zÞM–Âd Šòš?ÉT7¡vaN°W¹(gSŸm'’#%9BÎÝ¡B(.5çP€†û(¹'øSáÌéäØ`ÿBT�ÖíTx�íhòq\Dø³bvÃ*ZùèÝñCÈåQµˆfÐ sVq“G“ÚQG÷™qÿ�;•ç°F�gÍ!y,b¤¢ˆ‘œW,ö¢îjäöú‹žÿj¥Ê ;®ÑZV¯{™ ²C&3+Ä�·� žæA’QlX%^ùLò�Ðÿ—fïì&ZùÈ}«2T3a¼�x|UáãØ–ÍOìÛ X…ûänƒê��åÊX#½ \Äþ/–Ç�yX …ST)œ›¦_­¥»^)›Ïq¿¶,öqý’R¾ ³V¨§›£õ´Ùux ôT 4õIä^ÉmõA€â§VÌoì^×ù ¤‘ eNºïʃÙÿÁÜÔUfª�Ëä'ë¶ô¶bá5£b:J„¥�FI‘"&Ńƒ×hÚúA# ËÈŽ½½5cÇLÌÙEÐ\ RZ¤ˆOð`–üC¹Æ!µ%¢BÞ#‹ú÷u—~èÁ8‡„º(: ¶ +ÁEAßÞ37C7ªkƒž“¦Wy´àdÿøyV—%[k`¥FߺÁÛ�}fK¼›a3Ûs‘îUr5@Žt˜þA¦|ß­E ã¨)><®Ê°J4ËeSýÙ¾k¡C€5ñÁÔ¦ØU%j> àæLØ�tÔAk†ýËôZ¯êX¬P3x¢ÊK/¦Þ™$+‰“pÓ4ëýÂæ9­úíTÀã¦ÀÀ7K|g�\2%÷H¼”®5Y¤…^˜(�·kúÙáËA�ÒF¤D-;c’@ž„Ÿ]×lÜM¿pYþ¥�îA3@ŒI‰XwD¡rU4ßõ!8Ñö›—ˆ†åGSÈÌ8�{°*â9ÀÁrxN›šãõ*ä“0«™ ÅâÆ’» ÌvpWËŽ´öÑ(G¢ Z &Z‹Ð�z@0ÃòØúY»èJ"<$�LDTÚ@‹’«$Wõ‰õ°ñµ¸ ä'ÊZ=/Åþ/ T>‰ÔõûS€6e/¢kâzY1jÚße.ækä ë媉.D‰^AÞyuWÖÆ1äS¦_7ù¿2¿ ÷=\Tce§"¦°’ÅÇ×»ŒŒ·Í�3yœF†oCï­ô“ŸÔãëÖù_À¸´(š7jè¨='ÞíªXÍ.¶ý9“[~ˆ•oq+ÍaÀ³w”'ÃŽ:ÅÈH ¦ésÒ÷6°Æ·uÎó vZd0¹-užÏƒxÜŒ~®¾¬NgK‡Š‹éaÄM2×µu™Ó!B’³Ë_‹ªfÔ'á_Öµ`ÐX¬Ù#œ§C0Ôwî9_|Ü‚4¬ãüP3’¦ýŽqèßv‘̹?e¤ ;!£ªÁ“ü”«ÀóûôÊŒ…yµ/;⛹òðÞ{Jܸɨ0‘ÁÃßc}n”{ÆcELAˆNã¶ß;3‡×öé=¡~ E…l)¦Gކõ|”ÆÂ†Úïca­s™ùÚ—[z.�ѧ×€o${�^ÏF^GXíi«/ ™g¡ p…�çŸ,ëbÍñç1”3ÈŠšk!ïz"ÃsÓ·oÏ„‰vzU][§Ô+s†®ÖÕjÞ|w Ë+u<`lÝÜ´»êö¶¿k>ö$-a…�©.áieÏn@p‚ÌÐÆ¦/ W”ëýbGØJV4#Þýåõ)MgiƒÔÔ² Ô‹ú%ùÃçǰ¬€Ã¶oÞµb×Vt M¢“Ž!XoúNdwë¸C]È�õwìjó § R¦þ¸«müÁ‡,.ÿµ*ÃþXÌåÁÛ¾+ yúýhÿ\˜¥¿y°›–-J>èÀÏ×Ñ/î4àΨT>`Eeµ[v¶ªYQS� Í7¸þŽ-UÁº|‚�]ÚÓ[(½œ}ŒÝ¶€³ß@°šdvvN ŸŒ MÐ*ƒhæuÜiÐ7ùZ¡³?=lc} ^Ñ}'‰ŒÅŠÈÆ–-‚¦¸;G&J‰’éiÜÿcã ò ÜÞ¼†¬A@Ncw˜Ë1$®n‚Ò#ÀÚ¥É Á½L¬/`¸(<©ì q³"µ+&5–8‡5/Zˆ ;äd³y¶‘ÓÄÄm^Å•?7ëö‰Ûý‚M’-Æ3P…ì1x¢5¼>�}@s\Ø—nU|ËÚ*­ˆÖçϽs�/‘¦Ï&òàãV�”•üòìïõ…E­Fþä¸h‰˜pÜ”ð,Ѹ åH<˜à™¸Ñ;ÖœýÎÈõŒy+ëWÀæä:íóÈ 4Þø Wíû£nã âéžê¯-R·h\±×®l?0û�Û“ªªpµÊÇ èFØ\ôNø4Q�SÇN PöMÿð „-¼ŽûJg€Æ>Æ«÷îÇÆÃ{8b9Ö)…¬» (ç‹_í§Iµ€ÃX8È5Å^  cÿ"ãmäÜæÕ9m`ìš Â°ˆ‹ä¥Ž„ÔÍ›dÔþ ÂÀuB5ÂDlî稙üƣʰz~\ÙzÎH=+…à+ƒ:¼-§ýñx*LP¤™ß¦Žû LÞ/b�U(ãìly°~དྷêb«÷þC$³¾†¨órYز ÷û,ô[Ò¯,±q!…}ÖNåAù}‚•ZqÏ.ÝôX]øo6�²Áµ ϧP$ ÕiV@C|-™#i[óq2Zõø}ª;•ßÍ2µ€±CÙâ¥!Í Šõ8˜_eTC‡.åª`0ãÐ…µ$º=Éö쯣(J76 cÄ?@ L²Mào„m]—±*Š×dÝÓsò\ù—iŠM?ÄØ²U‰F­:BŒ'ßLú«ºÏ•#VA[¡Î~AaT¡£ŠÝmcuÝÁ�ÿ‘Ã…kÈ(³¯Ãgé&0‘Ô“,|‹2¦£vbBÒ-Љw1ùyÖ]ŸÉã\Ô,³BNýÅ_=&þ¯Éb2eD”[ÃT5ÖÐe‚ùè69:¢ðšÄÀ×^óC*}M&R\~v‰”ÂW[‚N¤ãgAóÖªlQø{8l1”ïlyq! ‚æt8¡uáÿ0xÕ¢'š5�s½âýú©*|9Ðý-½EÎÒÈÖ3½Ñí§¼Ð>Â*ö)H7jgŒák›5ôsFê:ÍÚ'ÄKÀ·¼=¨ÂQ¶uŒ¡øÖ„•äo5R±¢ßõ¨£*ÞHôÐÇ_ùíýŒÜ5”_W.¯Õÿ¹0ÿ Ü*¨ó~ Þq�q?À«¿(n¥5ë9ûɵ?‚uƒâÑ/qÈd½÷‰®×J$«Ž NLT(’�;ìV-¯íÔZ¬sÛ||wÉþ�4ÖòóK_™*šx¤#!¹3ªÉFT®-‡Dˆ�(¼¹-1a¦ÐöËŠ`È<ÊO3Ÿ ¶Îs“€aµ 7¦-¬É6d—9ûû%9çÎçå‡~â½T 7ù/ùÄA€éè�Éͨ9è¼î�þ�oÇŠúv¦hÏ›>BJÙÇ@¨žû~™ü´³F¤£°æýèÅÈZq â-¹ôÄRáÌö\Y¼ÚTýrìäæ.x¶ˆ>)×~îï‡ VóæOR*Ä»¸Û…ýìAD��Tú}«ÞÓƒ \,Åþ˜�¬‹©!±Êˆÿ‡"´—¾“éþëœÂÆ.Ø`#øiróµñÏæÏˆ<Øþ£•€ËæÊ²këûž%1¹ûKÑýSøgur5E˜Ÿkì›"J1]Öt� UÚW‹có:[²á½–^äY¿@y7<{ð!X '•8&*‘O iGC¹HŠ -Q©ž|A‘qX‡†‹#3ÝC<™ÆÊ.X2Ï(¸P˜á%�àçq3 ]ÚwQ&XHBù :¾ØRÎÖ9¤Žè2O€ßHfPçK¼¡å´û”a³* J$ýðµŸ6>O$6Eå—Ĩ©¤n»úËH}†Ê Žf¦h9lÝ*fúΆŠÌ*—@©@�j~³~…–Ø'z‘ßô'±À7¥3ì¸ ÇC¨³½$+S:F x]ekìñ*æ­‹«¡UÔì<Ýž² 6dÏV:¼ÑCÃ8KÞq®Ï ÒÆbû:¡4ŽwD¢¬ÊèRÿ‡ˈ‹u)T°OÝy%8}g)_wø IÚYx¯åu…tþou¥'Õ ²FL®Z&ÇÂ�×ŧrËg³±Åi–jäÇIfhÎWy˜|ûÑ uâ§ë7¿ øßΠ�øSýäë•'dUâ®ê‚äÿðÖ3ϰßFJÓÂZšXï�—ää”l¢"³Àú—L-åa­T| º;Ç79€wkËL€Ç÷)Ù�êÑq<Öµn/XÒ3åñÒšm�è8«¡<Üvšê“o^ ‹‚ãœ{-¡ªR?—&u!­~ÆŠGH–M‰¹™ìž%Þ8Û˜›Y’•­#i1¸¯FQí™Ï*žˆ"Úà§ÍØÌ•H¬z%æ ïIž²˜ÅcÉÒCøES’†íÿ�„»ô .ögTG«ê €…?º¹ P|£â½H;]J L/Hšw$”ÍrßdçL™‚^γkùâkÔbñ®É¿ÚÝ·3X—²Ðw'm§Õo”Q™.k»µ?*ÌØ­¹w{$úVr�{›0È ŠßU‘òz,À½Ñ&ÃÖ#ñN ´¯Yê4Ü�äTh?:\Ït@€ë’ Û "Ç$c¨:‘+M‡¿ñÃ#¥¨:<›u5}ÈÌ\”¶àýÎM U;Ö^³ü_^T߯—je7Wù¹H2æ§#™Ð ˆŠÞ ?6^bćìy"<=ïÊ Ç4 Wá�åìåÄb¯l§¸#ëÛ÷>÷M…¢»™!y$JÇUvöýšÞНY:\ýHyÕ‰$?„ññóæjx �ä� 7‘ªƒ>ŸjDLe¼ÙèâÍk|¨ÖÛobENu!O6Q¦xhÅig�ÃÚó¤÷Qnõð�â}ß§Ì·/)áK�Ü®g÷¬vÿé‡kŽ›ŽbRó 4b:’ÏüÓŸó^„.Œ¸«¸ÆæíØÑH½F 5ö%²géozp¥ž#®â�6÷Ÿ³î׬0ÄMd¾;Ùóäç_Ѓþ`UÖ}w±\î �õª/R_¡ $¼ŽJªßU3»§î·BÄ>åŽhl�a¢J"ùLlÔ;†V0gäcÏ>ÄÎó¶9Ç�BNˆà„žUx¯CÏWÎ'¤ïíP…·…¼ß Oð º!PÛ‹EigÈfáN ”¦øQ‹§T3Ÿž+ÚT±O¤IÜFHiz�s´ÊîG3²ðå–‘Üz�"PvÆ o™.WãÔ~¡Jør1ÊŸL»ÃÞ:€ùµ»Ú‰>/@ƒ×rÕ fˆæ¹�¢Þð¯Ù£»ö.®}yù�G7Ô¯øêþDu3uMžŠ,›ïâǵƒl®£P! 4œ gfU“ª·©zþª,M¢vn€%‹‡V¡e�ï„Zí̲Gþb|ö¸•æK.U+qõ'ç+ŠünM[�NZWÓc¡:¢•ÿ?°;èý0��Û!ëtàø\0O¦;K½yg$§xC‰ª—ÍIHL³FŸô-¹Êý2+*æšÐénl“>ýÆÎg4•ûéq䲉ïð8%0F8',T”Ý-Ö•§œ^9¼W¯æ<ÁX9¹ž©L/Çlï`£y|ªp‘Ùn¡Ê©¥-½GÏoc� €Ô^lcœ”¹¨ƒ³\´œ"µš?”Ñgeäÿ4› Cê?úÑX(¥ Fž†Fh;YCt -–ûC8X²Øfƒo°‚Oλo½³ÅÛˆ s?É$#¹mðŠ#ŸòdæáZ[ÿøÊ Cg ²•€‰h,Z êL¤CLÓ5+Và�óÈ{€nj9eÞWÍ#ã0 5é <¢åE9 p„¨ídNL÷òðû„8vd#PYÁ¼^ìšr½âÌN3²ºR‡lj¡î<4ç·6¤™DUˆ…@Òâ™UéñÂÕ‰O@ö>°‘üÛPB‘tãuzƒLU…’h|¦‚¦Ê0èÐ$z™«z¯P(óØø5K7À š1"‚�žIû@k‰º0º=¬å®+vP)E+½©M ·f·YÁb‡Pú'ù+þÕÎ=ÅÆpð5‚ø`F£X´g�uL²Ô&¦°ÊŠìîMå�^;Kf@þ„Ô*{äÎÉçõ Ý«Ï)ÕBÒ�Šòt‡+awð(þQS§ÖúÓ5ñŒ Êâ±ì¨ó ƒ Ѿ™¸FL¸y¤ç¯þ�L±vßî7(¥_bìK&Üqú=*é1 0¯~ˆÌ¼jž®¡;iN<Éc”�=i �•š&Ùºßü�½ÌÚ;0p�f|Ì—¦œz�W…ýØ0¨žXL|]¡š_“m†µ0æbÓ£Þ_ÕÆ ÌpKO/<7åJÄÅg R[�péñ�ãõÕô8zuuxø–&D³z!êD_¦u•íÊàs"×þlÈÏh}Oݓù{�ïq?*Çí®;„ S›ˆÅWS¨Æâ6OíèÄÿ »`g–îåàõh°þõø>Êg%ƒQZƒˆ‚RæTjáâÊè8�åSÔ ­î�Êš¿ä˪` !lüo<®žaíõü'¨2¯u!¯½dìtñ³Ç6¿ÄéÒè“Èu÷�ÎqªÂ³ì…aá·iïç3s¦a—Ov<8”Ýÿ\fîCçò9äÞ� :Y ÑŠÕg ðÛµTv�Û&‹sÅ™ÅrÎÜz†cÝb[$”‰½vƒÍb>ÑQªð@es!‹åÍæ¹ovÂ,EÔNT3Tùu†¶¨-Æ[»`øOyU+—�y9ÅPn´×„üérðÎ%úï˜×LÙÛP­¶fƒHO&$8T¯»ñ�¦®¾çXW–Uið7?[%ÛAäi(¡Óiáì±D%v!”ËN“_o’É<…oÁÕò»%ÂW‘!€™#”q?½Ìÿã_‹±e×Ê +|õî ÿ_ùÍ;¦žî¢(3[šrÓíáÆi~›€Â‡¼Á¹ 1wåtí:iÞ”�¾Ùó¢¹{©<å?­,UÔk±™yßá¡Iß“\KÀo0üm:;̶®f¿¤î0"ükÑ Æ_õ{2ŒNøØ|¢í£ò¬¥zÙr&he³ŽàùoÉmÕ@7çñp!Ž/.�g1²·y=Šu¤sO»wšuaPA³²®£Å®@iüXk‹2H>­æ¸øXÞ÷±Ø»»¢”ÜGwZ;ÍnîÂ?TɽD~6V;y-C¹‘Ë`¤Q½'\€šæšó¾jÜ{ Uö2¦O£OÂ~ÁåÈ#¿íJt‰âê?ö\¯Ç� ²FªoÖXbÕãØÑ�få¨~J|OLØ¡4løéôôÛД$DÆQÞ‘k�bÈ›Ur*5ySlOßiü49Æ $}ñѸ½â¦`g¤ØUXW8ý±"üˆÈ ôv¼Ó¨}D½ƒ•LÍWåúùžÓ‹¸�‹‹Ñsïk¶ÔMü$*˜ÎoL°¡A¡¿ i½QE4)sÄ¢¦¾>úWªó*`Ìlüšwê£gÀÖ­vóƒò…j[[ıé­ÌJMrúí5§ž¯ YJ´_“ÆÞ51+èð²Uœ Ý_1+nérßöa¶@d‹º3Æ™ªšñÀ•Ad8ýµHWÔ§­uÓšÞòüípê“ÑÚOˆœ)eåÔ»“ô}Üéh_[sÚ'æ] d| ©:ÃË�Äö~k•*&J*’9C[íü[´µ&H5‹Ðm™i˜.¼ö=ê2N(/ÕX •@”‘Lnï2RtíAwÛÔ�xçñ«õ —gm%¥åÒÀX÷—lÓã ®™ÇÖ†‡]þ>ËñÌ8c½vWœ=ꆑõ]É´óéI›>ñË|¥¥EñŸ¡�E–€»½NÁŠPùórI?”‰î=M,lSè•[iÕ¬™žâÕhø ÆÌïü-›÷AtžyÝL h¼ÞÓ>¹CyV{ïÍ�ïÙÅhÏ2Ó¡1Mó×ö²fk}°ÌÏùªËÁäÅê–Ã#±V dv9¸Ijå1g[’NÊâ!ÎxëÜ‚'Dˆ2e¡ô·½nMAò~|—ÒŸÉÌ¡tcMØsçdño 65—•”‡"È�<¢ ÉpL¢4É�:×r=ÌÔ/³„ “ëƉ-OØ =显ÃÀÀ­8yXÑN‰‚Žf«ÏˆÚÐ XB\0DOa÷~ønm>nˆ´ë>Ï_ånFKY\ßÃP/k“äÌ禜ÿ/Œ’å0 @FFW `«]�~E)p3�8™+7I»°,mŠ~ yLlt�ÏQ®Ñ~JšrÎØ•a}ÔÅq¿y­Rw`pü%ˆ`‰�8áÓ­¢Þ£&ò©î¤è6H¬4ÜyàLJ¦WÖ£†WNg‘¸hq5 £yª�0FŪ£.ÖkyL©}Ä*ðƒã#Ô_ðüg!F® d·ü$}8+»ÜÓušÛüœI °;FpO69v ì�÷¥Œ±È©6’tzþv' òäùîÄ3¦çô_��m RW:0Ì"k·µÀ¿ ¤ô43gì“#˜Èk �D§™qÿL\%|vx‚2ð†BVâD¾s©rWKØyW31îâÑ=Íxv.b,f³>¼´4Cº< ±\�©<š“·JŽbŸBCúCË–eõYù (M76õØ-¨ÏJãÈòŸ—Ë•‘…݉²ÌX•CÏÇ￘<ƒ¨1ÐêÔ‡ŠÛ l�TÉö€!¶KW.ƒÂã�ò( NŸhñF­�…+6jdYc¢f"•�,ôßgÖâæ² •�F>a¾òv’¬ƒ¸jfg�Oaе5 Fä˜Ó†jâ2##{ [Q‰ÁS§¤žÎú—pEÆêâ’ ÕGê�%4Ö”ª×Ç�ë@Ûk‰à™’ þ…>×ëo04ïÿtè­Ì!¨\L^"Ôp–Œ­´&�€âABó´Zrô€æ04ÝF ¼6�˜yËO$»6Ç <5âákvü.ࢗÃþ˜u¦ƒj¾�–�ž‘A‰�ñM!Æóü’ZšÜ Ш]e!Œ‚ ‰B¶›ë�8Àê íWÂ{¯E³Xz–M§à÷B¥h7©ÜD;`ÎØÃ*€d`,Ñi"G7¨“˜½,©xÊ ÉÙøVˆ£YX¯ÎY q˜Ì´Wõ³ -MSy/Icôò–˜¬zHÍz2ñH �á,ÜÛ‰JԢȢ: €ï¹Ïš§tûÝ$¨½ØI¾(ß–z6œþ÷ãòýR4>X(ßÙhÐ\´ßȲýÆOØÊ.Dùø”âs>Þ7`ó3¬ûõF¢ý�QDEaˆ`÷ß0u&„m’ȳðt„‘I_ÿ‹ÖÕû— `fÓn�ÁpiY[Søï9™B¥ø,Æ™¾} „ÂÅÕçËxfuyb¬h ÞÄÇhÖÊlR¶F4Ó‚’xêïð2(Ä2UÿýÕÉçpDdåsA¥dVΊMtØ­wlI¢˜?=™.ßxñUð°³ ¸K-ÄïÓÝf‘i¢§I7 z#‰šÍIî ÏͨµÙ —é,@´Ôõ Ú5ñP[²E#ª�øì__vV]ÄÏ‘ \ƒ]†fŠç^›UKpˆUšÁ�ôËgÄþÈØC"í•?Pm5 lr_©ñ„üɦ—J:ônB�¶Cƒ*±‡E¸Ä¨ew¹z^ ¯Z@žî=ÅgtÓ+ü ÃNFÐB?·ìÚýñ ¸LÞ<�2ZG‚ÍÿÃ`n!ß)Þ¹Geè˜ £Ã!s¡ßg[ËëM»n�2ÏúwçU×[¶€¬ŠðJ&·ü—ñ«HŽÚ*t­c\œÛÑ+UCN^ÏžIÍ«kwV1Xï]. ™Ôãk©w‚° 9ÃÏè+ÜΔ.W£8`#(ÁœÒ�°ƒ¢ ì¾õ>L{ä_m÷àwALÄÚG‡*=J¸­íüW=Ã’¨�Bb?8ì’sϺܴOûÊCÕPâ]i¶Eiha©ødEƒÝ¾Â§Fˆ*�'�Sâ@ðü[똗/Ș=ïÄôÍM@êNK:?ø*¡•EfZs1‘J¤YZçj…gõ$Ë w½¸-¦‚mGÔÿ }áµ �‰!hH¸�ß.7(e�’w«ndÌ›þyDªl¶"´ÎD-Uofî>x“™)àbýa¯XÖlˆRë©â)gK‰†«B­/û©,åÙòc.Î5¸ñ­Ó7lÀÇ £»:XÕc—®ŠC©°2áê°g¬¯pï×|¨ªÓgOåÀ{ìmö¿È,‚ÜÿÃNËË_�ä}©JýkŠÊÈÖþÙÁmý&7 x³ƒ�[ûtp0ý0]~F‡ æ*gÙ®G¤èÒáˆc™X _Dn§ LÚ�£)��¸rÈe ª›Ê±Ö9,Œäõƒû¹²XólãõŒ*±’”i»´§ZØób=£BçT¿jçþòíOHÓõؘçÏŒëöXæð<·ŸÕ-¥D`-2¬‰´[¦"úýÈ[ÝiâµÐ ~̨§ÿ’ÐZ)-£�„ÿ$€x;‘xî¦Q$²rü¦ 4‘œÖþ6è¯qé6åÕgô½…ý.˜Ã�àbGí�JJ™Q-×â`Ê÷ Ð-ÿ•ðƒ`0öŸé-µÓ—Þj–Vý¾)éÈ�þxÆ™}[dd¸jŽâÿKÂÅ…ÃB°ß8ÓÂá(‡Zÿä^^¾¡Ã­ü"s7T9~ʸPË¢öx‹s5�.šÒªeDÕÄk×´;µ]úÏ=GUT6ŠmÎJ<¿‘ÊÄ’"£®?úŸêQw(3ªÕnœ— ËÕ:)*ÝÿÖî£b‚êMèrøþ:Í9ÓD‚ʈá |Cm ›¥Ä’ÙÎ�#ˆÙjcW]Y™¿ ”ta�e˜} ðoã)ëÈâÍ%#ÑçAƒ?.X+×hn»ß’™.d7á1ÝÀ*#“’,¹ŒÄ&=9"ç’r�<¥^ÁÂv6s6à)™Q·µFh¡01¢q¸NuJ‰rg¯Ø]ú�Á¾*ÐEªH³+p�ð#c oê-žZ£@L;Ÿ$3«±¸µêÇcÅFן’-±TPšßöXñâ0/|ò­þn*†ÐxB%]롯3;~RßqŠ<“·$‡4„?Èù8$Õ9ž1¯&d¨«#üÕØIUÕ°èW‹„šƒ=YµÆKí³8þÜ�Ï[Ò³Tt żT‰m&gÕ¶sõì(@!" Er饶ãâ:žœC9Ü¢'Ì@Ó²@QÐu'@ÔÒßìÝ�¶ùÀŠÈÊÝ­Ã�Po>åq¯€›sÝÞ0gãaÇ—¯èŠšHHvMŸïM§ÞËÚó߯ÖimÁÙò�e2¯Ý—"CÎtT™sùðLäg3¬–J:µ ž¿Úa (Ž.~+J.0I&¦ø»*hÇ‘ �Ëê~´`ìÿÔóݼËk·�qçÍ­Ýz|khÂoÓ/±1È�·t� I)±.ãdùqv¦~5-É“B�Iq£:Š>Ž>6Q@¬X›e§ˆt­*TPÔ€sÚ$µ uÑb²˜ìQýÃð¥,â‡(Í^3c2„A×Ùt1ŠY�¾·D•U†«rrgÊ",.ÓÀÁÎ]VŽÔK¥îu»WZúÏîl\†ZK»-èNÙ ÅÎ<àÉ–›uœ5±SÂn­8'"Èhìˤ_QgDZo#v˜9 ΓVÆüMY3ËC÷…X±»Í±K�”«"qqªd¶í@N“—ØA•êvÔö 4W=�çÒëU÷¤ tíæµšT@£-ùs=Ñ�8ð" ’EöðÆëÑ’4(`5“C7œÖñÂp_W|Q(Ф³âê4Iσ�ƒ5tz�g°«ß}�¤AcG#¦=ÔI,zœE„I²¦_ÞäüWy¾Èn?Ÿ![ .µAh”fÅ.•þ4zìï�接åiQ¾úµ{iTjÔÆô*°‰ÏLŽóÒ–¦(ÕÍ{V­ùÓl¯dŸ¾Š]óÝ·ËÆÄçÙ©™ÌMy­QøâEÛ÷3xÌëü"ŸVdOS¨¯Ïxò“ˆN�7¢~Îôj±n!ÖFH–_û÷ª[Œ1Oèê1"þ둉(0 ã½¶$ DŸÙg¢ŸÕv©Ý·ý>oÊ,ÞÞÏG66ÌZ£¢åÜ‚+fí÷wd§½ëí÷+ôrnùK`L8¤ÂµÕU¶MÇñ3´Ø k]�Š=›¾øŒ›NÈ„qX·@l±ÃBm5.�”,®?Ý^àŽ$Îu¸Žþ7%ÆÇÌelŠÆò¯Ýs‚ŽA î š=tÓc h¥Aɺ}ñgÞ‘ ÍAØ—²XöÂ,A¯ªÄçÐï‡møhLd¶éïó 5¼¿Þ¸Gâ„8äZbe´cô‚î®/A¥"%3ü� µ™5óüËÕ'Wß‚yX§q{_O>ï÷:Ê(Û.Vl–éÄ-gëáÞïÔ©¡ZzKï7ÅáaŸ"HRÒ¡£0ƒ¦`î!I#ÞwÄòÑièþ¾ùšýN žËm˨sº÷¾6 pVžeWR�9vfN¦w?B%xÒ;öúµ^ÔseŠ*Ÿ ƺŒI+Î…p8šÎ|½å=K’Ô"†Äµ+^�ãî”H~ñ$˜ágÂùÈúp}¿µç S^}]'õÞš„ÇðÛd�Ò¤­Ãà¯ìº�Šðu½æ*´ž8åëC.e‹‰dɸ½f#üìA’4Б¦ÿç@`÷†õue&Aéé˜ÒÅ'@*ò  ò8ÊN´c*å˶V”Ž}ñqžÚšSø°T޵/€á´ügue.m}w¶%˜»ËDê)¡c1æœé×_^vKÔ‹TqDQT¸"ô!ŒÉ‰—"Á±©RÅEÍ,‡ý(Ô°v~}ãËý½Ê]„³ uMð#ü[›j=gï ‡`uíKãF‡*ðœÎA»1Õgê#Ca`ÖÎe÷|�u åEvíÂÿ‚×_÷ñqmÁ¡âò„_:�MŠÃ2;å¥qÖ|#ø§tâÎT-t“WˆÕ#)eò�úí¦&×#/K; 7WbQ½íë‘õâ™XŠÁ§Õµ°—š®h�p/Ëßý˜„‡e³æ#w™ÊQèú¯FzzrxÔ£ ÿ‰±MUnÝPrl�ƪ�g.‘1\JâB£‚|¤BpöÆëëßxí”Ì{†3 â8…øägó\‡èÉrÇ™’@Ê#££&éºÀ¢Ck­„hS‘"2%˜ÔUÏõ_×ï��9¿¿Á6cý‹PÍv>.†á8Gæ l ÎW‚›è= ¼ýθNŸTì’•,h�;î¢elnÔBíñÅêŒM7wŠÜ~2ŒváJIoÒðx…zŒmýßwÇ97ÁÁ.@–â¿òÞ_Vm;fl úêmbQ/¤hdLîû‘ÃáëF…g™Q†Ó�! ¸*•ç0 ¾=Ú”ñA–L�ÛFY€ñže ŽØ®‰˜�ô{8¦ÀOáªÞåö,|¿å“°öHö؉+?˜¹#)´_zI ²Ÿ¨öQµüÆ€¨ß7E˜œVãð=)ÕÑð+Õ�§ø¹åñÞòfeöcgš®1²;¾M¢ýÂH-E°ø”zâºúØ×T:_G¾S”‘ÿÓN3{qi1hkz¡Q†.Pç‰G#K#5JÜéÕ¼æÅÀÈ™t/ÞXIÒ  qÛ£ÃA³ q€TøÆD!¡a̵ÅI•î{œÝLÂø°é#F*:’hØ7 ÂAüž½E‡±îXÃîshKrÁ=äa4¥G`pÏÕ•ÔºÁª¢à¥-ã-fqAæÍ½_¿§±ÙÁÒVLØA¶û9.ká�#¾EËÿ�|Ià |>¡ÖÓÚ¶Ú«de-ÓHÕæ¬@„<LjñJ‡†�qÃ-Dt‚¢ y¢o´ðƒâÇ×_o²�­!çyJ‹øL­õE‹Úi‡»bJ<’lÓ…ž›SLê O&2I#VÌ—5ëN0;-Í‘®ÕRœ¥ÄéEîWÎv½Ý‰�¢€ù&à#ñ æ;ë—î/ITuô_~Ü&Û˜�Ñlt å±÷ ã �Ò( ÛÍ�Èãôý3Ñ™ù�U%ý¨‰E�up£Š ¾Âêh螺~ÕýkÏÁJô¸�mÀE†¾Ö€äAA“·ÊW³Š*fÌBóV˜ýäßÀÈ-¼Z^hœó° ôe©©ê‚ï�÷ìG(r“#&WñÈ÷~Z›õè¨+G &þD%zy¼˜ôš.zzŠœ ÷œ¢óÉ ?ÞÔŸó�@Úéžø©™[¦1ô^ŸÔÉÝa$¨ü·QÍt ÈÞÐ-nÅô÷вZ8¨ì÷Zyâ‡Õeðù#í§QÒç&•‡›7¾$˜OÃI4¬†ºåûÒžxÉ™Aâ‚Ù¹…j­öUÂ�ý¤Ÿ«˜‡×¾ÁbJIìëÔq•:r;¹W¤¥ÇüGÆwþä€ÇŒU.Æõ÷ÙŸ¡Þq?ÖRqóŒ#HûŸ‰GùÆí^¢©w(<ˉÎÕàËj§V¿¼pȉGmû4hC gŒ²w ä/4°c݉¶«²x(Þ¾—Œmªšè> nËÓÁ3gƒ¡ ôOÕJ¬9GukB<›ê }z«BïŽp†fËâÄkÎL¦%Ü*GÎNL…«ØÄz·¬~±ƒBåó>Õ»ÑUWö®¡Ö�§kœ¦3[ölÊØ±Sô˜Q;ü#7ݺ‘ìÖæ%t-Ø9–r6×! ɱ�öÏéV'vòK¢Uú'Ù½ žÚôO[à 9°s±ìœÀC`.H\o~³ñ„¿ž&êá µ£1C¿r�³vEGÇ=�È�›åJºGв5°Ý•ýªoáLJYŸº•,oDæ$æ0Œ`4Ç&÷æ´^y»ÔWŽ}‘©È^Á›`qIãC3£/Z…±:„p]f ¼rlèðóÏ+@¦Z—<„á“c�ŽÉÓÅ¥Ar[¶_%·÷ûÓFWƒÐ—ݨ¤®”—š»ØfÚ‚È*°¤er ­j³ýõÿ3n—§{˜€ˆ¤»Pv¯þC!d¹A3Ž[�u´ðÅ*»yô}‘ÛAávGµä[�ì~½G×ÌR¦Ö|xÕ/zèR±MÑ?S•]…´Ýaý>Ç"( Ô#×ì<®¢Ov¨¼8ž·ÀaÙ.�Ƥ;Up_$aÆ…VN!ö�§¼XµÑÛXèzí&î;Þ— šy–7ž*1òó6´ Á‘è®Åó£ó‹+–žå¸ÀIDžÄ|¡’ó2vpY¹\›ªJc\¿øÆ'ªôÌR(ò/̃ß—�U¬Üæwï1ès«òš�êÁ™‡°9Ö?‰lÿƒÔÏà¼E^ò(ª4�cü¤®ªµ›{\(4xûèr;M+˜l¿QÑôÅ.´'or'<ªÁ2NöFÛ º‚OÕ”H$(dú"wU?p+CÀ›�Y�0J–.–Ö½S®Å$ç—.ó;S n5”ƒü£Ç»úºÒ¸X®¸é9(žÂ£»ÔXú«3RÒÃÆQÕ¹ÔRI^vsWŶº1!b£g• …W—Ùa˜ô ¾ u‚­<�Hžì°øcÕ$w8ÆZîùñu„�°ÄÅÓÝ£?”"Ìž3#ºKìø¶‚f]‚ ÷‘½OákŸÆÀ5âÇÄÓoUR¾!sx›ƒ$E¶œAÕ½¥ yA´8¥ éª:—IL|ÀϱmÄ4ð—A@« À·SÚ9"ç+Mm“+ý ‘ÀËGærêMŒ9so(Š• çxO-mdû‹; +¶¡�Ú%¯B>Ú$Ú�™Üe9Iva£Òõ„² ™3tÞåãÚꬤ3ìOïöfõ·=SUÿZ�¡É,S+¦ˆŠÌÆ;Ràû›rÃE8ø!8FFe휥¡Ö‡øwþÝFfnAP¸¸¢=À¼™üÀ +ÇE—&Þ­t˜èÁ�ÑEwÕ*m×Óiõ¨ö¸DÆû‹þ\­æ6 F'¢ãLX“Ê$¦‘[´*t=¤úP(ŸkHm†±y]¥ ±KÔЬ²®7 ù¯ˆi1Çõ¸B;Oîsl&¥?k¾/jLó¢³—¹,cÊ´¶ô#¨5ŽÐ6ÞõÌp½ð’½fÖA?Û.W´½&ˆûLD>c‡úàu«-žÅmÚYo[M¹©`ÀÏi„Y˜x€]¨sÏ €±2õîKùÀçñÿfï‚Iv£1ù¯ÏÒyuÑȉÇdõ9v'B�“ÃýdÚ‘r[öYÎd®Æ÷ôãã˜TõG7ÝU•~0¼.þMël›¾`λÜù÷)�‰L}\`|&ðã¥KœäÖF–Ó3•œY†H^Ôj¨^�¶©Áª¿´� ©}ì×ùºGôqšr�[ïLåûSVÁñ$¨ÙP1Å©˜ñ¿# à=�ÈÁrUÝ› <˜«×·;ên�z©¸¦Í %¡(E%© «l)"ìX�¹«N�‘¼Ã„4êÄ1% ì~0>LßÞ\A™`GÂÁ[@» ü‘Å›Wý3¢“µp¹Œó¸iÕä ‚?ÁzJð Ia¶¶žøtÆm’:w�ÛÆ¡G" 4¼7‰ˆ%/9y´Z”2wøß[‰&I%…ëD™f}ë�¨¯ÇUÅÖÓ}L=÷$U‰�r&ª!XÝñswµ•9³Hš­L�ο!%¶hÂå”»+‹´™$£ŸÔÝ,~ÕáåŸ7Ât�åƒmåÛüDFã+‘\ójIpôÚ“Y³ wßäÏ7áúµJ(°ª±ïæS‰Ì[gRùÈ|XgÚд­ƒjZ¼ v½,þB¸1×Ñ®Â?GÁÕ¦|‹)ÌÐ^#¼«Àõ»Ö{­·ž»•ŽâŸE.`«f—|ôày�3¨Ûý 䋊ÑBzÖyd¾kWþXËX×I°zï„´Kë7ýrOã ¸§½—ˆ‡LÕu .�óÏ s~íôXÇ¥f·ð/ê;»ÀÞ[ãФï# „Ýã_¤ä¨RçÈ‘P-(Ø`»~+éµÀ×;€D¬ì»8üº;™û‰¡;—cLDJØJLàŽ/z® Ö@®á¤.‘Ý4Åô}ÙyOIóMxTdÒc»ßeÏM˜CaÄ÷á|i€æ‚EoS8v`¥ltÖûk—ü�QRÉæd"˜tõ?ÀÛ‰>Öíõ‰{Hàk�Á÷Ÿ5©P�%–}Q®×þñ¬ù¹^DÓÂR¦ÈpX:Ê0/;ħ‡RÚrŸRvc/^‘äq*~H¹±À´‘?»Õ ¤ž3ÔsÀÇè³ìÌPsÖ�D¿ÿ1'­i9–4}d¶lÃB§þN!æT춤^½}¸´.¸éîJKËÞa&Ž_23 ‘n±ª=­SX Œí1Ä8};Å{¸zzE6]ž¤G³ cgõ¬ r¦ÃþŒ±“[Êô´m8F™8vìƒ í† ÷‹ x?'U;Òuˆ,Ó¾Å1™µ¥œ ¯Ü ¾î�}úU¾ynöÝú« ·™E¬�¹†•ô“ ëœNlæÇw覟ºâÊØˆÎ¤×ÆIV�ž¬ 6‚ž²kpÏß™e�.êσvÍž »·�V<%=&qPa޹p>4CÃß½ÇP`³ùk"E9*¬Pî÷¹ü»—y‹»\Ò­ÛÐA,ÇÑxhFk¶�æäÅeW&ÅYcòJΨ|ÕPnÊ$ § ¶ù\á…ÅA[¦O_4RÏ+�‚õz›ŽFT@®LÏÝ1Ï…Ú”OÉ%Z|Š’ ³²Û}Eµ $}'Åœö;к��9_©Pg;|M‡ÿIJiëÒ«Ë-1“¦Ö”Ÿæú¼4Q`»¡Gò‡ýuX#˜L#õÔÅÜèã!”ž«ÎÕË„@EqÃ(t*¦Èzv0CËyŸÛä;%UoÀ—iÕ‹HÓÀ| '€šŽZ ƒ–Ä¡\>Þ%ÚPö.0Û%}„ F”bì,5‹q†7æ§õÒŸ²ðÞ™bKýQú/¸ç5]M~þ�9Q$¤§ÆÏÃß�>Ñ·WqHíEÿµ.Í!Ö¦ýó•¤ j¿—Í›öØ ­Jb:ûÅÚ^êï�¤ ÑûöëúG2x0Æý¾�Ü­Fw¦ãz?ËŸf¬ú±|ÉÂݯŸ }ή'œuè¾û�yóx<×ZñG×@§Þ?5{½èjóŽ¢ÁôˆA4TÞÝöŸ å3«Pl1Áwº–g’`Îí;Õo㘠Å4~Uš®ooè+¡p‚æ¨&©™Ü¦F­¾n´Ž¥kÎÓ±QíJs�GbàÀ�V°:∾÷!˜IùÉ=RÞÞšL,!ço _8á³Ç˜¶[hEmÔ€ê/"=K Ÿ0šàTÂ_Eîðgï¡jv[¢R—ÚNIN㢉II„ƹ"—w˜dì÷ø r±Íu�•K-6Ãa=e€‹»ï}TNÕ Þuoã÷í~†'Êž[ØøsAnvg8ÐnÖpJßš7fŽ¥:è÷»•ŽÀq¨£w€•îáýo7È´�g¢Ãsøpg¸™ñô6áʹ¨]Õ:uÇ…æ0Ù—%÷ÛNGR£¼ �nUù^(µtî* rӻ̛eÙ¾µ¶¢Õ‹ªÒ…¶ØTëúš»˜-!O‹‰Û”NE±A–8p=Ÿ5û…7}¥ô™üˆ„E’Û°VÿZŠ7I �3D>©¾çm^AÅó÷ž!{z)R^aµkõlêaÜ–8ó‘Ýa•�ɬˆuÄ3v‡6u²æv’fhN aD² ¯cÓÙý”ÓÎhe¢f$��sä® µímu®G¥«ÃËÁ¢˜¤*éüÛ�¥šù¯Âz�UŒ�-ÙÐæí6ufSé®ùÉqé@?hÿ•£¸ðñ×sq&|€=bµn÷½÷=XþÚ›ÊYb:X )&³u-ëm)<«�4]¿ßؽl‡¹ëGrÊw·Ù¨À‹%Ôý%ö!k¿ƒiCLÃÖBãà~ç>Ùí(½ª†þyƒã5û;»�XÓ×0n\ò—Y2–ú¿l×Ç9‘Ýè54“Cl­ç”ÃLh²HTòm–yì#§(Žt`.[½�]Òšiªý „†�‡«Ý#›ˆVnµhÁ¸«ˆ*Ü©ÃåDíÊ5cÍÉÃö‘;´æÖ\L{h}ñ«©ZäJ¤jçaàÑ¢ 0z³*-p׺xÄÙ¼L—Ïj3ëxF+ŽΣÜrÄâš;�FYwÄæL Ìí™ää,ç7wG„DЦßvGFèÓ¾pš­…ìÇ¿“‡@‰'á 4™;Á]`%ñ×ï¼#ò¦÷1ùûæ6Ó^xòUSЈüȆ .Ω¿ûS,kk Bªtàu°ß‡‡¤†[õóÅ<Ô—öÎW�Rz�Ä6å²jI»VX¸h?KÞOÖŸ_f°ê8õ½ù³på8/àCtÉ)þ÷Oí¾4ïPx‡„Ãrã«ßÎwÙ­FÔhZÞ~'*pxÃ"ÿò¨I õ¯eyTøÉH",¬¨èô(�ˆT�*vu Ëùtï@Çl³*Œ2$ªFÆyƒˆÆ�Y6€û3sÂJ©_…wàWÓ?eБG˜þí£ßà™R?ï;/�¾´ÿ™“€eÀIwâÊÒ�47{sdr@'‰¬%ÈIfž¯µé›`ZíA¢IZÞ³Šszˆ6…Ÿ¿·"=ëóÈÔ³¯³¸€`² ëJÀÖÇBø/ã0ç=‘dé�rá%@¤å©¯� û °Avª˜+xWñe`9�Z‹ „J»ôÄA¬)N³(GÏ㩜´cg ¦xH“^ÛÒö‹±CnÜ[Ió�,Sæ„G ¹‘Z¦�Íï6AW’¾Ýѵ–ÿ‰’s½8žÓÅÿ¾+ ò¥Nx@™M>/CÕ䨼ÉÛ2®ˆ“ÍÆt 6–3¬_Ö˜2“%Ð’rþÉOß�z¥Ý.èeyfY·ÿå˜öÓÈa=£¼Uî<eðÏ§ °LoûÆD.õ‡Oþ4HsøÄ -8àz)tÇxfäLët¿`Ô0q¶-ÃôHfOgG¸Iåd�D„rÐ&¤.ƒ4HÄ‘)“�� Aï�Ã6Ïï x‹™*[ï�·=LTŠhÖc6ð\?[³'ZÍgª¿ù °ï·ÊRÕZ>‚:´2[žÿøÊ JàXÃÊY­Ëë9dœrY\¤³ûÑ1S?˳]zz¼Ôoožã‘tõ@^ޏôŸ2¦‰*A ¦½°ÝÌA@ÜÕ”é4t×àM )ß«)u² ƒÃàÒ¢^ˆyL» Ì.Gú+ôR™eeËT«ºrZx8<`)ïàßY‡iOápÒ_&}D»O 8¸¤³òx­çSIô¿7Ytýr¼, þ« î…ՙеõ:ÿ�ýK®f™èPŠ’*vÈzÜô:ià�á[œm„¤¡ îW‰•É%™cÕŠe—hQ€JHY Vx¬ƒñ¯¿Ç%æŽÀ�³½„ Ý8@®ä,vÌT²~ Šm4ß—ÓKkÙGw—DŽ10µ¹'¹£" %­ß1î�ldinÙ}3»Šk0©b!l¨®}©a aÖþÀ–\ì2“ÀW‘ûäõ4Òù[ö‰,Šh9Ãö@‘´X Wú/äþ´­yM> p#ã@¸‹š¦©»íŒÎ(¼êo‹V.öbu©¬ak'¸½g'Âî0‚ŒržqCÐ"ñžÿõr/÷sy«Ä:{Ä€TGÿ#žÇ¼LX:µ+žTy¸~3Ó ålKJüJ#çWÃ\Ñð™ï-ä0)ÚªßóÊdüO^É”Žw/cÖ.v»Êæ­�§1—<æË#G\s²˜&ã"¢VCî†Ümø}ߨª”¾À>˜ÚK¶Ï;ˆ´`·Òa~W¡ïv`½eƒ6ò^¨Ë‚âÍý»QÛ¯´îØ‘ÆÇrây€˜hoc=…Бø'õ…ž�ýíÿ{|UÎçÝ¢#Ô’ú*G»Ö�Ç‹ƒµ—ñ�¹íÿ¸¡CYÕ'‡´Œ·ží?5é¨w×µ4wÀ/‰€ðpeoe‘<ëÇ‘FѶðYçJ‚RþJûmCmtœb™gMRT*Í¢àú~g½Îòío]ºXÃö²üµ®ßØÍ„ø^ )\†JéVj¡°Má‰oõã½K³R™{~‚D¨�*y.¡¼ó ³½§=˜k‡»O�“èØö„ä±vA¯ü½W¥èpè&>!@ânk'ŸP:¸ª×¹ßÁD¾F\7[ç¶ž4p#ùК @iP%"Õ5& aÀu)·_Â’ðÜ!Û/ây¬¾'�|;§Ùœt°Ü•JжOàqÍZëÐÔ^’Ëò‚NémãÖóÑØ6Ñþ£G™i@Úy__çyi“l žÂM9å}Ù¡dcçéˆ�ò�ä¯úÚ)b€¨Ju,†$Osî•à{HÅÚ®…Ò�ܼ•è1ü½ñŒ‚+¯Ê8Ø5zôƒ·‰‚о†G¶{Áœƒ_‚i]�Ag Iy½I•ø܇­ƒ1ÕC�þ”ï¾ÑìÌ*ðÄc�Ë)Ƚ ¯âô½Z(­'Ë´q¬z�êáR¿Dg*íÙ%t© 0‡Z)‰Êº‰6í’ñ�ô«˜ÍÝXP}�)ººî+òGJ3 ÛΈFÒÌ‘µO£²ñsc"&™Xй"Bì¿ írýVnŸ¦«°e)!îZ+ymM†Zà…ñ5Ì|“ÅÁÛ`à~“rÇííÊ_*y+âÉ{üÈc›³°æíÅáj[ï¶ ñŒ°hðoæ(–‰,Âù(Ô²h·Î.†L&wYNd›Äªõ2‘ms!H_ƒi¸›› ÀÔ]e ÑtœMßéÞ€Cˆ§rÁï»bTŒ¶ìUë%Qö– tußîcð�¹L£7ú+‡æ a=Ÿ\Ôñ+•p¡+s0@¤„û‚×(•{?ìš~º¢åÞá»Î‘® �ôäÝzúÝGsPk^ KD~±"�N æcgye� ³Kx‰¿†ßMºª9ÏŒ�¹Hrâ{WçÎ)¶ir!~`©qÎÑŽ÷b£ðÀ;véc´`™mmA@¾ìyë·Ã¬FO#©QjŠÄÓEzg�ÖæIÈ™ÜÁzrÄ¿#©V÷ãîê+†„ίb¹õXÕxAÆ Åþˆë/U°™õSãJ‡NZ3|ª ü�žÑgG‡: .’'¥ƒR–f$þòL™ôÂvTrÕÛ½ÊeZ“$Ý¾ÛæúäÏ ÕBƒ/‰–µñ\Æ5O/)ѱñþoØA}áÒ23„>Ú³£4.w)N@³ ×ÖøŸŽFör0v̆ Hô¬;’tý}¬ó3üá<¦Gž¼ ?)ŽêŸdf„‚ø{Ò¸¤»wd˜M ˺™B5¢¾XÒ<`N.ņz½7m…bÌ’žrÝiéÚè5O+®™H\ƤD[µémûj¼ƒ¡B(¦è…G�¼áŸ'ñen©¯±%¹>ŒZ"e{jêoé�–c÷pÛ•’:ë2×u8Yþý){7Ó¯SÂE€ÖÒ/¡þÙ!�˜fn¥Ð}áãgD^ñ^ù¦ªefïCc_ùØg+�VkkέóŒ×)y~‘S²Uc{V+õ ""Ê5¬¦*kùköì^_ÜèÜ>î2 ŽìÃÍd#HL&ÍËÜ`ÇcB›b£m“k Uȃã»ãKg×ù¶ni"ä¦Ü£ˆ—>yX%0»lñC›ƒêÉ ªÆI‰M7ða\�YVŽ8ÊQO•jL‹5܈ðaTá#íîÝfn !k‚z�ó—>”=~¾<[på=øê{Cü?”&Eu¤­L—EqPÌ‚&ê­Ì¡P¬î™\ÓUŒ½¹ÎøXÉØ 0IÁ�tŸ ¶¶ CHZqüÕÝå—FýzU¼œI‰ XiÅúî#óa{æ h�&Ÿ¿‰Èúû�]£âE²Ýëê¯ÏtÂS½ÈǾ”Æõ¢²]”ÇNÌFcIwq!¥‡©(ïwcA�fG¤gëïíbA°¢ä!ÄÄuHÑ¡_ƒ8LœéÂCÚã‚l!vü×Ë™@¤V`H/x#�… pÌžì,’4 êB5Xo¡mÁà3؈f]¾[C#*„^V^«w¾8d[ø°,c ßÓzä#söS‚kô(�½hâ±@^qB²0V¤­1*¿@êÈȲf{[˹w="*šþo½Hàf¾¡,ø*ˆÿ)ŵ�WjA\¸=L°; 6&’0›Ö±•‹cÚåÂÖ9… *ïM&‹œ<êHàBÆoÃÙù`“­YÈÈÚEÀT™ˆˆ¢iï  wL¨º˜[¼ÎA+æŸ>nÂ);ÏÍ#1Ÿ¯½Ëks“-‚‰£ôRKX¦«“‡Ýkˆ§}o³�­(@"^ÇÀq²Ã{ßÉÕÒÖóQöz˜Mz³®»2Í3‡moŒ"8bÒÖ0Ö³Ï4Ì .øl.èêB·¬™�Æ„ø¶‰ýlt€WBã†`‘ŠšOøât£y»Œøn]f ›÷™§[ï)36:(—PjtóÜCúÕc¬KX‘{î.H© Œëéo¶QÔÈ»ÝÆE&‘H®ƒù *fa¨ÈÜă2½M]ÕFÍø¼/kh©c̈v s›÷ŽÑoK ‘cY²¤ü½Þb)¯î¿Ê„m\râDä)Öù6±…¶ÆøóóTènô'%ÍŒ-éäܽ€ΔA[WuN¸‹Í â¢�[+ÿà­§ èÞÞ²šãœôJ þRÙñÝG¯9~8õw=.Üd<úEÐH*¥÷£Få åv ¦})AxVRÎ÷MÔÂmÁ#@$á7=Ç(8ÑZ#ßôv<ÝVò,hW›ú>ªs•w#~Yz6dôŒÌ�fغùY™�Ê:У$RœÞž£gb�;¨èìš·ZàS"ÊÖ@û•´�ú�?ÑýßÚ¸©æe²ÆæEïÄp×^ >Ñ;uN¶f’m- §ˆžŠŽ›5KDñBròåFŒ>q6?æö¨úUT€¨bf}¡DõY/òÜü–Êg)[ml áø&2§¯Ú ¼Òžš;|Ïõý-RǶS!(Â)bg–Mq¯ õ]-¦¬Þññw~hÅtž¢Öyظzã¿K<Éš¢Ri…¥Ù:@gùê)1»(7Ч~�¾$»ÉÚk.Bša¼WÞ�»®�æÆà~ì eê/7ca+ñFõ�Ð Ÿ•Vl-!<Í:.Žœ^&cG…×L<ÍÓÏÙ£0ø~àK3¯»eB‚=Ÿì¹>}È't¿¢ˆòËD)íiWÖ†^ÞsUõ†1ì¢ÀÞtÔÊlò%èD¥âàña�EÌ‚ÒUêkµÄ¾69 .…]Ïø~éÚ¹X�Õ=>�-Âæÿ@î+[ZG”Mm%[¹¾ÍY_YJæi¤Ü#í!w)×iu¬8](ÄWð (�h ïºlßÈs²î°ô®¢¹¡ ŸSzÊöh­X[7%‡S3·ï.uøÄ%¨•¾ûhSô/tiø;ö·ø-Î*Ðë-2ÓM¸ ¯‡îôV4 @ÎbÀ)ãû.]Ú�ÙP„BaËs^݈’d)ü·(Á–H‡á�°=jír�IÐð¨20kÉîjÌ4'6š0pFïE›‡ Lº©ƒù0ª&ùÌF)ÃÙ Y79 g]çó*þ"„̦4Ýkm,g—4_üüŸH-\YÇÅ+iÄoþ©ß)Á»%¼‡|ä�Sy{ø Þ[›&nžŸ¡£sÊ‘Ò#×a¸RÌ_"}CSK,Tï²70øX\f€ºÖ›6-üò8 "Ý8Ÿª“–8I\˜B æl>æK‡ÅåRÝ ­všRò9�]¶Ÿ·ýHŠFÜ9Í"ßBIè¯D5s–ÅxxÃ�vã1izÌ‹—ç ÞzA�Í):4Ö6=’Ôº–Dö·[Íø…¤Ý·Ç|•’ý ÇäCÕ·PR ä 2q`×éü!›�4¨ôIjä͉É9‘yûïîê@z­oZ,²hÃKƤ&¿–AQÀÒ�v³ãq|ñ^dÍ>�ØHå«qÁ lîŠ)ÿ0ÁEƒxËסÀMŽqûM8:;{D æ àÈ—U(,ß|'Ó&BžœßUÜN­2!ˆ’æÛhž[¢’Øj]¯Ç‡ÕË2Aïõœ‚¬KÏoùÚ/l0`Ïf8ÌêÅ;zꀾòTgd€ ²`úDÓ¹){¹¹ÛÒM»r–ü] öy#q¶,´; ó?ï¥ gvTמ‘ÕúL<åÈDÏŒñ%#u³Ø£4QûªT¡•t ô.%d}Â"}U“t Æ~]¸(‘ç.ñ>”H�~VÊuÄ+cgþ²¿T¼×ߤ{s³8ΓÑ9'ãâ)û‡0��,s1fÈe@’^Q¹¸7ì©­¾²‘?o ÆÀµ½;‚D·}9E*Z}¨iªu²sÄËZf¥Ôš(Nh’+ÚAÐm€ó1@h bGŒr¢Uv,$<ÅbÏ×àŽó�mÔ"pnˆ¦Mî�=�Å8=œ¶;Ȯʑþ÷D[Ú�ÇYÏI7¿{7e¨Ö¦"Õ±¶){:–Šô÷³ En¾v‘ûÂѰ›ËšN#ÉÝ5„w0 ~�ìòƒ¹‘FN×Àù¾86»DHµ'ð…r·(O?N›<(묤ûÊ(„soÉ$NÀ£y”m|çuo¦}]=• â«ù] ê+,~rû;p—¹Œ—b8¦¬Q!}í~ŸK«óV'þfÈ¡[#¢ô=º‹L"„»šæê}¸5êx$e%KÍ�ÈÔ2ÒSÇ,`\ýÓ°°#át—'6™ÙŠR Ék%ÀY°ñàXV¹T’c‚qoÕñgI½ù¦™#�‹ù5ÊÙïü›)‚”ß<€#Èb€­1ƒ j“.Îÿ2@UKá�„"3Ó:».¬ ëÁ”D½ï¾ú,"Ô¦Tv½“2‹Dí‚’D‰`±ùäE½Ð­%d'`wê"ôëÿ�†°8ÎF/PÃÕú½zÖûrÛ-¬É}-Žäþ‰*t`‹z­·Ã@eI Õ£ñLZ®1Õý4=ã%+Ï}mW"Ý39W/eóƒ©D‘.ŸD#üõÉ`\ÍÚó »™:µÁÂ7Ö—P1“(KÕøŒ 0¬Ý©Ï.Ä/Á ºzë)¢™+‰»×T½4‰& ñ–BØN5Œ£ ÎFßø (Z3×—x;­êzÃ2%†ž6ÏZq|Aíã–ªiKÑøb Ç_Ù°ÃÀí»É¯Ṵ́½�Ïó[!JpVtG6�gãVƒ~o*½Ós  W ]²ˆ eiBÅÞ~7G @쵓ôòóŒ"ÀOók\²â[–)_¶õÈì‰ý¬¿˜xm!‹Ç™ùÀÈŒ\B)º÷¥(ý¨ÒÎî1_E™ü‹$Ͷi¾tü!ñrÛ'–ÃS ÆD‹ Ó k,̈ܤ!‚œ%az0wg>⥯­Š{‰ÐæÑ`½à‰UGÎ]èÁ–[�i�­ †÷Ï&h.|¿öŒj@³’@ÖÕיּª‘? ؽ•a®¡]Ç&S“ d½*DKº€ß=·¦ð…›ºP&'\Õ€?HÖ×¼Ú¯©öé¦ËfØ—š¡"\9Yèp\$ÎÀmꤑ‹jÖ¸ =ÔÌ=Ò0qÿ"XYNÃ=£·ìáè[BÈÇ´‘é‡Ê�N`7½È’Ϻ€ŸXZ<ñÎÜ¿‘ãÒ«i:Xrºòü%¡êóÚß�â›O¨`ðÀ]qË>!(sMVaÌÌ©«üÇ%Kd 'ÓÃ?ßß‘ÈGí*$Á¥ÿ 'ÅΊ—¼Ðÿk@ýî“Þî!”>'QDf�’,„£V „w÷ÍåøŒÍº£a7œ‚ÒÆvpe�eÖ6x[—áÖÇwËè l:ã ÁxItýaWU'yuåÁ¡‡�>ÑÎÆç�o7=ld\’pCh}~sé¬Ê³?\Cζ-µërk5UI—Þ%n{1ƒ!ápÃPô–,ÃWŸdhsòø,¼B|R÷—ßåàÿ~Þ¸O½ºY`“JóIÿõúäÙ]J±hÕ¿Cʉo4´ò7¬…à·€Oeéñ+µ¾nØ�G£¨"–&CŽÿ«W‚û¨�&|ïÒÊÕ¿X{°þíñ/Úo´nJ¦Gu¯—îüv8A Pí_ZT™„L]dçƒpeÚЩÒóUÍÀ*îYSœZ^'8�FrQ  z=~`Œ½/�m¦†P!;es*Ïg¯}ìÈ‚ ²{s�þ¿ƒ×À“!Y�U+ÍQ&0)Y�L€~8pâdÞ©­Áì‘`€ÚÈqç¢0ì+!|™”n5z#¯>ü±)¿0–UðŽïÅub Ks›7¬Èrîü4æUíB#a-ò8—Ž mákZïùhsîÚ£YæÎ&§`‘¸Ô6wJŠðv”ŒLÍ… iøPÚSr�Ò\–A^è‡@–!“©ŽcÚX)rYùÄ=-�«~$Ê΢¨œ.’üÁа}¾¯ÓªNeá…NÝéwÿe|4óÝ3½¬Quhû”cZ `—É2YÅà�?•DÇg@ö¸Ý§#o»ÝÏwËŽÀ3MÞT�ð¬|š+@‘!mŒ;·»¶· ŽzX¼~˜— ôd%­e�sv³p³¨žüR‡äÆNÐT„=“ÉphXhAŸÒ€ÇÃPÝÊmÙ¾KìïAî³Ï!ÄRäd8ócÃÙfº{sUÑ~¼Á¸g˜óœ=áG"»!ÄP{:W1¼)šb¥¤Ss¤•èhœB�ö¢œÂ²( ´ÀÙ3ˆQ›¸‹G^ÉS–�¡t]Q�o¦œ�ÃíÈ$=¾®:ú‰`/¿£IåÏv‰\ÀˆôDgüàÏL¼¨P£Â„œFA{uZ‰í³Ô³…´M[9޾aL}ÙÛÄ·¥ ÐGâ‹–[ Cõ(Ç[Ï~XJ'™ö¤óÒŒ‰F´ÿÚjg> ;) ›Ÿ…t¯Œ.µÐAÊOÜÑÔæ3ÖŒ¹·îÑPŽ«àÁÆi]{À=¾¾gEÄyìð×ѪX±$ë3âô¿…ïÙÁ¦¾¸ùÅWeM:Gœ�³•õÿíL>.ª¨eWœ×ŠŽõZ„oüZˆqoê¡9Š1ac†4Ø*1ïS´P£õ“°ž|Ú¾aòÜuÑ·´”ØÉã-kó�’âóÌ/®‰LþªK½o� �2¡Ç5óvœÉ¡§¸»�ƒ(¢Öú�M|Ù+´%ÓC€VN ì‹d“'ª ,+b�ÖÇnYǔؒ*‘ÈÛK%ÓP,„úõ ��ÁAùFÒ]ÑP;w³jÁ®åÖì�Þч¬±Óiº§ÅÏ…P²°oiüè …óÌùS£€Ùà‡É`Š­_£wFx«Ro�ƒÁÞÅ—Mb=ccÈ¥orÅin c¶Ws3ãùêOøªC7ˆ@¨·øR¯ñ>›ÙZ}n²+……«ºúËc¶X7S~¬�YËK錋l`o‘¿ª�zÕÇ!®°ÊбñÎÕ·¸fíÇ,ÿƒ)Rù½²÷"5\(�EÒÕ\o¶ê҃¦@CÁUÍE¾„”äpÀ)¥¶DJê´òâ =/»ë€‘ÑCÔe0žÏ2E¨3æg,‘u#H\Ô±ýVNkníÊŠúŸ s€&çÆ&.4©²d¤ñ7 KP£—öÚ(.P‰ÝÓ8àY™2»•gP¹²·vÁ°ÐqM‰® ‘„õñaÚü'œ ÑHæÔ3~ϵ)Ê'¿ÜšØ#“¨­ÅÛ(†+¼Â‚öGyÆÃÑsàõ#±ïìÖå˜r挤¼ƒ~Ò A�ôüÊ8†Ñ¸¡´Œgñ;æyþN@ˆËŽOßsã•k¶CñÔ|QÝUðlÿ‘½£{w'Î0­ò<6¨f§hr,ošÃ(ºjç¯ls(œ†äú¤A’æ[Èù€¸ßsËNÙ&…›|HGDéæ ¡oElð‰Åmaé†l6BÕh+¸Ýí6}ƒÐá*¤¢$¦>idž[ïûÑØÆZôVŒFewÄLNîÉþâ¯U–Ÿ a¹G ÇÉûsàÉ´œ] )öw?¤b�°v?Ö—ÇI-Ø(—A™ùö–ÒË.CT‘åéÚ!UàÓ† ž�‰´ê�{x¾fCä;'ZÄ«O7­”qÂõH‚FÐ'›­ŸÌË—nß —B¾`£Dé©"Ã�qÆ‹ÐE À8Õ!T^˄׷í>å²u�ø88ä¹0IÕ¶ú�Œß6š^Kú|T§Ì\+uœ†|„Œ0í÷€{þ—¥©Ù¯¯&ª‹=Skwú]T:ã876c²™d”%JqN:è$ͦË[ Ë¼êm_ö´¯š2zÅÞ˜öCº~ k¿”“•Åm=±IÔT‚±c ‚a=ÍF v�ôÂw·Ó,ûժˊÚ5˜"ó0átžTÊÆX¦ÔÄVBv‚€—Õ·Z,—F•Bf9\Â-åþpwŽŸpµÃvëŒõ]:+ƒPŒkË@ðÔˆ­P¢ÄN¹�),¶í~YU€AYB”=C´�—\ãž^Ø”EÚàŽÚÝ´ÀChåÞKÿ¹[×4ʲÕ>X‹v䀷Á ¥öüºDø˜ ‹yg±@a\Œ¬Ô쇡‚ëÌy3ÝBÕåæ”;7áx¼›­7¼�Ö*,Þè�êÒ.Ô;Ár‡G^³òcŸ‘¦âÆjOõnáŠ<‚§³À"=nwé$nô -ÏêE}ùT!3Æ8ðk\Â¥ Ïå¿þ**Ê*©�ò‹HÞø NOUt¦FÒz(¡ncÿÕ%I-½!&Û`,W’¹´3~|_T—’fÝ)õÕ¥¨`ÈÞ§ŠÉË‚3aÔæ öÅæÍæ*³c{$ìQ/$? döÞyÆøýË­3ðÒd7i§É ÷d3Kôò­Ÿcqú…·$*…bèX½=,KOÙX2%Uöî<É¥B…†Ph8ÆuT[°a.ib>½®q¡žÂ †ª�^«÷ƒ‘yPÁ™xß�ÜVgêæM\¿å/ÞÔdù±¶y�ªå%Äï©z$�!W?áüj•ÉOÀÛÏËU_Ë£•F‘83/%‹:âùþ#ŠÑqZ ‹C‹¸¬©Ýíå™Ea!ƒ~��7ÝÔø†�QJF²~ aÒ:çßj—Îôu„ßHë“Ða�f³Å¬áûlub&Àæk cà[”š0(‹TG~^pSô­W3× €È#ã‰~æ_x¹!VDK²P*(æ�^™¢äÓ‰œ¦Ã€â˜�e]g4ƉqÎò#—P'_”Ô<©°×…KYÁ�¾Ý—Kž2³Aú‡š*6 €º»ÒsÕæ!s�岺"kÊ»Ë%Èï¤ö£p›"ÍúŸ<Ê•½}YwÄ[1Ú°Ê€þœhÕߢߔýÛ¥»yЊž¼Î@�t,i)wh!ž;½cœ–�ˆíM‚ƒMâô$;qÛú¹÷-5Á8Ÿ±Üt/;¿-q´4"’ç•4„più¢É\ö±‘7&ÜJgŸ×R.i ¼ß¯Ú<÷¾N± @"®ˆ¯_¼°K_ÉËV$ŸÌ4–$™1ëÓÓ5y}œñ22qÆŽþJõüÜ¡¨{²w…�žŒ{+YŒ³U!ƒ®cDÊîöTæû�cZ'ø&Sì Ë fì𕆠7(}²Å‚$� mÁ#�á…[îÌ “ ^H{îcW_Ôì U3}ã;u{#zÆY¼ÿ4@|¥‡ÌßåCSÄšµ‹°PX�ù§zDà¦SÕæ7CTßë¸Zm -…¶H jaͦº“L¿ãÙ ŒA \ý/ÊŠÕ6ûqOÕ Ë«+ìúü VÏ’¢:èî(Õk®òFÞ|¸OÇ&¼f›×õ%ƒÂ�~LžÆ·g já¢b=a. bªâ,MF®'œãîÔsGÝAm¯é´0þª8„„hßÿ׌Ʀ«7@"ôÎ¥û{Ûò<Ìá´Ç%í�¬t;Œ”¥èwA5u½3©Ê¦¿-Š“.˜ç{å".ñÆ8ÿÕˆ‡°h,»­ßh-< fí)ÏANs¤`Ð>1® 7ß‘^Ö´1ê Ý†ºHÆÁVšòcKg؇%¿š·Óû‹šKVOh 8Úoa#5k%qÍ8SP»égý0‰ê¥ ¸d ŒDD[–°ÃÍ�—3ðxÓ_ðœÞÏ+«#v‹‚—"VJê]ÆCš)…™ìIUš®'ôÕ+RW­«—Ýš>냱‡É‹Ì¤UiÕ& ö[�nX.-•ò�ná´u£–àX�‰émóê�ŠûùGH0Å¥¿±><Ëo„¯å7LK±U‰�…}ÞS䄈ò›üRY _PîÿL‰U‰˜µ÷˜ŸŽoKîn„Ýp}…ô¨WC3lCðH91v0°ßˆºqõøöœe\ü óúg^Fk¬ŽtÒ63éàïZ„R÷î…ô¬G`o25ˆcA|�çX‰GAê\yBü}zãÆ§‚åAeÑ(¢Ô8·j�E�ˆ*µˆS:ßÃãÐT|™5@áF``Ÿ³ýYì÷¿Äbl¢VË_è1™6aÌ3²X†!ÉeªÅuBnƯ4ܶ­ÃÖë.©7À»í>o0U}Ùã�Ô éåQçߎD»Ã{©/nd¸eÀ¥»57$Ü5u�Ï5ƒF8T¿u@ª{p»¨&_oF¼¢’2�†$cH‘lXu}G4$Å Í|´ä,¦È9º�ãp¾(²�|ã42Bñê…ÜW¸TºWV£öÿ�LâŒgÐÅw(ºƒrm`6ª‡Kn•�@„Ž5Ï�Ià¾2Otµ×§%R—ž�Ë"œ‚à³â­9¬æ‹KˆšŸ%ÐîÖ(q:yf�ÉqΤcßFü3Í©:�Ø!‚¶ç:ÑŽ™ÑèIî}LY¾Ì¿'»Új­†öÜ ±V³Eñ7KÖØÊcåž+ÿ£ýƒRÂÞnȨuø€U?:q´Ðh*†ü4£±t€íŸZt¯Dâ£â£k>C—äyYBi9„æÆtPrÛ|°õnµ7L×SËWÙ1³4Š�ñ©NMp hÒÍ@4~·å¾¢‘„FüŒ-BÞÝr¥´¾dË×ÓŸü ÓYG†y�ÉRkÓãLñ°¡:|ÊþÌø|‘«•¢Vöm^á›j¢i%ìN€7§'�Û[0h]%BÎn¦á:,uG¤`Î3În6ˆëº”úR%>W˜+2Êlˆ•DÕ\âp–ìîmÚ¯(-ÿ„¾u2ÍÎÿ;Ê·P„vl¤–…[ÏrnùC»ÇW®%Y`{`Qߟ�1áý~]IöUô“ ʼq·Gí(·äÔºõev̵Pâ¹ÑH�šïÜïÞöbÁëšáãˆÁ$ð}L•ÏX=ç÷(au æñH`cP¡F~«t`9œO�E¸ ‚>µÍìØ—H¾&’}ÊíjqÏ{ÅëS½ݶÝí1ÏXº¥9r…¿•üH)T cKµ«�Úç:µ0¦}nxʼÆG±8ü‰ô–VTbáÒ{ŠN¼ì«‡ÃÝwù q±5ØÉk´ô à.*†ÕÂÔÿŸr¹ô69Z“ù �elJÆá¦kMLþŽåx‚ñ!ª¿ªUSýí�Šãð}׺ÆoJÓ.èNs‡{ ¼VÖŠ¢Ø>±xdú˜×Ù÷HÚ~ÖÊ–»ÏBöy‡4mÞU´CÁ¼ó¥àûþßSp½î3õ,ß/UÂW÷4%‡£ŸÑ&Ê‘Ež²Êq(^M¸�Œ&zÖ!œXã�iÇÕ¢Wã‚ Ê‘—]q7Ð`ê<áË'gíÑ®H`Ó o; ˜âPèÀzŸ1{ýÝ—-êö@ã¯]^‹LBðBE—À ä<(¼ZÜ{7$ ÷uÿdÄÏ^ùÔ|zëē鈺µqÔÉ@‚cJšqtœ¦<§*‚[éÂ;ï?ñ»\&Ìò¬WÈê_³Ê.nKm–È늄EyFù«ƒ"ÝëžÓìSH�äajü$bxϧ7»!µÈ|Û̾½­NáôyÚ¼Ahõ îšl_j 7>É©ô 9Ü¥ŽxIµl9îÕ:òs0çA9£–v¹Y²vƒÀ†,ÙÑÍâÐqßFÇ*ÌÍ7*´†i"'(~†¹tÈÄd"ûÎ>ù¤ÌYíÑô›Ïí_�#@IÌÂ>Æ¥åyÙµÃaMf&/Ì�!3ÒldL»ò±åé¦,=¿/ÕÎà tâîLVŸ3—ÞôÀ`=BEhÛêñ©O¥RŽí‘S$ë#AVýøZӠ׃Õ‚}}hÍýDø©5ð¹� VåŽã9‹�0aWÞô,í¢‰YÙbE)Ó2�»S�«¬¨u‹éÂÞvkÅ‚¡D°^¬¨Gy®{ÑtA º˜fðcCà8H ÓEz’¾çOH3"Kߦ_1BÇHO»zîBì&|õ²á–D?©žM÷m_œÕt<“6H‰W$�YéŒ{j8[i+ ª}šVôÃdJ”˜!…ÝÜG)ÄN­m3EùŒàƒ‚±áGïÐ dtÞ“n¥ã)¦’™nÒgÈî£~×AÏ‘kü=�™ÃËÄ„§-n°Í 3”« ´nnÖú“'l§HŠ�<ë§ú~“l4É!õRn>‹ïŒ{$ï\Êe‰SRcÿ–?AjC�Œ¯=ëÿ­$Wþ]OØ/®�¾§y¤.dÀ;²ž”ßË‚iÿoM¿K”$§Ù,ŸföcøË]î’-òöÅ+0 ndM;CSi‚5ÇVÉSSƶ ÀÐvƒ:Yy¯&ôß#Þu~¥¤à}-´/úO¹#ÿäqD“pê€!v€×GzÞa˜û…#¼‹ÊgB,Ÿ£uÙ vÀ÷…” ðKnSŽYâ:â?I¨:�d,Ÿ˜ñÇoÊ=GÛT�ËaØ—ªA!HaZxÞû¾<¦Il‡k_€Dm'5¹×íqÒÙôœRÀÐËå Ññ°é¾ªhíP0ãMë»ÍÓf‡¥ñ|üCÔgYW¹Ìá„VÅ�¿¥˜¸‹ë: ZíÂþÒ5™;w;•ÅU¶;©ÇÝáµu’zÓÉ"@!ŒOWKB"{.�‡OÜŒ‰Ð�Gž{éSª¶îõ³L‹Æ‚[¢âÞDêL&/$¯[”)ñ¿õï÷#BT¥M)ÆnE¬‹öÆa°eúó½ÒÇü·ö*7÷P5÷¾N6ÄÙ¨òÌœRb{­ ú�E„TÆAõÖ_dç¢}�Oí{¨¤=.5€pP¥ÛÆx™QeH½Kªˆ>7K&7¶BíAÀ¾ù ¢«ê¢0)4)øpBeÞ{„íªœ5Q.ÍRq€‡!ÆÙëX¯Nôiý~25Þ~3¸÷©z\’�Ù·h¾ÕÂÏí3 0Cœi�„1%†9;ÄHŒšÝ£b@–—þ,ƒH8ŸÕÈüàµQÔÁTŠ ´?ŸG’T[EâÜß(9²¿]Å¥¹?�؈.ùk-”㜩ÜxmîAHÏÉnEÝÎe{ç/d iKÙ+º*¼�$�‚ž¤ÿøÊ M]¥Ò¤)—k{¹Þì„omê2Ë/�­F·jL‰•@¥�/CUÃèÍP£ç‰-Â6ÙO!Ƥ�ŸÕmô��쯤E\ÉŒpbØ\xÒº”-ƒ˜¹Sâêòù¤Šë‡ÜÇt×ê!Eîuw}$º¢ošˆÊþ òV±Sr'ï1hÉo¾i·(šÂ$ô¦RˆÓ(#QO™âÄ„KÌzð“ <’äÕ£ûáÓOÒ7{¡°› a©ÊpZ ¨EˆÊ˜J‚•^}j,7¡WØ{'ºð†‡S“u¨‰å ´f–2]˜Ö fTŸÐ–ÛujvÏHÜŒ}þlžñÿ‘ †š$4Ñš„ jÅÉ-Æ1oÖ^cXG) z§ {I%!ó`/lJ®’Å䩺šÓêKµ‹âÀ#ñ±µ¹³ì5 ™²ÆO�lÚîcÁ ”¡FÎB(úlÆ™ç¦Ý‰ZßP§ê(ëóа+N ‰ÀhÝU|³ÍD�¥¶@yàûnÞkþpú˜џ͇\âl¾€»|T÷�|ørÝ>L¸œû½AÑ@² µUS‚øC7Â;Bžf®¼�Q@Ïo!W§MdKI*WRûC8ÓlƒõõX^È•O7ˆjÔ])Àhïcæ4!eêiL ˋŸóo/ �Ò�3b¾¦~�k‘ƒ8hp[V†¬ɨ�øüHa;”s�\z픡âSµtß¾Ñrƒ"ÿÞ—­Þ‘ØTSâª�LZ Ú¾±H·òÜz¨ü"É Q0„”ã@Œ¨ÀYUõøw¶EˆúÍÎãÈFi>d8Ï‘ '’üxÄj0©…$#¾ó^pI�Ž%Ê*Ârøìaq§Ú–)c̉‰oÀFÔßg2V‘¤ç͈çs™þÀ³qé˜òV£ñ¦Ž´Ôx½X ¾QnÇkâw’VûÒÈW=£½bƇ÷t0‘RÍdd¸mx¶ºØ��{Ýbáà H‡Ü  Ñ9WúÙëËWîÙ�3¸j¥C¦¶Þu–ïFý½1Ci¹ß+j#ë÷ÒÿÌî¬|vØKÅ©�û@ÍÊšdeÅ4ÒA‚{[6­•ª±·Å ýÃ'¥*á«aÑP3îE¹/z‰Ó–0tãøG5XÅÛ]‹N*ìô°:Û$ÖDÕj&UЬãZbŒVŸáßîÏÌÄ‹€º«Æý=í,.2øV�ãüþºÜ>FƒSÃ")Ø »¾W�ìä®cÖ¹ý·Q‰ï–¡‡%ý—ô‘…hÔmoNÊÎ×oœát¬ê~ßllØ5è~ñù¢Èx“ÛºN|¤zšØž :Îש%,9OâÖ¢šÜ1YÀÖ"«¿DÉßÝGT „9º · ÃÛ)‚—ÓðDÃÛõÿoáÆ…;Bvù²=Ø©Bõ‰è�}bN=_HfæÏv"ýõypN;2&9oð3A;yŒa=”2Úð€Øäc=ý¾)/Ö)» ÊHs‡ßU]«~î6*\â+€Œ'yÛº;bÖØ÷øB(ågÔh–OyG�mÞØkì?þ)=6¶Øõ{¹û«XÍ�¡õݦÄî˜pP‰Ð8—Ä@_¹qÒÔ(däǤ¡²íEA¯ �#›oø §¨¶½ëÍÛÆ#Èd¦ªæü‰›Ñ³ZlïÑ’'bÕgWΫëͳ¸ÝÕÔìKˆ1Rˤ,8ˆÑL –Ú—±0aîWÜÊÔnÌ웑öM–I@Ï�žòÈŠèÐPº¯Ï<;|ÃÜÈzà5ͪˆyV÷2ïã1ð€Á¶žé3q•PN29ÉqÇÕ=IfN]Â:O»‹Ëã®Y¯ãv¹,‰â�Ü8º®v´éÞÏŠ·Û� ±æF³>T’•Œj*ƒ†ÝqmL)þÙàãèiœùª@i³‚Ÿ6€eNº§` naG*×ú‹?�÷uƒìâSVs'[±þÄítä#,—uaåbB'léÖ6µz.£ ¥ÝSÀ�Ž˜rl9!;a 6M 0R!º£7Ó¼3ôDѬGmUÞ³�Z¯rçg’]ø+1Æ+ùŠ,}HšüfÐ ~‰uëå©9‡î™á÷[_nóf&Òo™âO‹Šgý(^+ãRDŽY+Ì$:~°fŠ€ø=™ ¢Ñ›î9nî•Ï«7s­«Ÿ�"%#+_3º�+é c\S>?··(ÕŠ´Ì8Ó÷¹óþ¶MFîÉ›&+o S4¿!6¦ñÆ@Åö"«2ƒÄôH™ÒÎÇ”¥ÿÊ»ÒÝ)¦HD¾ë0(Nñ¨ð»Þü¤ ¥'4@®nÎ!ÉËnõ¦J”Ìã ünûÑ›ûƒ¶ý‰¼œœFIKçã­dFH‹K-Åš²¯'ü¢X{²"Æt†«ƒL9Ò¦NÓmÝWÖR  Ï58*k¶ßkk ³šsúXâc®û–cÕÊDö6,†EÊìråojLsR$Î,èužï|ØHkz Xɘ?v]¹Z2gÜéL(ˆ�_­ TöÄ ?¤®eßǽž nßRð ã’Öê ™©ŒŽÄ/M~޵7\zà²M*7`tÕ¡'¡P5õÜ»ã¢13å>IUl�B] ^Kn^?K“mu&°Ð^eGKRòáA¬ŽnkV–×”‹áÈm$Ã;ä`²Æ 9„ÃFv¶¸úú6ýEYft‰UÑ_³éÀ‚~—}ƒë]dÒMÜ$mÕVKölÛœôòDlQn1Áy‚¿µñ’ï,Wˆ7$•¦ø—= àÀ0WìņTõ}!Ëç“'•lcTÓ³¬3ïí1ªdÍ¿)—b¦kÒ? †`A™Çî™Ï¢�µºüš§à¿­Ú}E½¯|OaÃMH3÷ÌTumîK n²keüÊTp Š3æV^;þ2E2AP*¥¡ç£ Á`�ýØ�;mÕFXÌÊ7mÛ6 �×*“ Aóï/Îqÿ¥ºs/xº �Î]öÍY’ Fa›ÿUûe±ÏÛqå�v$‘É×zË]Ã[ðŽz d’@Ò-0q¶=Ÿ4nkTã~$ˆ :x?F:‡RÛŠwÐK¨Œ|ÎRN9ù Å]Œé�ÿ‹ÍçøCq4}YCÀ`h�|Q/làjøhÍÃ›ÓøÈ²™'2yÃXoKbce´C9‹«NJM™J‰ƒï[HHžf�*@C�:Ù4ü\:-r¼œàQuÁ�v6ÙQi záDæNçðÀÖ2®šj)Ç·Ò¡d‡sª}..®+1 ÷®9NJ ½xàéIDá„S�¾4˜ýèËí>é¹Ù»*ƒE{39‡zGö$M=ÛªIQÝ:5©xô‚µ]’}Žì–jä±aW§2Èš}pþo§ð+{ºT½íR¸+=A9ëÚw.TªÎ¾‚â$Ì-àÀ˜] ݧÍb³´xÉUê+ú …†k5h�Ùv{kÑ÷£¨]zz’‘d´JÓ1÷ØZ ¡0¸paVȰg´D8ÿ±Šo"ÃËs-ß«)Ï Ç9In#�»êŠ´!* LŠV!3äc®Œ›÷‘œŒ•¿üâ* ²Ö—&X °TÐK»M÷“Ç)×¶ñC³6C1Ô/’/y›`ÇU)ŸåÐ'ïýšM\Ý ­p£jÛßÂAL°€_ÀNj6l ·ó$¶?°þϲH\±-©)õômº fÍ’Å£úû?üóH´çBöÝ©¢ðbÚ˜‹«ÌàufŒÇQâ ñ£ Ò®J7ó:ÓD)=Ë£}ݨ�4#c« …ðqçÑh�M4)ÙL\¦i‡Úù¦õ)U'wøù~·vìöÊS,æ.óbdi†g“¢*Ìitm¡*Ùm0iÐü}ðº¹#ó³�B×à¡dYnÀ‚”mÜ}áÐÞ�^sܵÒÖ™Œ†�Ss^¯€[”ð­²’µÒš´ï„¨N ™Þ“f×H£S+]½:ºf}À-˜æf½„…fQ›Ã$kF(�˜¸RY”•›1a/~zûv4f¶¤‘ï ŽÑ[­æ{é>™çã¹Ì ™Oûå‘E¥f�dÌ;þ·£g4¸„û¾þí ÙŠŒ"˜V"‰ó½¥ö¢âôdîmáÂib4d䯅ú:Å¡½oÁ€mßNÖgj¤ß0áNâ‘Ü Ð=H«rkXadN2ý8& óhû¨�J4 £l�ì+uG`øù±À‰RÔÍFÀœ“¾SœåÊ}­—Ÿ?’ýÄ£±«â#|†Ú�þ [k±—öÂL­…œÞZ\ã2šµ%ÛÅÍ-ouÿâà¤G®E¦<Õa ““½"#ô¿0нX;{„cðYË>, Ðú µ¾á³Ýñ9”å—œ}úm\âÌœ S‘ØVäÜUHyGbm·Þ€¶B€r}þQÉÕ+Ž�Á{ÿ/kÆÌÛZÃÒff P$õ<ÖfÛ)ÔhFnD6]Ÿ[Wz¢•†ŸÁ¡û-·Ý%n&šo–í·Hx%x ‚Î.³¹A: ¹Ï˜)_´äã÷4H¬Tïöž0÷8Ãqá¹u§Ö¿¢Wޝœ;¼ZX�Šv�ýolñæ;zJCêw® ÜÝæ'ÈOÓâÎ1Yžü|›‰GõÈ×Üê*ØEŠWxÅwÌó'Ö]™`ŽæïÇž¸�rÅsT²õÔì0³€ùø6Ü"-^i…͹œ'P\¢®fð††k«1”r¦†��&N]µåS犇PÅ›4"p† �7º¹”†+n¯XPÌù’´ìoYR™Éa;þí}Ibe骗¹UÐÕ©H�¡ØáÊäX D-n¹ÖÕE‚hô±·éAaµ9ûQ4h¼÷-�°® ¥E( É]Gʼóʳa•¸xL“gíT¼kvÌQRý˜kVƒl“]ƒ®\È «¿&ŸØ««Qç²¥:Ê�X1¿%‚ˆR´lø<Ûq&d ?ŽóÖy «8=7Ôì�J""�¿`BÃew/½Ýõd‰'b .•ÉíÉåÆÝH=åô�°ypó%,1 ‹EON ±Ý1üäÍ7î k ~.µúl_bïAù…ÀÑûÄÞÚûEØ¥4Lŵ>—!Í¡Â�¶Öd§Þ�¿G­`A¡üÔÁ¸ßÙðKκl†õÆ2›$�”²¤øúKð1C�Îä9�Ü×Þ+0¹ëä€Ã:<5ÍÂ7öhœ®÷·ÉµGqÊ<йâU®˜T…–�> Í,aU�ÃNáœ:’£háåÛ®tuê-¸BFâòQ2ðPbµÏó%³ ]œ@:ró[kÌŒàÎßÙå°ÿ ,Yb½~·hÖº ïj¶³¯ ðFak.¡Uók„2Vç-ŒÌU£f»rÍÚ%<„ø�'%{G/e-g°=½Â¡?^û*@ûjqYÏ-…×k?CQåÑ>•„Дè ºÔ>w1û�¤`ãLµßc–žÇ‹7<t%»¸õ¿É\7X�n<$NWÌ-¦RîLÕa&vû�—Jmû_“Ô¦À3rÈ%/1Å<<Íûú¯XÃûÍ™Õ<X24ÄmF$Ô)˜öJĈ c ¥äu¢ÝM”£[ ãÑx°È ŒÐêy®qöwŽÒêQ˜oÖµä0÷¢…‘‰_nò¾ÅLwI½É?ƒ¯¹fq…/°ŽAG­ùê”?¥/6O Wò“W�!“zšAþ#?ÁPü›3à“Ág£E<žf ð3þ�ªBOï½rçdLkc�>ÔôU Ž"·‚ç8žt’ W4?�1I²›4OŸÀ{Kš‡S ]›&“Ô¬3„YSÏ}aókACB” ¡‡ ÌZqsÂ꧸�×¥.r% ?» 6¼kî O')aƒý©ù3c>rªÊi…ŽC¬/FË‹iQ¨E3²‡/«_E÷øÏÔˆ½V€Ëª¹£÷×KOP‰´Êö¿²Š*Yϧäè+Ù®î0¯šS_ÅÛçb&V@Ð×·î¹´Wýèˆ +»hÂ-Tî )k=oX&tš˜uáæšpmh‚\Wcü©�wMyEByöZu‡Òà€Ø /f°g·e?ÿÃM‰’ð)Λɂâ0žU’¡¾Ž8pm—EÝþB;å2xé7ö‘ƒ)3B覒9àˆòXG;Ùá'Ͻ¤HSŒXézÏœÁ,c·¢L”Uˆ Òlž£àï‚gS!À*§Yõl.EþdVŒô ÍçÂîe+Þ+€uÖ™3Ûù�cœ|úéì;oR›øñÓNÇѨóßr}h@uAg[ãͱ�ð_�^ªÑÞ +­}ÆÝ‡Î븙aÐ8Ž:j7–m„�¤ÿpz0ÏÓH ìè€ÜÒ/°¶Þ�ãT.»õ…—à~¶é¦VºÕàÅí¬ÆrO‡€ëeIiñ-F_1ÛWHg’(2ŠìŠù€À)Ÿ0ü+ójÕ‘¡ÙÔ¦,LͯRÔâeÏSè¨æb2(#�±ôŒÑ6¬îa–ã:MÚ•â+�Ïv)ßU_×-á_LºàÍ(SVJ%§uE™ùw²®Ž·•-ÓRÊdp}��xú#Sm胜'á蔼ù:×_¢õô‘3æj ZNXë`òÁ}ѧuû¦’|÷•™aA IxzìÆÍx?mW7ež@75¿6i®»‘Wôm¤'·Æ�‰è­k”çqûqR$€–³À�uoí:Òë?Ì%z=ÚvŽê•Ê<ñè…÷Ôà„¸îª5])–9‡ áYw÷@‡«íuõ€@\ j29ITÃÄ¿C𽯿Â9ØeP?®¨Ô d¢Óß­�E 㠼übÒixŸ”É,ÓÒx¢þåï"<°_Æ“ ®sdÊ 50¦Tƒ ÜF{ô.]Ž*Ãd£Mp>?O\ß’wîœ"Âè•f"Э;wPU¶=f—…¬‚ð’9QbËÆEGÝ}¬OnÕNÞä_G‡¾ú?ȩɵnWé~�v.}³ïiÈÖ™ŒÃ'1{û±JêZ˜ ¨ÇŠ!�S¤ YŒÁ€ùøE�0õæ¶íâ&žx¢‹¯X*_ÕÞþ@;ƒ-èÕ…ø­ Œ¡àâ vO¶¢Ë7½ýy.þøQDâX^NW¹˜gsÊ‹u©‘÷ñýôž/Dh)Bª¬s‘“�h«®a°ñíþÕ›m–㸒©–æa!iJð]’ j² ÂèW-Y}m´ô˜àd¥æýUX³¹ABƒÛzŽO¸�©Ü…/ž!¢ª¹‘&œ9'G¼û³Ž9™N´¡Ãp6Å—�´3+¯{eìŒZIdÓ 9Žç‘ÁíìÕôæ¼?l¢r¡õC©‚ÆL¢ÁØòDb4¼£Sò†É‰´]ôÄîY�êpH!+Y§ª:œvç÷¦´¢l2Cí—*žÅôF\  V™ý”„<*E*ðê,Vî|`×'’1LÖ]¥Šk1~Â1.Ô!Nþ4s MZ ·Êõb㺄|`Í•Àö’›“ª:-H½ÉçÃá•¡" ¢)*ôL'Æ’Ê�"X©`ã˜Ò…Ù?)`Ø6eÛ§bPup ±xHžÉ€ª�•ßFz݉.ñäM”Ê<,<ÃOØÏÓy†Ítv‹ö=ЇzEäóf.ÂÔ }×›À÷†²ÉRFæ¸R_d/o@E{]`w $—û¤+›¼eþåX3 A°dö$l·Ä;ÉœˆæÇK‡¡ÈÐc¬¼Ý¶hýø�<+¬ìv·ïÔ ô0!ë'{« øU甽¥ùá4(õ#6Ãî€3n¿?WH€»eE�b·]ø$Ø‘�•âS¬’�\Z`è)½Ì[(9©»Cùœút¸r3)ö÷ò×DÆ�I÷â·ì¹Xâñ.³ ö¸�âúª7£t•75è6¸Î¬ñl‰f¹!žQÌCM jBT³wP²‘¶nD ˜i›ìÐýsÖ Ÿ•ʹ«±KÍ( ‚þ_~¾ÙöDømÞûB•b¶[‰�AHŠú4˜²§l‰8T×­Ø”ußü$¬è­}:‹9ê+ C ß1A4fÍïèòæjRJoÅÐñtd/ÿZ©¯‰GÙðá±ø�©œítÛÎâ¢Xu@f îj*;Da]™å�ÕêØÀðôàwµùʦèþª s{bàZ‘ç¾5èÒתö4Ò>|/|Yé)^sVÅ"‹ˆ°Z(LbAq&vt°ˆ ªÚ¸qÁ¹OTp]áR½÷; ô5ÌK´uém„z1Vu-ÇÄb-Ê1çÓØ†…šARÎvÑX‘E~DÇüŰƒ+>þaaã*擲ËgÒ8ÊÏ!™ê·C½Ià\¿êfÔS¥kÌ©ÍxúM@ýÎ ­*ä›ñPŽq¸˜k=7zbžDN ïA²ù!ã“)ÑÀc«_ƒüYç‚ÈÝ@dßst[`Õ¨¿GWÂ\#ƒòD*~ÓO¾CD%sª…¡‡}ßBJ™\»Ïÿ;£ç¦T{U0*´Úʘ¯g€þ¾®ܱ¦šlÆþ6ìÏœA¿‡ üà‚B0ÔHy°v�|ÚM(º]­ßŠ�ÇÁËo:�uÝ÷ò÷ì¿iFciº5#&x´Ý ±ow^œP„ÄníÜ*•û£„gMËZ6êò8¿Ðb™ü8»Þ³ÉÓ‚±R–TEúÚ‚¹’5®Ç“nÎ?O¥n,Ôôȼ¨±È¾¹ûÞ©/Ìl~CŽ-1 CZ±–^Å҈슗±ÿ�Šéצ2·ñ«!­3Ø©Ã=µdŸÏOÞ0�<5˜ö·ƒ{k¡Ø�>ò‚®ž{)M¼¡¦öÿà�(K�<‘œ`AîЩ–�1#ƒtàB6C¿ÎÿUc+['®§g<±�¹ÂýÕD ¡@ÿ0´8úµ[ÄÉõuåÞ1*(ØÏ#~/«3䨖­‰»*­RoÅm=%�ª|Nõ™šd �¹‡=tæNçï©t3BŸâSO•L>ˆMåAì°NË)˜–C_çÕP™ 5 …*qèi2ÎþÆixw¸¤ûñá�J‘iV—áAšçåZ^5‘½u¹a�õ ÌL翳³üOxk€â¼?ÒÀ§÷î÷1¶“Ø5%¤]»Ôˆ�€Cƒuz³Ùg¿B'qMðJ»~²`4Ûµ'ÝßpÙxb•vU€á÷KY=�ψÞôÿ»Þ+—é¹2œü^v>.Õå±Ò6ô• ‡îŽ`uÌf¦üjœÖ VIã8¼ä¢¯Ã¶,^Â38‘‚ˆ';þÿŽ¡ÐlÁûJjVìêƒe_Ò•‚65231¦@;B «�Æü„iBlní Y<Ûe1±ƒªò¡5Å oåÆíîfg^Ì$½¯!™jÈC”†{¨·¥‰ê_ÐûÒ|ڸІ TùQØ–a‚LLr¿>ü”Ih%Ø `Óð çÆÄ`ŒÈÁÈ!ÿÒÃFEÀ] è|�±žÜ¢¯_ø%ª!”¯'�—u&F ÷áÎ9³3#÷L×<Îl.]vc98ŠtiÅgg¸yäö<Ö¡,­dI"˜¡‘'˜*ºG�+Ä¿ØÁ9»±azËõ�-›‰äRQ™ÚE”ƒ²š=¥ÆÏÉ“eÃ:åݽ¼[ô�z#¦3GÓ9–ƒR,Y>'ŽèãTĨ×Í";Ôþî-²ãïæÌFp•X T—]} ¾ ¥#ÿGÄöòHAÆo§©öØA‹¸2¿é@¦]+šmç˜ïá­Hùb‰$zùåæcRÃ* J¼ô÷ˆ b^ìjª &š=¨Ä™V’Åæøv¶.ešæ›Fó¸gèNÏ?•Ÿy2u�A¦_ÇÅ‚2¹t›A€gÊŽ·ÂµŒÈ¤©Žœ€L@ÆR_\q£©ÁN›„�d91,t,<ÉÔkýü™JKî·5~Ó] E6¸Š à<J ­½©ôc;gÄ)¨Øv…\Z�' \Ŭ«ÈÌÅë/Œ÷§Lh‚uî*‹ÆfEJIn 2¥.Hd4"Ì·â$*H¯Ý¥Hñ:B–jKžFôF :¼¥wûä¨ê~óÕÉq^:ÈËÚ®ÄvæØ”µ°¦V’¾X¥Haé» –^›vB’‚¹v9æÆ‡�+¶�”�|Í(­¾¦“£,<ú>€NÈüõÆÔŸî`£»F©ù]Qüó²ìÓFÙç6‰®ä-¨p¦išÖ+�3Ð]<µâí�dð&ÒoÚÄ~Ðþ·HÑç"0IbÆ¥�Õæ¶[†ãwH1óQ=Ýx<3$‘‘ò䟾Ã_+%Þ’¤úT±ø+±ý <»¹.®4•za!#Ùïƒyþ-.ó ƒá_iÖ)‹ÅIËy¾÷§°2ÖÿHß#´ZM[‡8û<3Éœ<Äzÿ?mNÒÁKŸ¬LŽP®A4Ÿ„[¤k–0ž‰„‡JÓz˜ ï޾Ûìå-� ü±Æu°jâfäX„ïo Óëè—õ홥­96 E¬šŸDR}ðÚV6ègÔ#��1ŽCòéuøË?øÑÜÿKorIÃ^¾dÈ¢, ùõf7³tê8Ä瓦üxÁzÇ¿üUÒêxÿ�IjZ3¤©ùêµ%¶>Ó` NTBÿà„ª‰@Æ:µ+™+¾ `86¾ˆ@TJRœù«`»¸ý꣕àlǘ*짺þjìÐÅêt:††ßL;¬c_칊^aM&ÏÞæº™�_lJžöÕîJŠä²0Iš‘Ôäç¥J «š:¹Ôž,Û(-¸ƒÛµ8ñ¢AÎËGÀ7È´sáŠE–¢!*¾ ¢‡MpÒ¤è=À„œæ `fõ¶'Ê»Z�<^y¶ZS6CYs†²eóx¸ŸÜØî�;L#¶ç³YòØ3¤ºOxºM¥íÔÃø±" õÿòaöãÀçu±-r{¤´ÇÉxWÖYÖ|ƒwÇ }³¤Dáyd'Ø©œÎ² è«.±mòЗoCúa“ó"ð"å¬eDè7B{¦º&SÛò˜ŒÇ†éÄÀB³ÝÙ] |Íßeÿg>�atò} “-2#ó«ÖôõáŸÀ&‘U©8ùÔq¾ª¥·Z~³ëXêðÈQd�ƒ5Ú\ üËg`ú­Ö¹¤UKàÅ310-Tk&“N±À“»+dSZïù.h,ñQK œ3�«„i)£izmýMQx%8Ï gõ¯õÄðP½ºž¢ç ŸH_[RÛZo—I©d£üUœØ%·!žÅs݃ANµŸ-Ó)y#€èsNŠè›þ÷ÕÈ‘ÿ_ �ÀšÛŒ7Ÿ÷õcZ Ì9Ń&u5DŽÚvhb0©DÎûð�Gʱô’ëŠ*X²�1èÀ·õ1ä*ÇKÃ}[ô>fÅÈÐ7m|/E)!ä"ƒÉö ­­ ®в„@È5‡€ Uzèø•& æ„N·ÚUÜeHÌʨ¿Xž“m ¤sÔh)2‡ª¤T„,¤ªPû–�)N´]8õ¼æÒ?ïÎ,VÎgh‰¢–œÿk™cC®_��÷ÎéW:‚´î¿?«"�=Œ6†žϳµY ‹�U�«…�q†ò÷ð>^{8w©ƒk¥Áj�nÃjoךd]ƒd)Çn(‘zõz·ÎÛ÷©$î,‰EíM�h‹«­á& ûÎ'ĬGÄ£ˆýÏUD]áqòo1¬†NW´µöž-ɉ9HöEÉ  º²¾q´[Î ›8(Á6l`Ð Iàx6NÏÏ®ì+^(N²'N‡EÔŒ�u îÖm€÷®eÛAnNc¤A˜‰�‰.¬!v8sõm!]‹Õ&œ©b".�ñbj›±a2ñ `“^Yv$©�m�©+57¥>ü©Êe»Å|Ëp¡�žÀòääâ5hJ Z#ÏÿMå‘2²2Q’ŽÔ½§A%MøÏŽëˆq:fÙpàSš4E5ª¾F'ž…çˆ2SIæo¶ê" †œM׳YZÔh…"ù‚ ã ÇCÕ½S‰t�¿EyŽÜàé²#s×;0ê—íÿ¨ÜÆfQø)1 ¢Ñ£MËA%&#�"*8>lÛ,fׂ¸³êýW“¸EÜÀ,OÒ•É5’ §�ñ'R iœpŽÑ”:�( œÊ£Ïô-w⬆K`^fõû•ëÌ “ä#,UõÎ)Û'©³…¡@fõ…½ŽZš²‚×],L/¦Ê´3G� LO ¶�—rÒF¶X«“(~ÃDyé o¾ü!ÖkjѲŽpéÚ…(=‰2M£¤žmPÍÚª5ö^u]Ý÷µãµ‚Èœvckû]òw€›¶ ®™Zﱸ/øÐ3[ÿ$Öž[ ÝÎ[ ´xæÖÔü•f“ ëèBI(•åbÈ’|ª%juU䎈‚Àÿ5)dðüØåTFÜ¿5Îôoó ¯­(‹n®S?àØï>oß>6–妒èé5๗ ³WR\!¼U­ÊeGÏ%ºçÀ[’>[X•üñ:œ8<ŸÌ6ŠÆ�KŽ'¾BG/2¿‡Â\ˆ4�œéçòøGtø¹læxuR?<Ý4Žòî€($5´!cŽ�JXÜg³Qtû¹ÑõŒ¸¸ß/+” áÈ&À”ê»…}¬â%ã¥üþægðËPÞ$¾Îfú‹|¨«†Øb(DáRƒóº5üoqˆ»Xf |•›)”ç®ñ:];Îf®yÿ�=²KrwN‰Žâ7þXmþöèø“k, ³8ž»,¨êV‚IYe‚à ÐD®�4�‹ýgr/W8¡{…ë—’›‡ìJÂKМֿ} 3*ÚOp¼e^µËÁ½0Ãß"z=Øv1Xǘ ¢›<2µ0}®Ó…““ð"²ø¥„úÇ̬©S’î»ÿâ`?Z7ú²T¨£�6uÕM“dÅvJÚcßK›½"ÄLFo¯|óÍH5SQ{Š$sPãß ü*¯%µg‹ª`—SÐ�}(ü‘AAÜ¿,_É1òö º.)Á,µ'�Ä¥¸2ú^h�s ‰KÒ] ½?l`„ÿ’‘ê£Ü(м.Vr.èz"²nÚúBŠ/ia6Xmp0:¨7®%,£3Z•|êjàâk ºô4 5Ž �n<ئê•Ü"˜ ž|ÿi±øjKºù.–èØ)l�j‚é¡‘º¨Ü¼Y5äZÐY®’'HGpŸLU�ÄeWô03�ãþyý¯ØB[“yþêÜâýšô•¹†œ8· Œ{_“2¨A]Ó^Ž€‡ÿų”GÑ©ùµó(õ:À©Þ_Bκ«Ç5%št–:b¸ß]ï`]úÓål¢`ÞïR¥U�”Ø’0' Å9‹]¨;å߈ÏVN_0TWÍ"ù3^‰ý¸DËâÈE.ÿµ*+šÍz¹¦%ò. ûL6£ƒ|’X@C¯Ž3?ò>㨵PÔXkVòVS�²énî‹wd“Oˆîúδ²6ˆ-¬¼@EjRˆ)´‰Žì•C|D×/ë*à7* 0ˆ1¼Eù°|â˜È%š],Fž Â…O;•‹VŠ:ä{.'3åö‰Ã¨‘Ù€“Ö}Éc‚½—»¢]‰o{‘ByÖøLmIÖÞ­ ·ÉÙ,\ó0!øÙßnæ]½øÚ@Æ5¥ÖøñH~DT휂&2-_"þbò´Ç5µ‰µú•6«BŽ<Á?s|�+½$Á›jñ¯×®rP&“K‰x˜Ûº°WßñRho‹ýnŒÔ¹º´“ANM ãiFR­V!d¹¸ ŽÈç÷€Ä]ÔmŸ+,Ð"¿R)/d­üUw(UÕ?‘bñË’ð|“�fäjÒ©î×–˜ÔMæûȉ�kLìHKo Mkÿ(å° _šñ×Ê< ÷’h…jܵ¯¸Sæ£=YK;Ên¥ü7{&‚Œð­8ùÈ×µlöèù‡�›g8Ú)8–C�ˆg;\ºM½Gçýó´Ñè©*­è…¹`Ûü~@è\Sã±—ñ¦V³®74á`öU.¨¢8·k¦¥'Ï£Ùß„Ìs°)Xí-8!,€¶ŽÃs¢û�N‹¡§·ud÷’¸šB³Õ�‰‡k½xØ5�ÞqXþAA?½�4aÍ×C G4³]ôO‘Û¶�£½Ð'›ö‘�¿—y®å‚©7žíOYK(Äc@—µ¿Û9Ï¥®õ9Bh˶ÄUè,xϼ�w ”[Øà7 Ó�FÒJäf-#¨¥°þK 4ÿ“&hIâÆ—�ftL�…à¸çÔ ‹ˆ€,¢_w Ïœ#Ôâ9pÂ…ue¶ñò�YÕTf›•jØ0ª'>Ämφ—?Ub¦=¾)zi]—²Íà8…”µéĨá ?yt×ô†ÝîÏèΡO²‰ Äªj¦ å¸vï–zÛÐe�7iˆ†h”sDVûÏ6öš`g`À·9•Üx]:ÿqz€‘$R;¡LòéÓS綦ËÉŠ&T®$.ìÒçá¸úÖJ+ÎBŽéÇmLK¤$ l9jµ0”D¢Û¶Ö:²•&q'ë½¾[HžK�)Y`î§¿`Yõíý£dó‰½÷GÜá±Ò.²«öía¶þœÿ¤�:¤ìÆ4²%©jþI\e׿ãÖÕ;F¾ßÀÍØÊ̶båüGœ6wÝe�aqèÄmlZm [ Iþ“|ŒÁï==ò­Ã`B¾KÂÍiHÐñía…%¬¹Ö)…˜…ϺåS È#À<ŽýÏÉšrù¬ë©ó™/Dy§?E°ž�.cþÚP²™ËA¢‹H ª•D½è`DØ ô`o7.·GŒDl)@¨Œ�NIþF˜d,®É�ñ’JöÁQmn¿_g^PïyÍøsœ ðÞcØgw…!¡d¤ÇôĺծÛäùb3ü/8G#�øU�ò�¡˜ÈÄÉxæ½Æ‰ìC.ˆyxÖv5_Êy¾‹0íéµK›ÔÀš�¹ÒßêøžúŸ¢"NÒÍxÿøÊ XÞòãy]ø% ŽY<Ú…|£±›qÒ=Î.k¥;šcÄtî’¿w‘¥`Ý@YÉdS|i)wã1µ¢]3˜üpÝà@‰´ùÎÔAEc¬KÅ˲åR´îã¹BXÀ™~T«&»gî”ÑC…½.õm‰‘ؼÙ�œ1.½€«Š§zŽ�äÀ€ Tä×*‘D\²—ìhó¼Iàl$Ü*àÀ¾ÌmÛ$¶]ñdª¡ø1)cë\¹`�)§%–OIöÈ <‡÷Ž¬î­øÜB±BµÌ¦*’t?sË•¶¥´¡B9Ÿ£ç¦N´”:;§ðÌŒ™BZÒ[¸pëwó$Êz‡}ã�‘ÞE€ž…Ö¡ú¹’Û2ˆ¿˜~®aÓ’%O*@k|) Ó?7‡WìÅü?à¸úÂo•v'AnË¡yº?´©ß Ì$­ÂoY’§›�X÷ �%sø�(–5dSm¢'©²¾9Á� Ùû³¾Ta5°ÐBÙs ëÜQÜ¥uf—Þ�¥J|,Ûî%ØI£r“îIÅBW²Ù’çcæ Ý#s½«YË÷|⬼Gô1,�³ mÕŒq—^«Ô6OCÐ�Ó;…°€½Õ È æ#¾Öö#´ŽT¢÷Aêî*�’{þ¹úò »íÿ™&µ4І’‚}ÜÍø¶&9<œÁcÿ»À$Êp)-&|`v„nQÅ©‹ƒµ(,ùòÍÑž›dH…˜"¾8›*GK‹1Õ§.©´Åì–/×°êáÀ¨Ýå#ˆN FË�àÄÌ‹G&±“ÝØ8àX%4á!ïæý|{Âù>‚’CªL:ãG5XlÅO UIpª^JšöbÅVü�ÊÐÛd<nÇ`4Z×yã�ÐÒÿêµúÖMĪ 9˜ý܈U]í20y¢v¹añ2�¡ò1Ãhò â™<ÿfNˆþ©ðôm1 8„PT‰qÆŸOs‘ú·I Ëjì'NŸn�ï Ǩ›¬¯{ÝK¥½J|£Ð8°]zk¡%ÄjäVü#³B©dß]týg3£`aF><+ aßa«ñé"& xc—§ožÐ•üd MžCCÝPòl{ù;¤š/‘¯éb°N$ÿ2¦ªÈEÿë´+L » h]^û±Jä™yÈãÉÓ•'.©a¨(.¾²ùî”l&íeOð®ãJÕ³Z]‹9è£+?SÀnz˜ñó}UËZÓP€�Šº¡`Z’Ü ™‘ŽÏ“vÿF¾K…öÉÁöBK|öí*ÿßà‘E&œcgdGÚ€u33—´‡þeÚK¹xfƒ{PLÐ䬲ûÒ&!Vc,wî¼hÉ$ëK6´¨kÑ=·¢¦ÆÌë‚nà×{†rm9$Ýšpò_Ùºw)‚ŽBù¥HNM6 ½ãá:)ù©^3§ð¡¹èBº¿ƒ�~0r¦µ3 Ê¡1\Úñ»(>öNAÇD¨ZräFÃl=c”|ssßp|}d„�¯3FýhÐ…´>ë u\$O)…UÃá|<î7Lñ:z�nˆa¹“sŸø¥|�S]ESÇ*U™nzOªËÌöJ…-�_“Æl-dLý” ®LžlÖF7¬9?ý>{¶&ã�/•n„¹É#*·òZrZ<•¹Jl�‡bz^}…\¼&Î_F™8¹ ·2ê¥>Çþõµzöÿ=w!îr2$ýûÜÃÄÂUòdü$ÿ=H›i%‘ØÜ„Èæ‚ŽÖêQlËÙ+¿ú_Ä›�œÜ·ó•”V²¯yÓ6sX�¦ž2¾W*:NK#âhÒvò·OHax€R¹¯ ®÷wœ½E„^~ä™Ô3…y¥ãºfÔvÌ6á‹oŸMäh¬Uc}>s»ß´t-›t/•¸BèL↋ÞÙ–à¯;:»‰M-^l©­D¿âGÝ (:G¯l@û7zõm‚ ²ýÊŒtâg‡ÇÛ¡eÕ»oÂ=ú'á¼C?²^´xÆÑ#Œ³M;Ô'éš…g9cmnÄy•ÂÙ—½o8§ëçTÅ·�l=t’k�EQý,7@¼[¢%€¹‡œ9í–Þ  \Õ¬…ÔÀ š �XˆFî›Dáõ·tÇðW¨E€´‹=wÁëŽ×|A/,§†î²ƒiçõO�e=®@> µ‰ch@Fý…ç0+š!ÔËr²›]ŠÛ7Öi~¦Œ¾z€(Ũq(^CMC n$0…~>œ^é{E]Ìœÿ×™ƒ, : ,;¯U!�•`;àÒ¶ggP~—M„KP*àE?èá3�ë( ÝýƒºÄ¶]ÞBöSJ1_Èr]¬8³áÃ5]{PÛ#VÐ¥Ð2Zõ +Ä»Ÿ…cb,#X8ʲzm³,hà Ëèã}Ÿât*ÿ@ØÍùUhüeÜ;ô�§&†�ÆÔ—Í[;DÛ×Ë:^{±ÉýºíÊÁÑ#gÝø…³:¢…”2uxNŠK²Öý©MH˜+Ô úÈZñAg†`w0ÒVüõi/“ä6›²OKƒÚó_ÓZŸ�^m×Òi÷2CSÉbTÆU©áqŒ¡ÏŠœ-ÌTÀ Hÿ Ç·*dÍåV)w²ž&˪n—Á”ò�´—Y³‹ýÛN»þ¨G+mI]ÚvZp<“~,bü§é°x^� ŠÉÚ¨‹–Õø‘hû1¢JÆ›QÎÈE™ J¸ñIÓçä¡gÒM•mZŽæ9%Ü»v ¡­ìÌù³–â»ópºKl>JƒÄª~ƒ·Ðc·j¾À|§ÚåD‰;(š½a¦¤¯ù˜vFÔ˜ÞEA˜ÍvHûãU´x-žá÷räØ]-@>=7$ûÊ8ÈÍ'—‡Û›Òë>;Ĥ>½TŸræ}½ Ðk;Ø©Ø^*‹8˜e¸Ê“÷c�…tU#’FÝ®b‰Øó^YmTØbYC©�‚±èÿÞqëMÖL¦Øƒv*\ËÇs›Åo=�×úìÇW!ž¾½6¡DüZè¹ÎÚŸDê*~^”†T›Û— ÝNúKÆAzcuŽ˜¾õ l¯¤�L×Þ�†^ÜÒ s‡„säbLþË÷ñç-¤7$=eŸdM�m¬Ö�¾J¸:,ðkÒ?‘ZíØæ˜]‘Z”†&È_²ó2?÷®;ÂÊ\ùßõýK~¶XZ#,ÊÿŒE˜f¨Qz yÝ#òj–Ú–ði \Uvræ,ó�îãç2“˜‘𛕓5Nƒ M@_ȳñO•µÒB�(ø¶ƒØg\d=9Qcˆ\Dxôˆª!ÉîNHŠ GÚ£<0ŸÃlþùµ ã­óܯ =*¥¡ # f{Š'ƒ™ò’ì˱¬©?‰p$YLÍfdíÙø.¯[FTâ%Wæ&.ÐmJîØ—Ð«„1ONaG,? —^Û…h¸—#=+'b{c!¶�pö‰!~·v¹�ÑÂ)à­tP 8¡ ˆD$Ý&€U"ŽF³FœF¯©Vÿ'ža'ßæ- ò3èê8É^»hëãvX%l4ã´?÷40ËöVV€^DñoØ$˜ŽÀ X€êœxÙ&¦´„y.g{ ‰Z5Bx¯Ñ¸¹…–uS!U·Užp¿Ø{}¢8»äúbÙ.P…^ —b5` eû‡Ï{Ï{4ób�žðYÃy öê*Ä¢j½cë:²É¼‰ÁÔÙ øä7o�“ ¡Óo£NÆÚÂ{hnZ"1M*�À«$óaTàyN‰^|àÅŒ=ŒW‘†.“®³ÐqE· ^”2>¾÷ÐõX4ë –ÅTMP˜pü³ä †Ð“ïQ‘ß•Àg¢TTÿºK»µ¨x•`X'½Eb�\W3²I-Ìý Z±Fz‘×+h¥‚b•›aá ¥ô·M.ÈdçîÓ¼Ï4ež…̯šJðAÐù×L &ÑÁ§†ä¦þ0ÙÌÕ×ÚêÍêÁ1ïí+èT“þ£ `‰eé,~ÎÉÔ¸Të6‚E£ÁHŠ%3ü.a s ¶:`AO ¬Bï`–tÛÀ:ïÐÂ€Ó ®þÞ³[ºŽ)ícq­y¡º¡-å%Ý…Ø×Tšg1X±`îäŸ-®qRnš—=NÖ©�÷ä4ÂÊ5öúÉHñ¶— >£¡16‚apF:š+:ò¾é^}Ôî_O "B¯£Žëæà1àdØŽºe‡iÈ·q’¿²Ufo=íîwÚG@tDs­H9¼�”&‘`œþ´C™w×�3Ìñ„¶?KkÑ)ÀËv§‘BSÅØqÇuÑÌ»Îv¿µ“t(ÀhÅBCÆ”@I«”'$Û— XîÛ˜»cÅ¿ùî¿`t§Et¯Å›ˆ9ñº§9‹iÈë úLÞ@ìBE\PAd&&ÌYNKƒ˜8§†ý½™ a?JY¶ƒ‰@É"Õ¶>E÷:ü´³0 ˜çƒúÑŠpÎ[€Qõ£ì ?£›ss¾.r•@É{&/¥ãú”ÞùNÂ5(sV3«òdN~¥ÆØ2Y¥¶£C�¼]asDÎ÷>5B|žtžÏ±Ççi½âhE]D`6`6{Ý[êç!ÍyÁXœ›)Vb[3i« C¶ßzuTÐ`u=ÛÝ­ZL^ð ë´þd÷Ç]NÐIf5NI´äTÖç&ü±ª[9¿Öy¢×L¿oN\È·Ó£ÐîwɬÁ§vnà]¯FUÂï))Çxt§#)»]@!�âòqUÿ+±í~f•©§¹ÑI!õ§(9˜ ©‹ùJR‰#?Mƒz}aá¦L· êœèñˆÒA6Êø'ô`úó òIz²=Ý„º“œËk®¹£ðèh3Ѷ<v_LÍ[ÝÓ²@7E&K5RL;À«AâAžž,É@þAÖ<’ˆ>BeÎî ‚!ýŸƒnʶo¯>îç6o)H¢ß—D]«%™8²AàdõûéF2ò1¥nã0ný�±£îf:Æ(ijŽÖ'«¦ßs.»‘޼h¿bqÝåáܪ<óò:ÍÌ-Jü½"?Ì€€m€�5M*¨­œ¸jfÝ6˜¿�Òï˹aé³°áÊMÑ4â±Fß®� q/&{vßµ2Ì'JwY_/·]Èo"¡%šFzÌ3×D>jKã/ ?ðW¼çƇ\&}ño¹³üûd_:+ºÖÕúư–X¼ëû¸7ȵÂÇ|Ú\P�.nÂO��à»�~²\>uDŒ]½Im¬Šó ¯ŸzxŒ}d Á8C4�$¾ax�SÙ¦ï~í&<Ý2`œ 3“ù%¸ï%œ0ÆËÌ_øªÛìRÅn- ¯Š±�% ¢ €+Š`øà’�h½³”ù±”p%ÿQI´xç)Å€Õ"ò¥ºÂñ_…÷1A; M3Äù¦ÝÇÉcªÇê\Åñ‹ L�¥êþMµìBGŽ:&ËL�+D ?7N÷–�!�»3+€³F"•/'^ñŸŠ†�©½¡¢|;¶uqêxýºµ[*Øa‡”¦H°ÔØH7Þ…¼±§ÙÐqWìrÖn„Ân‘O�©ðŠ)ÞÓ¾!äœMkâŒ{v ç~P9›l+#ay�ºÉ´›ƒLØ!² nˆÿ6˜Ðëc@ òJ3ÿŸ“�¤$½W Û¯Ý^˸–Á?Õ¾êôq5¡›�ÀàTž®ÌÞ¬¯a¤oŽ’yÞÿ1^iÃHB5�ž¯ Ü_°Á}ô%v¢¤(FšlˆC«Ú°8¿l#ûS?|—üž1ß8ü”nïéö³¥çü4ôAqÊý¼©"‹h¨ÐŒ~ª#á›%»ÁÿŠŸé’"Ÿï½XQ[Wä:þàºÈGk\FJç·š¼Ž†ÀÜàá¥ÛÆ£Wì¤|ÛGfÂ>5þ—©¦xCYßš§…žŸº/Nž~'†%Ó·WL®|Û*è»ÊØž<]Wà°qÌ]œ|�ÞØ«n…í7=HF!H±qö5zöòîÏ 7x|H ò›Çï±2ß©*B} µBÏ:2Ô)ò§köfñ�7]}‰âê“ +ÿÒ{ºUüÆ;¤kzL²ñŒmé±ã<÷iHÀÑæðq–ÆZ«€²—]©×0L*&®�Ÿ@ ºðÕœ·`½èyhQõ “Üö^Ð*ß²ùßµ?÷nñƒ%IÜ¿ìõÐW=ñ‚[•(Gºašõ€`°g�€ÃºrËG·œIù4[Л#OÞ—Ò¤H¼ßSvJé�ςן\V@}èTRŒè„�s ØU,)/¨¾kóz¯8™�ã(•`{5ßi©Fñe±S�Ö´‘(M˜l£s& ’$¤'z1:üœl~µÙ(ÒŽAú-›°ûÔ cä÷`Î|:�AÏnôžÈm¼2®²«ì{¯ŸlÐðAíãT¦¬vЧˆ ½ÔòS~ñªÛãîúl7¶Èéßdh¹³$/ÞRy$Zèå“!ñm•¿3‘ÁÏ]oÐ !þä×WåWZptÞ¿G2LLþ§ü�cL ÕS…•©í°aˆûËA¬'îþ_§0ièës¸•Böí5PÖ ¶oW)t€ŒŸ–››Ç¤§á‹ûõaô“­©aQÏ¿� ¬µÜK€Ø�j¶¼Ü…t†ªàBíe¬¸LøhLÊȽð¬wðZõW@©[øŸEžl�6!† x�±æ¤…~Ý©W�ʾ>f+§"«f6¦tºÝ3ÉKˆÅHáF)ñ‘bÚêhµyÁk—‚á ZÓxcÿ„«ñHz…Éj”3"n†\dÛ‡|;�‘h•lÁýšÇÑ Ëº@¡DzúÄŽ… Cö¼_ˆ;4HÎ)Tf¿RÅÁ:ð‰«ó�j΢C;Þ¯w‘<n S‡Ü$}ZÌÎÀk88pèÍï^)4<“ÊÌtnòýÇl!b Ô‰[—_(³0¼d ¨“zÖLYøøØ ݶy ½“ÂÚAo bä]c©B7bQ$•ƒLMO¢¿Ía¨þNqmÂížÂý¢*Ÿæ‚è¿<�) þ�~ (‚ížùíÿÒèèÄpjDþ{ö›ßûÎÜëÎóWøáÞ¨EE§®E;a!Ý?Wá¹¼#¡®¾klñ2¿µçÿ†é¾‘²Pk�ÂøD«–*2Ðц$Òq�­GÇ(²ˆ.ßxg;½Ãê@Å…þn~ñ £�„¼éêºàqÜáÆŽÊ¡æ©U‹aÉM6MTî1<tÁöä®~W)»^:d†$T¦3°eOa¶Ö‰µ¢ëz0éŠCXMgÕÐûÙL”-´ÞJ°¨Ö6[å/ÍO\:2Âc¿³. aYQúç~ súRå]m¹�/¬‡lo-xÆo×Þz¬:Àðoú}åc¾Sg.¹5œû뇩«¡“¬©æÂŸt3øå¤el@Î@«’>�Nµ.!÷‘áæäüÐ'†©È­¦ÅWÏ(pÉØ*ʉwq_ÖvÞ' ­™úšã‡�ã Ê™qÅ”¼íh¼\Løß º¹²(�8÷”n3¿–¤­as”ÁîmªýK"£v²¿*•xzµíhj¨{Š¡ÆZ0ÔE¦§³Ë'öÃÐT^¸ov=£ß|é|¸Ø"äx½®NÜ.ƒ{À©N :Ä\—*àÒÒ.öT›<>eÁËf[* 5vGAH½Î4z~ÇDÉü n@%íÑF üÌt±s/>>axMN±Îpë¬,p¡Ë›­g&Ò,0&`ãYæ3)™¯¬ôÓ(ÜOÈð<ý±~!FÌH SåÑðsÑŽ‹kˆo䟈š»F €â�‘@é1¼NdMÃfIæXšÊ6ë!ÿÈý³í„–^úÉisX‘�\ $p„ÊF·�@šî�bc[¡àSÅ]‘ÀE^ͼúW½ÒèJ%9w±U2Êx/ÔýyÙ£‰Ð¾‹UÈ1$ê¡K×gƒÑZcPHõ1Ø^L?ï±V—Nç¶`pBWBÈË»ò~7ØïGŽš£þ)âíòíDy$€�úÝEã#j8É’°×^$Ù‹`Òñ¹ã£ïcmHè÷Õ2=si•¦R»nêñ Q//À¥¹Æ+Ù<ÆÙXæ3ÔÞ»„'ÖUÑpü”6lùå~ðæµó,™´OÆRV  Òâúaø?‘TîN-|±�ã‘[2ú˜†#Ï´^½(gäÞtª™; Í¢§Ç\ãzJÆÝ�f8£ì!ÊfªCÝh ÉñâæV�WKø4N“�«gˆÌeo[ †\‚•0v•íÀLwg͈gþ“²T@í)®IƒÓ¢X¸À¤¨ù?H">9Pж\Nj‘Œ(_Ë1ج žðõ9¦•.³Ø¡Ô]‡e+†à.±†±{Ãnï¹qÎa�d¢¸ýÈ5¾¾’j7K­-‰T7±ÞÛåIArÂÀð^~`ÏgBRŠk{÷09Ý]‰Òi—˜Û9ÌÐÒ«×^/,(9¼>ëÒ¤t¾•üIr¼$OË o‚Öŧͮ¬ÛF:ˆÝQ —.ý«B>Ö�Õ¹ÁÆÈ´j ÿÛ¹éíø�ûómÜÕhÿÇ;6=6Ò³yþÇ~–myÚ¨"¿2¥µ}€4ÆØ]’ztú$Óü®£�J·æÎ ¯Í&¢L£KAÆúKeœbMZ÷BêK0F2$7œö 6¢ðuò z^©å+ô†ù(b”EÉ]Äc;pkcp ¡[ýÇ!£©Ì M<� M^êãå#/‚I×.¸ù¡:a'Œâuœb-$7T/¾üx1úézÀ²à+… �ä„w4×êÊ&Þ­p—žz!ƒ@!°–òae(Ô«ÆM‡RÆnÌzÓ‹b§¡Ãú´—Sµu›>´­q�Ûi»ÊÂ\ì #|0}$� Ds¼“à´þŒCƒ ó1›ðçœÇ–H´ªŠûH_ Bd�^DY¦«ä¢ f陈XTƒÅ�³@ãPönVÙ 1jÛ¿¯àô+#ù&Àî³½”\O¢†·1Ê|WÙõ|øéŒoéZÛ²Ž0™ÝŠÆ6 « [¸qéɽóE»£F£‘O‚ïù#{Ñì3€¿ÔÏ¿g{²s\-cœ�Õ; 2Å Tô0  éÿ÷Q·ÿ%Ö|п[ ÎZ2#pE¹\šÒÜ˜Ì c“eçœëð‘ÌѨgà K8U»ökU›k÷‰Ài5ÛQîïsÿ �–À‘µ†(ÁÌ.ìTÖAÒ~0Í*¬m{úš‹u=N2q$jø°@t^ššÀ~ƒ6Œ˜ît“úkõ8 1ô&¾›WQuR#ÕC™™ 7!CÕƒ%êãíÆ@Õš›ÖN÷¨Œ ÓõâÕK±ç­CŸ„Êa(K£ÿNãòÁ‚Õ9ð¹K ÔãÛ:Æ%)†ÊB:’“¦¥Ø+@Åp¥Eö¬éÿíB�²¦/ßx!¬£±,Zn®ôOªú¹›±õU‡JºZ ¸Xª{ŽïÞGÙ^GKBMìþhçï_QâÅW;ËíEãna@ÚžIfëÑ(}BÌ�õ=ÞLX�æ½Ï­›ƒÐ‚”>táý# ûÉž¼¸$¡Æ"÷r™Eâ©`Œ€nCÒ›¶ž®¾”ìG*gʦ9N·L¹ñ­Ï¥‡ïüUEýÔœÒÆsB¢‰g´þ8‹š Í¡åYx)®ü“ÐAŠ[¥`ˆQŠ©2«I<6á"vѸßG>+Üñ2f{Ô€ @AÙO"aw½¹2ûønZÄ2ºjJ›`j‡%ï‰kY™ÿ½[;UÛµ7:Yô›[uò|C)UT¿ «é.dSˆ¡«§Ñ.l Õf¯°³óÃoLKC±X,—ÌB´½‹uXc%U%¬ãiâæ¨Ì¦@ò3†Ëd¤9hÁ8Q&[fëÞ„õr.õºj–ÒšŽ]ÈÍŒ¯³uUbâ¶lÔ÷϶ð·a.©Tçç€æÇPó_ëÁ Pçl8bõpN>6R%YýK¸^ ¨8œ @5DðÒhll(€œ0.9·„µ~�µ¦$ŽHÇÐS~.�LãQ›”QW>6¶”@2¼*œ»=é¥þYÌñeÀÆ…VØÂ€>¤ÿyŽŽI̾sI稰 )þwi3à0Ç|Uνuõ�tJfÕyÇHœ#ÂQ¹V©×f ñÊg#¨t£ì~¾ˆãzUÑÕ�ެ�¿žR %Nd&j«s·+Q¹_�ììøtèšÈK)7bøbPÓƒ×su·É6F[év_zæõyàúã­žu^¸ôœ6*ýäÜ�‡C\äÅZ8·\ü|Y½Ó+Uy³×&•T‰ÆÉÈE×óÜf Ñ*fDÇj2‡Í–¬ùÕ\—,{èSAcÅšÆZèÇ%ùÉ\2¯BéÔ„YÊ%rØÚ÷ì 2DòóCèCš™3Žñd�1èP%€›“Nl~G±…¦B¨®[Ø�ÍWÂŒï±nò{F†¼9—Ñ-ùE |6rYNK5ò€(ëmÓI©Ìs4“rEñ¹8Ìçëí{ mVôT‚˜ "„» ·Ó5çß}”rnù‘êÞp$¬ÇÅÇåúq6ÁBãßDwv?¢~s&sò^°/V�u i1Ò¤´³y9[9Ï×ô™�¢[ ÔQ¦ì‚‚ñh�Ò;Cÿ–MiáX·�u¼ávV]5µîÝà]HÏd«•ÜhÅIYfœÅ½F¼dåÝÊ¢ ™m™'·¯‚ºVN�L; �€œ©ó+=Æ}Cdï8E€²¥ —›\þt¹õ¥£ç9>Íy#Ñ0�FO_�¹®kŒ?g�œj¶óÑM›âO[Ds§Çצ‘¹ðx6¥ÔÈÓ¹ÞßN",&EÐá?DûÒDÙŽŒ³2=`/jaŠE�m±`…²èƒ�`Ž—s -þ  ”ZÚÃj€4‰õ|¨¹N«¤B4 f*šã^ØÉ¹p÷ǰ肫÷o¡Z �? Ô‡Muezâ{˜5aáD®ÍŲÄ|9IìÌF‚u@P–IoE E?y>`Aj‰—¾'µ°âß*Ä¿qðEŒPvè5y$ êk C"Òe±µ¥ýCYWÁêŠöžëÂ�ghÿ&Àk:,+–ïó¬šaï>·â™—¡�Ðf&+è&ËŽ7™0.ž­Éßüe¹Äžp7»ý~SVs2î1”j4±Ú�G¸o`’éûœ”ÚEÁ4LJÛüOÇp¼üÑŸËO|‡mtú¨Ln ô®À —à=£m"%u[Æ[ÚâPû)ÞV Gí=Žm†'õâ[Û<(­ü¯J,ÖønÜ‘þˆ6­ šÿw”Fï+aµ[X~öhhÔŸ.ãªL>&%—jÏÈünp0Ì,[=Ì~}967îL;$Ì*éfH " Æhä×ȆO–Ù+™X™B¿9çcDZðJõ>&Wã{a âd¾ fòâÛ+>ÄB ¢ù]EëEžg”ïLµ“Y†pïßSÚÛãqVºLïŒ]k£xæš]C ãL�¬ÿ¤ÉxŽ01R`ìÊx¡^Qä¦�)~¨G,Aç ÊÍ(‘øà¼¾Ñ“È~Êz€MÚ*nÛ– B‘fO¾â !hs¿l–Šfý°‚(ÛJâæþŸ“Тy]n(É%ÁJ@‡øÁ(´ïâ !%‘õ;µó>ÒŠÖœ0¢Þ;®~¿v©¨%pAçÏ€®k:ðhˆa8 {¥‚©©ìRŒ9ïêʯÁ×RGéÚZ«;¾)om/ˆÑmàgG“ÿÏ›t¹`—Óè�c±�zŒ€NÑ¥SVÇèGÛÖËÎ9C, ¿óÏNÚ2¤‚¥z«W„�‰‹”î!±D-:sftGû„ÿä 6H¶|@0È o–µ fñáJ`£(e|œ§Ru¶+­‰ù ¸¸Xµ›ß`t¯!9gÝòÒ*îAð÷I‚²m§ÕoDzª-¶‰®xj[¤%;×Ù‡U)ù"áÆj·¬SYØÓM©`Õ#g(l3ö‘Nöfpwíß§Ê1þˆ~È~SÙLóeú Óâ™8³ìàrqAîdm-<±iI…b±<çÿýu÷Ôºyíb&&(Ž/ˆÈóâ¿E®î…z@Å’XÞ¬ÃO…÷nZÙ“ú”ëHŒ¿²÷/à¿ýãK͈J°‰ÓoQ�·�‰ƤòŠC9+�åæó¥µ#5Ö¢YLêW¡˜J¹Kø­õ®EtØxµOVúÙ/ _ŽWö�ò¥D?§_´¨�R__·ã–³®smÜiZ‚{÷]�!¤0Ï=.§7¯µË“ÇØ6Ï=ò[Òê3Eb¢él­[àsÉį~ùý†Ú”Çý' Lÿ÷e³ø)=M°„Ødá$"dvkó.•@NÕp7壆wúg'ÙíÃ\•öÌ·(£œ½\ÐJo(õŸ·ÖdºSŠec•�òç—‚½¸%ɬÔlâz59BÚ†’—!‡$U,§fÃfyÌô‚ÀvÉ䚪é¸K̬ga¹,V=÷y˜ò0Ó¿úàmÁ4F¹¿¨^X JÍGÂ×Y˜â‘j ”¤ßÑìkÂð㽉±ˆA%Ïâç ÙTs*$…Q ·c§¸¸?Ù;k#i‚½.7æ ¥óûR¹ê:—c\u‚ô@œÉ¡Œ�÷±ðš¦B¬B¾JÁ…¿0μãN= î˜>:Z¾¾jbïw¤=Ã]t°\ŽÜÜlË�"{Â) ãwF¢P±ŒJL•ÜDCþº[~lÕé¶ýže�–û]ЪŸš‰®ó—ûW™ØXÇçÖ™1nh\±Î('Š<Æw›󙺷¤ØQâå­i”B"p y¿]]8\ ÷Èp©¥|Ñ3¹‹¥èSÉ6g×YW¥=�à:ßÎB. <&ÔBF5T=V,p«´~ C ¾Õ7(;µòi/¦3f�x‡q”Ιž�Ö¤jž}µ–³|3ãxE±ÞR9o"ù.×ÿãO´¼­‘Ñ�žZ¥½éýNd¯p£`|[�hÊ£CÝ?ÿñèFUÖ)õµ_õ‰ÛÔ}Ö¤:%tk~‚ßHH”_V’åŽ+ß©j¨µZ™}bML0; €˜ù¦�!ð_Ý ƒý¹?ÂO¥ êsú¹ƒÊåš24"ÎÿøÊ _d?ò‚§ÉVªš¶ÓŒt›ŒÑ0k˜"Î饻d*©æHDd$O~Þcþ}p ™)ÉÆãÖÊy¤´BØ -k\ŒA,0ØcÄ"A¤õ�»îý¢¸Û…�#õ$sc‘{Ü©!|ê÷ ä–˜•6àÄÄq"•ß)´:Aß$Qç£7a-Ñä·� @´ÛºPý”רù©Ã‹tpšõd�ýìxF��!\œÑu ÀjqÜtÁÕ;Wɪ¯úg£%- j¨àj�þþá‡LÛ÷g5G¢î�¢æ9Ë(’ÖdR�ó0Ô 8\ †0§óhµ¾Fð—.-�ã�¨TŸöϦ¸5Ä%xºsH ³�M~·ç‚-ýÉ^€ÇÉ%¢3i›ò“(‡:Õ„O€r24Z¹ž „¹,ÑàÖR¨vÙI!ŒøZ¹¤ï«ŒÔfù”@BåM"HØŽfç\:`�)”±qpUÇ›*ª¬·î‡©¾}q•Ó]J¨#»Õµæ—<œÿ õÙÅq_ ¦�½ õZÛN(—(üÞQ$¼iúá˜!Óõãõ…"£¤bã!%[»g`¬°'2o2&w¹Pá+J,Ž›xÿ(I#ûŒƒ» ǵ ¥×ú�óyÙ`wšŸqVÔOÞ Â&bù˜¬}ó½%$Óf,Þ»¬ç±—F‚�|yLë÷ȃ†“Ô�¨wî(`‚I,ŠD<<.ÉÅ5,È?m¾7 #§o‹�¦nÈXÅ&ý·U�ˆ"Qçx\[’®!í¹ž ¤$°dArÿaZð¯ã•ß?,5EÐçŸÇµ•jý î´¢°ó³²ÿˆ¹­™B‡G8Ýî±ÕåóhÏ¡ü©À/dê²L/×(o|̽Îç¦3Ö''$[)_®ø`q!<ˆUú!¶G¶Çµf— çÙ²cºXÂÞ¤dÑÌÉÑÂ@„}�Žê@ÜDþâbê ,*HU¶HLÅl]>ŽË9t¹y9|Ýö �T¡æ—¹xVSÜB¸û�C-ü®5ô…³)Y²o:¸,gÔ¤â÷$6Ävf{¶“®¥1®þíÙâX™×pG0ûû›dê�k¯h½ä©nLðþˆ¶d ΚŽ/£SЊ ÅJÅMûK#e "ÑõRÙêÁ±¤Š ¿ÂŸ ÙË–Ço�jÝ(I�`ì5: �æšµâ”Ñ›kûMgf!m½,vÀ‰�ÇQ™m¹p¸KS·žYXº¨˜—л¹êÇù }oÖí¹„DŠÙLh!Ûµ†N‹Üu<ú}Ëòµ:òøCx|ÁYS8kû¢kÑšIâ®]VZ.[I›Y«Gwýóº[ø€§CÜä’mþ7KÀýŒÙs¯ª»;I9rÊ9ã¸'¾ùÂTó$ÿ6c~RA<ÉsË)!(œdÔÝÃÞ†ó/}™¥ 6[컾‘ö�ã�áRÓ¬™‘5Ú½�„*ºæÏÙŠÛÏjjµ“aß5ÂtÐWKé^1j›üq°Ÿªr[>’x‚?b¥B¬Ü¶²è-–þ}B‹Â¤%XÞ)áø�lZó˰'/fQ½Qd m‘“ð_WÝÈàeµ‘ú`t·V<£A·›:ÙO¸ Éž?Z~¬|„‘2¤Œ€rÊ%›¾½y@_{�R™ù}aP¯¾ç_Ó¸Þp/¨ÙÝ�@¤Ýűn¼RÛ%gÛòÅ‚þÆÏ“ÁZ|ß×à]–„¿Š®ëªž 0ŠÃ Qßµ`¶·¢&¦bª ?±IIêy@N7[7‹Ér•S©y¿Í˜òÚ’G‚Âñxa_§—ðÈI7Ã.|¼Èdor³½Ìã1• yjfŒ;ÊÖö¦N§E¾ôàW|¥sP‹Õ@¾q^€<¾í“àrElClÛ49~£Š–dð§çáÜþ•ú,'¡wþ”"ï(fvß<(œ=³$OF›š,•#çrÉZrŽa‹6¾þ`Öakr)ÖÙY+õ.I|TB˜ØÌ= Sbõ¥<ß+p›óä:ØS©t\üëÃ=˜w ‡¡–¨éðYÊôt+É_\‚ÆicàF·BGÁ"+òh5zmm_ç“Ο�‹òè{F)ß¹’ɵ³È¡W~–K-)cÓ¿‚�ã§iÀøá4+é)`~›À'/‡�¼é•Þ¥¦«Ñ1fzÒu ›f´š�e0׈*ÙK´n¹å}U©rCo¥J†Ø€Ñ{ŒÀÓSTÖ’OÄ�;槨¸ï¹ëdKÖ�Ÿf?ó…7 ,Q?î ÇWœ‚R ’Fyr¶7P}X-Ñj\ 3](äs8F»”×åNß·Ì…ù]ƒ�M�/Ó²hù‰gžÉc-[l`ÊU#›§ŽíËWñ.ÒJGjs@ã;U¿Œ[»MQvUÞ(ÍŒæü²m~-˜¹uê_ë7 b5Ðã5Çs£îá·ÿŽ2Õ6 ªà Ó¶9ý�Æ+¬Fc±Û–j XõìVTPø˪ù>qÓcÓT¶"j@·_)¿d“ƒô‡rÆD7•÷ê~ŒEE¾R¼¿ hQ¤5"^'WÆ1~¸vÆð×C–ÆeÝëág?Œy sqåÁl÷²â' ‚yô3NÓÖïQ^@lG¦I@ßFNæ_MKÿdʹ0¾Ž�Â]YÝeÇ|ñ_rœ+7O9<8”�¯=RSQô��†.¯§N‹™´�Då�7¨Ó÷i'xÛ~E>^ýÑ­pK†�Áá°�ž3¢Zf€°è{xö™jG‘û�W®A0JÙ­JÝîÚÃ�î±½—X±Œsí°¬¡±0fs¯Ÿ²º†®D{[‘¯¢2-3èïFÚ)}Jû1šKm27ò¯CÐsû]gv¸Å�uùÄQ7f”ß‹n¨»A+â¹k#)¸n�)š°}Üš! CíýãYA2 Ã䨊ˆAü¸~�Æ/˜ ‰ãô!˜ÑÉÒÉå±?çãÆëÓ–…ò[ãSVª­Oê­nkq©"Ê8Ÿ•“¨5†°ù¤¬„dqpx�®¹BÚŽèÜÀŸñ@<°í7y<1-CÊäÏìˆ{wâ躥Ýgñ±$˜ë?'0šÍkïJ`/—Ù,Y q«S<bñãÞÔsk�Óžc|ÏÝ+Ù6[˜ªfÉï¹Û/>M–öV^HàèAcZð9�mtn�"˜�}Æë¶¼l{Y£Òü=;ƒÓKÂ%Áò¹|†uÓ˜ìT^ËÍZ~ß,3:‘ê W4¹K¿k��!5Ê’èµï#0ÉÞá9ÕyŸ¢{ ¤@„"ú.>¥G7¯èÓÝ¢ Ç-Ì{<ÝUÜWïúa±kŒ²ÑOYþnõ‚¶€ÎÞ಩Zí†bU|gu9óšAh¦�³ÕD 3òK£ðò0šB¬ ~c62Ä«Ô\/Ñok÷±A‰á�%7ölV†Ts׻ܪLcƒkN4Émíæô[k°*°I»Q*-TcñN�«›+ûnŒšÊ·Òò/ÆÛØ+Á–pñ?�í3çÇcVQÈcáÉÖ µô ÏT�›@õÝß5ŽåpÄ«>�ü”ÎÍ >Þûؼám*"ïR¶m ê¾×$Ø@aÑÀзR˜ÒÉí÷�°ó§"4^µ™få€èia19I»W‚N•+×aЬ-Ç›ShCŽÑóÔ×H> ÎcåÔA^/�¡én;”¤�´ö€ˆ2ñÓÊõlßÔ þ쥓Éõ˜=™‚—Øq%–®óLo“Û™‰øÚ3½¼ì(  X!1º¹ÐuÃZxýUâ…¶Á¨ùv]³½®øþÜþNÙÖë¯vž37=ä²VíÁΰíVò‡£�@†nË 8·(³9ïw@Ss ] †¨‚Íðˆ†é¡¢íq_ÄxúH&~X´¸±ÑÍŸÆk"ÑÖŽÁ¦ÓC®äô°‚sœ)8ð�Ù%m8+ËêG¼�Ä�^RIZ�õ¦áUTÞ[¨qrfx¨ìJ¬Ã÷ŽßH··T0cÀ:„?¯ ìø„5|%3å/$svŒWîÅbŠõ™~4)nL1ò*ðƒK,‹z•<’Yº©«?‰�E»‡ TÍ2 ÉêJç;<¥é)‡àô•˜aî1' ò§ê;I8á­ŸXÏ�ÔwÑgÃ*˜¦zT�‹aŒÂ§–y×Ìfl§²>¿KƒÒGÕ\e­f—MByŸ«ÏÄâ’æ²]?Ï@HäݶÃÎÍP^4÷BN¤ûhù,Løòš�*Þ%f}- ´È<1�Cé‚i€,©1•8ø°ë|+^™B ÿù NcËæ7Z¤;JÉxaÕVo 2Kû–øs ÒAøb•¹ö� ÊȆfô‹×Xq¿¾ 6 ´Ö�¤¶§¹0XuŽÖØ $¶ª™û¨nä\Ùý�«mõ· U»�n¤è<Íiá–(ÒOÞccÉñ¦G¬ÎÃ]O[·4 g»\þŸöõ “��7 †ómk™6‹F®,‹Ú}˜¼èì&‚J#x䩳ìiÖ©;XLÍ|LJžì*q®å÷l´böÜZ^o®HX{Ïä®Î¶3ïóA¤R ï |¹9ºF±ÎØLjƚ¼–- ¦‹ÔLC´ê8'E´E[ðü�çs¨f'=¬»rŸú¡A€YqOKç¥øY#uâS–:zªiwÔÏöêøS âbX†ÚöOŒ.¥Ûø)àM@gvHÖ¡:½$PUÃqé!\T:L7 ³Õ3:7ÇåÛ}ˆókˆjëŸ.5Ùœ=€)É­Ü>fJ§qظ °Þ�˜¾#?UKF£¿´ÆKº:‘¸Ú�Nxƒ3Ž4qÉ2 �]ûp•¶g_ð{uCÌXE¼ç2õ+Îê½g°L¢â‡—b9}gk©è~©Éé³/…;¯ýÔ…pöÏ›`“ø0µ½+oË}ó õ¢�I•*~UJ»~³ál½¥uq¬ä´™›´FÅФe/q·Ôim­­õØ ³¼ìÚM¼sÁÄ b™vù®¸nM°¥´ûÓN�®™Dúˆ>JÃê¬c¼Ï„Tå¯"Á~mÍÙŸ 4t\>€¡e´±N¬ƒêXd§( ]ÞÈ�,;W|$µ`2¬´nš±u6”í€Z†Ê'ûò�T×&‚JXqSõðí¾ðÅ\Sã¼§Êf&g,c¦ÿ»ŸP 7>ådþ_ž°ë½”)=&T ´�>{œ¬ÐÁfÛɸ¸ŸÁê´ö×=„N¿éGMm§a˜†!NÊ,Eåp™¥ÍGV‡çTÉMR…Ýh[ÀæÅ±‘J§[ û yÁÎ%ÉS_öÌòŽ3™5®Þñg;¨°¹ô$Ä€ç¢ÛƒBÿ¬E?¬)XøØåžÙR`_Ì5åÊ0/ÁDLÚlÆ H©ì±¨Fm›‹ :g›q¼!C}`øèr^ÑJg\. mdòÏW²cs¸¾æ¸ÑzS§Xd·‘<6)tÑ•gR(!T(dãåPýå,DbOáH-ÛŠ8Ñ4ÓKE |$s­Ô'Ü Ï&6<)!(º+_0–e½i%>Ï`úY�OÕ·¥Z$ÍŽô‹u¹Äk)ïÉw´¬!*ŸšŸžwÀá.KÝŠ1T²Ø�F˜‹;%\ß $€ˆ¡Œ°§�0t–I;m¤/ãà{ër¥Oø°t =†{2Þ~ôl±Ñ�ȼ6®¡"�•PŒ.2¥~®Šòìf®âØ—R†´¿­ ²ÌÓÞ¬Æ¿ï€Øëx¹¢y4ï$ãè‹<’Ù‰®eð!*ËÒÔ«ÎõYÀ-Á >û@øûóÿ JX÷”Þïfäòöµò,C�aQ¨KÇS³'Eö…zäfƒpÿc¬  ò‡ �‹hr}®øÏÉ9yøüéío �àÀ¡±¹_À‹ç?Ч vX{+ïX‘Ù&¶Ýi0 ` ÞÀ�ï &­'ö2ATq?ƒÖëƒb4N®Ü´šj0I§�P×Yõå zLtVn`ÖŠ,b‰03æÖGûT(#CRØ *ƒ„¡d3>ÙnëÎ OkÁ¨EËí¯ã½JA*No„ô ³7PHØQxïñŽt¤óQ¶ï÷½Ÿ?m;˜�¯ ±Ë±ÉÈ �"@Û+òÈÁÿkFþÀ›bOøbµÚCò Ü�Íw0ÜÇ"~ ‚¤ÕË�Å÷´–“™ž¶÷J°•ñ�±Ee ˆng³´�œÀ»¦/>–a.:B“¬Fjš]Òlw–�%d~DVZ´ÖÇçÜ<þ“(ÚGB7f§>¨n •o‘_ñiݶÉ.`B‡•;㌬r ‹ Æ«Éûïl‹/–ꬿ±¤&¥¼€I™×UÕà9·n@2~—ã'”ï•Ã[á®C-=®ÚNhã+„³ÙcݤÝbc…y�MŸ+G³s§E¡$†ƒ„ù܇Ds—’Øiò]3BÙ‚�êQÌW´̧F²êìÐ8g£J”åÊOAïºIx„è.òP$žd6$jê\ þ¶ÐÊaõ»n%B€0Ô¦RåL>Y<, fÁ�!åc‘1/õ¿SªÜ’”rj­sSç3›‘æ¹ t3íµA {ð!åþdnF&=÷ô*Àdþ ±‘¹\I7ˆTS¸s75+píÞ€6�xÕïúE2ag�8 á¢05ÓÚñ¼UêbÖjÑ7n¯ËÎø�ˈqòˆ+ goËKKõÉ�….µ§HQßKÜéÝÆ÷徯ò0•‰Ü[wv¾â{}Hj½Ç8¯ìè&W,@@n?­07 w·äë¬Ç·ŽPª1鈱?«QÊ’þÓóÛ� vš˜²Ø¬aþ�;·o/±kÑ<¥VŸ eEÆ÷=žwj«/¬°Œ2á4E¹Ï�I»gM\å³ÿnJ`·�è'½Dtê+ {î×Âú6Ü�"êÿBœ­ìü@ k÷ÓÈ/WÒTÃuº“‡¨&xÓ¢,У’r/¬Tp–H¦åOË?ÁÇŸÙ.稸5.סg¿jP«‰#Ó]ƒlððF@J³x "ë1ýÆ»iš{1…HñÅg92üü�ÜËNKó@è·.EúM»-°¦-cã~ƸäÉoõ¬Ãž$ôÓƒQ%Ìz”‹Ï§™Ÿo®0r±‹/�íPÖjÁ¼?Ë'5TenÏÅL™²l0n¹`þ ©íG`ªZwÒ€×½Œ]{ˆ‹Þ ½/8òÇSSý­†ùê½æbeøîü¿d›%†˲úNº M¡_Är¹íÊ[ÈØé¢%Q<¶/!šiŸ"¤ËÂ%‹YoèdÌ:çè Hí“ÝÒ ~!Ç"¨æ_0­nû¬ö:šô£k�䌭�63Ñ =*OhÅMÖ‘ßoÍ�J^PÔXpŽþQ°�ÕЫ×:vò}ÁxHÞùδGÉ�àÁÿ;»EY:nêO’5Ƽ.Ið… 7WÙBþ{³b¥éŸ@}KÔ;N?&[­YŸ©öÿÁÀ*bz"×i"—Lj¥0ïæÐ¼XùˆUüðSûë6«Ûw(ñ3Ì�(B=¢°nt|80M!ª'ZE£”b>‡T”“!ó?¾s[®°¿K¨€Oâ—Ún´®ÊºåcĬvfU)dX%#ˆño/4‰îÏY¨ØŽt�}а"X7‹îaÀ,¡y;©ÕéÝ^&S9)E‚†å,ÒF6¯÷Ç{ßx;Æ�~³²A}áÖt{»Ÿæ7ï’ú]Óâ~=mÍh[&ó�ÒêU¢[ÿ “X—®)‚G›y !Ÿíþôâ[ÈP?‰³‰"Y» ¸‚öÀ¶¤Ï@1C&A€7\U‰'@;"v„`ÜâB%Vï¨âƼ1÷!Ö ŸŸjÂÃZaŸŠÄµŒ7…ɨ2a¡r-ÒÓ“Q–áÛ?7+›´fúÖ‰Ù. Ö¤+´I{¬•Ò(€‘½Îå¡ö†¯„&ÆþJ¿Ý Â9¾°cà&Ke׬äŠ{*4h&zÙØa:«Eå%–7Hã#ÞûeÝ+÷»¤Å],À‹è‚™1Ô~}—v$\Á¼ )Ç–�\ا ʱ´š;ƒÜI’L¶bé«F¿7ù-hÄciX1‰z¾¬Æ5*Mk³óNà„(¹Gò4}6¹‹uÝÙ7Rð2yZ[Ý]43·Âm®SfüØa`q´Sß‹ ¹Hd7:ö˜vµæá’‹R*qó•‡ÖxA¼7ð€#㦤959ôèûœùdfÙ™È RwTòØe¼ˆáÔÆÏq;™0¸d†�ˆ�XÅD6w#-ã…ëqbLT²v‹пðI^Íh±­r² —ØÇOS9†€>Òð;{n(x5WQµbâÖÛ 7° °R ;sw‡ê`.å[â‘¢i‚}Êžc Ýçþü~É‹/<丄7úÌîqLådt7˜xÝêºöU$Çþ‘qW0‡­¥Ý(¥øMˆÕB¦ÛçI­aÐ z¦Ø«¸Ì}?oK"¾ìæÏ¥~Ç‚#5ÔØqfX®j›.ÜÅ€¸}�ìAÃ!V4SI}Öo-65õ¿‡Wç¤ Üô¼šâå L“Fú‘Ðydé¹ú›œw‹´�‰Fõ²ÚDÿ· ³6ýM–§3IЕ¬ÓgEEJžF4C › �MSœ³dkÛÄ9 ¿I�ŒôWÿÄØfmVIMq†&³ÜKógn‡µÕÏÏËHÕgŠËdÊx1ð¬äVX0¯8Æ[?úÃÏ®íã'™«qQäP-þfã4õ¾òüI·–шÑÌÚ]¬.Ü*±ª„²IãÞûÅêÄTŽQ"ÀK÷‡¬ …3s2M¸„š{ÃâK£»kÎÎl£b�\wöÄekž:p7—Û�Ræ 詘ÔlÿûF ÅŸjsãà‹à=2òT¡>åe®Y´ºúJ¿fcûdž¶ÍQ> ñ¤%TröÕÀ¹i_×Çb¹±{ѪPN‡ã–$P,y‡/ ÏáECœUM ¸“»&5ñ= ÅXÖƒIõ9Ù=´Uc ÆÝ¿_ý÷|ßô�üÈéÚ„ÝâxC'¸ rÛ+”4dý`Æò£ad瓟õcù˜¡„-{æzX²Ié[Õ�4ߌŽ3óeôó9Ã(âÆ2¡vË–ÀÞl^7(Þ “ᥡrÉ™­dÛ—óŠsÎÿ”h•a ›'[š¦ n†L ”˜0&Ö©[vݳ#æÙFÒ�ÅðÔ»Zm~(?ù×Y…nh…yu¼j<õéo»ºéKuˆÃ<¿·{/Øk·Tÿ Ÿ¾nò+gàýh¼=2<6 gJAYBŒ�µ‡gX¤Ý¸÷€­ÀVÔÛçàܨÖéwÖ¿õ“/`R ×_0{n<®Ä´Ê“kú"øRîÉo)± FLæâE+˜÷™@ Ì’¶‹}8†’ýëU)˜¹õú ×¢œ(@v[Ä+ö“5’óI½¶îø´ˆjNᣠ|·uÁ™c<0aÂ?�Tìã Úbz¯Z)ƒúhP7ó ¥Æ`�Õý2Ø«éÔÿæÇ;¯=Ú“Ëó³1ÈÃÓöå�Í«FµI±õzØJñÄz¶ŒE¯5˜ÒU ¿þ¸ëÒµ¶r•X5ÃkDÓÆcMfr ôf³PQƒã³MËC…'„¦�T›NÔÌ·•l’}á½Ìe|‚ùÆdºÙ)[x�w¢ñc5.…L(ÓO:êqwBõJO¨ìê],޲0¢5i¿’Hs?‹á{“,ÈeÜ 8¨{>„;Þ}CÚ´.’áÝ08Îþ¹X¦ ®��Äã]°<¤¤JGw…x𰵨þ†e…hÜjζ"¾èÈp„ñ;5 œ0£vWbgóñ"þÓÜ\ïQSæSõH^}¿_�C«DÆBçœ5"ERP5ëÍàwµï‹•qÒ´øAq�Á´Ceöå(~¿©©Ü3KgÖ[ÓV‰ÁË/mõgûç� g¡5ëÍýïÎýže‚e¡n€EýUi;G'~ì’:+zêTc}åwý›•úôI²ªn«×d-�çÀìÿÀágrÏ‹ëéU�›2t.#ž¶ 8Ôô”V’Rí\\ T¶e ^NšÓ‡Y¤ÇÀ²zÜ™]•íëø3fØÙ‡‚•bo�F>ˆ¾+!ôþeÖû§å7sÈÌÊ�¢Ì½{%WâYåì$¼VÖ;WsMVC#{ˆ—È«‹�žïôè²Sÿœ™à\9+÷!A±ùÞŠZfê±BxTÓ-.x;�zNdE�øÉê P1§ñJ S Æ�ý•-J¡…ë¿C{Î ¿Ðè7È þGe�…¯ðéã@«B7,ð$ù€¬P0Úû}¼t qK0`Á»q¹é ¦Ë�Z<Ÿ”3¿›TiÈû8fÑ�öÛ‡!t¸êõ,^ù§Œø$¼ËÂ÷s[©ŠC¬Hj öÚT|õEÃòOf$þ–âÙ¿#¿%Ï‚G”OH\ÌŸo‡ò:ß_7áýöæK ñ{§Ñ Ø¿|œ»Å;°Îß³uˆñ”þ‰�Ï9¤†ìfçPt·¿ü½÷y:�' ÆþÔìŸÍÍÎÆÑ¶¢[ã¥#áÕ8aüF!)>ÎrØäÉÐÌŸ‘mâU£¿EN#PܸQ�%^æi.Ћz´Ãº_¨t\ü`[À¸¤rít ×*1º)�ò)�år-Îý·²t˜gÖ7¡QNy¦ï{v¦™Ö28š‘óøÛ¡ìþ©å6ŸÑÒ�}í"sû›šµNiÒãÆÐHLá‡sQïÔüà,Èùyxyšár‹0 ˜×gӞłìÙc‰+$ºîÞÂF½ã7k}:•£ ÏÍÈFP™ë˜³6ˆU±IÕwº‡ä‹ŒÌaÙd¢ê¨d¹%¼xk7ÐØc’ßšƒmÇ!ÖTg{«ˆ&âÓ%~€<¡$åÿV ªû95ë>™?@í$sd!;¹õH€h8ëGÜÀ&¹� uá’d¯æ §Jwó“«Ä:…š€íIjñýÕÖ>‡r¸ ïf�¾íʇ;RBu†¼C òhc̱€ò$÷fIÔž›ß!¡Ÿ±× G!i&Rí?.;<:ËÑÛk7þj—¤® «‰!Â/èÒŠrôv=&k#Lšçn”È«©OÏn·ê3Ó<³”î5ÐJåâ0?»*+ >,›H~ä¹tc¶�‹Jäg‘MÑJ¼mË×T›1¿€Š)ÌÑ rÀUg, -^ö®|W�:äÇâ�@¤…\A¾²O!ûžoó*K¶îªnÌ®sb¼àœ�ò=�Ù™¥šgûùßfƒ6¾8A¤©¬qÂ7“c ­£¬v@,íV_y}‘sã¦CŒð¬þçY]],”„Çåí¾ýR"¸÷ÜsŠôXf*mq EÑ$ÖñMìÓ*E�º."�X\{#Q÷ÛiSkµv™ÑåÍLŒ=6ö_²>‹=åOG`å T,­:áÙuÙ+‰CÂbMÈ:M$~å¿•ÊRµkýid¾ôVIÖsI8ÀRÓ•]­�I;Iûöqë�¥ÆÏsÓ *LO«–W·¬»ç\õ!ÜMÈóBä�-ŠTNÞœ6vd6ñɬ„¥L)nËÃÆ “�ûìÞ–�Å}xÉUæ¢R~¯¸ƒäý­ž ÓrªJíy„·XŸ86iú°…Dò-úLèí*qT¾Ý¬�¸l†`&ª12&o̤м-3¾†F2Xëµ®–á` ÃIâ蜰,=LæzU9–cÎ'Zº‹ÀÎ0+€‘»—KH¢Uõ»F!‚–gZÁ¶Òqròl³@‚öM€Mh¨¯Zi}{£oÞ·µyœP‘_9¼rñ?_"©qMêíïGšðç—Ðàø‰ül Î2‡h=éæ˜Þ¢Œøûî¡'f˜Ô:z„Ãt(A–½„Æj[³ûÂpv*¹b2$·–¹°×$ˆËonÅÑ`TÚL¡LеFªœvõ�0p1"½ |…[’+]Ëê·xí¨5‡"ò§Ùq¿¼á’çFøtãœ-Gȯ‡>$‘à[dõ�0]=QU-—{Ê-ŽX‚ ~Üzó2P˜Lz¦×ÿ>Ú‘�I7b¢'·»a*‚äcN;Bé+½‡2¸=ç=‚³î�¶Í(º Æì5¼3¼ ÇJYܤÕUè‡Ý·’¹mšÚidpçí|º }UÏÔI3/ŸA��F;6[úKý)sÊ�[©Îvûi�Ñ—?I=-UÁÿË‚$ße¢•˯çÖkæ ±ðfÅÏøí!ûô$Q«Jðº-0 Oç݈„t/PðPÇJ+`»p_Êž9&’6Úà'aƱL[!åƒØ~#šä‹­a’)x‚}žnß8% GŸï30qæBF¯ªpX¶ ’–·�÷⛉ ¥øHÛP-ØØ]81<±Dçµ»j‹¸‹FZ]¿.E.­Ì�t¦FM@´˜a8"÷¾C× SÂ,$ZÀî¶åjyÁ­N•‰BCÚꧦ0ÓyÒÐû°Ï3Üç{i¿R¼!›[w/3Ð�™Øù°õ÷øºÅ4M P�p®µ=í&——×k!€ßSÍÞü*®ûžr±´qyI€ùæÛ+yþØYâŸË3—Ä€\•1Ú© Ùáš�E2KY…¸+�w¥¯w«u¤w6»GŠ•Ù*µÈ\u…¼5ð¥Ùw!ÂO"~MâWîw'”9‚Z–7ÞUé9ºAòYÙøžÒ¦«,V,¥ÿxÜöOO^•lÞÖÈDÝtJOv?«ò¬¨Ò¼uކ�„Cßï> ïÕR`ž¨Åµ§ê}dèD²ÐbI!]-|kµ(°äœ d×?ìPw`[ŸÑ$*9pˆ¹ˆæÌ ¾ ´%A@µY*ׯ8«@²ÎGxÁ¨ý}ãg<0,)³‹Ó½"‰¡”Î7IM} à–º™í˜:i×µK+$´i<;|!´ÁÍUÿÍóýŸiúæD²°Ó÷»éúqeô=&6îÿR“‚çhTÈ'#Z•T�ìVÍo-`Å^ r>mö#dh;ª'ÐÿWN Mp-Þ3˜ð…ZY´þÅ͵†ÅuÏYÔ3í­V#ò¢W3%3Y>ö,ÝvhÑz S,ý}¾S½¨…GàoËÎQ°WRÈ:<õg:-ëm¶ V%ØÛ ð ´c6.Ñó÷›S«¨Täë¿5$œ9«Ãv P)PšŽ»*üjZ©u¸ÕûüÔOnr–Z¸ólk9ƒ¸WSˆ"¥Ì +™)é' a Žˆ%=Æ&¿‡½oÉ ‘¶�Ô) j\Ùí„£ŒTU,�ÈÆtM-ÙÕö�¬Z2Èü&¢1«�7ÁR;—1N+ T™Ï–fŒÈ$�ׯŽ0o‰ ÿ ¶l õI¿/´ŠZAŒ¨ u•ã¿›;‚3"GÅð×Cû—´ºÅ£uÕˆª]©Èù8›~of‚«à+ºTâ±x \9*ùSæ°oÞ³øŒ>ÄÍ-U/û'ÇC)±Œ]N¶é°†x~V%€0‹k±î.2§"`Ã}ðµä• »ˆÃùVë•(‡§ÍùJÝDwµ\9€6¦óFr�† àÃX„Ðó_À~˳Z…éö·ªuj¥Àà‡ …-Ã1 ÏòÎÞo7ˆókÄÙ^¥ú€·Nt�º¼‡o²9Éòue#U¦_Îôk±ŸŽ^!R‰0QR XWŸTpÈ[ŒÞÃã÷"ë|¬˜ŽïAZÀwoIÚ4+P°§é8ÔpóýW¨)]!S¥äØMï â;C€ZÃÙ@—™ 8³šÆÃÑè4ƒìL„óψW�³êà¯ôˆáNƒ-ˆ@©�Ë{A®«ÄŠ«YlaÄ[ÍYlcÐÝâÁ¹~v‹Ó»o¨w?xu²ªBÞ2Ë>èïI��Ñ€éRŽÍ„á/]¦püIˆqqÔÒZ%³_ŒÖ�Ÿ‚ˆZçFeèjÓ(T ¼³}yû†»eöTæ{Ûßûfj*§‚Ýú§±¯h>3¥êý?)îh7C¯ –‚+òÜé]p³h±S™éê’ÚG€J3ë ¹í›oq�£�‚%L ‘IæÆ8b×Ù{|¦uñç:ºÜ5wîŽå͵þ“7;duß÷1;4ÛÍ–"U·¥à¹€*C Ø?#¼5Fc‚ä‡Z.|»¥}ž- ³çØŒ²†IâÖnît¿ƒÜ?Ëç³_ZL€Z!ÕªjHº¸U¾ŒB ÿ}èp==m}"3?¯�eø˜¥&n²„í¯DÏÂäªòuéo±šÓ†ÏX>/-u e/<3·Õði%ÝÝ%Ö‹AÒ¨ìŽvŒ€‰@^ÿ ªu¹ÑéMU¢cMø³ÆæþÕé(#Ìr[�*ÉžAÔ©7Ä*]Çëgë»§L,.9ZÌO±Ñ’bÉûFd1²ˆ†³KÖëµËVߤÀ+?©©àQT2Zå,k â¹7ròõ%Ô–ŠƒœEäÑ'ù¤–114ð/6$�\“2{ÿ; ³_whÍv£Þ4n-Å !¥ÁÏL×aÉ hDœصc]ˆ–ƶn9écÔÔãe~Œ¾EßÎ%éÈÒ¹÷, ¡›i˜a¶Z ¥3£1µ§I)ù"ö‚=–bˆgôc’Ð)¼±àmÀO¯Ð{Æj;7¥ ÅTYÌIïDCxÒ{¬âxÚÑû‡öÀ®ÃÁâ1Mù¹?X‚�£g°­Ì[Ç-¤Êv¿:·5¢tLpÎ 03¥œ�¦úm*˜„†Ï«öKîTE^Ák…ŠgY¬¶´kšÙ–¨“WM ±:ßU'>1Û•�O†—¹FYQv<]î²Ä¬‚I³Æ=×–î:ñL)Éc!#çoH^@’'¾„ƒèà¸eb^ÄCKLPçè’«+ðGÃÔs5k–#_�áTýB¡(»*g¨þ€·*«6®Qg€øèø{eÏ!†.Á›î;Þà´c*ÇÚKNU—‰e‹=v<Õ¡$GiÎ�½±ºodO[âgBìz×5ºŽðj‰e$õ§±Éù+ò]�6D1ø«Ž ÏP-amÐ\åA¢dãÚJ©“Z¹é u#¨Ú‘IS&�”|¾öϤŒÁ*k 1ŒOï} •/À“”Šb«Æ�÷ï¿ p»à™5èÅø› (cý“JÂoÙ ^puM/Ã?ƒÉ–íþs{‡€Ë¶ ^hÓ©v/€ÀÉR‡E![…`Ⱥq£#„‚ ?—ýŸø ][ÔÐÏh6Ø?î÷ RßûhîØ ƒäì.è*?gþÂûj¬üRéÖùÇáÉȕɶ�ÒRM4<µ ½G�p6iå«úÜëYëŠCÍ4sÄA|ëêhõ×óÿŒ£(îÙº5ú“u-Ä-<)–‡^æ`æ¤'j`*kP€�]Õû;1d€¼»]Ù YçÓÌ .çEŸ1;kà&»B£aBïB´Çû›Ä–ArÔÌÏs0XëhÃMlzpH=bñapWÅq·S«�­­ÜÉ÷5ð­Ywˆ¯dªÆoÛIÓÿ^÷¤Ë&´‹"Ü%À4¦çþË0γ¢§DÔΔÕ"‘ÿòIï¥CJ/ÚêŒn89Ô &'‹} fÕ‘¸l¤Þ�×Ý\fÁÐE4íð9ÚÐ&ãiÝEˆ„ü­Bº°\çGA²—ºâÒ‡Æg‘¯EL!‚¾ŸËÝ$&Ä"º*‘MÙè¸÷V+Àë= Ì^ÙA•P‡Å[’-öºPÄ)`L fû°ù΂¢2ƒþd)@¡‹ ­9Öþ©›+ÑóìBR¼ý_ æ©)Ù«¨é5&ëÙ|ùº?ÿË–«!/«ÇÆÛ=ïYà5cF\_�Y]ÛI†hÈFXŠÔÚY«#fuOæóVBÄêñ'Ы´^ÔÇSÌnÁfå]5‘‚'d7B‹0-4Æp”œ Lþ¤±BÓt†bÅ%}<^×Åpsõ¦¿œBDŽÏp=}8�ÅE�½Å _ó»çtN%¶ ŽìJÐ�ljÍcȲ¬3·bRL…Óí†hµgÞëY¤;oæû9YˆçßK`GWðÎÐ=¤] ÂlôÌ?û‘ÆÙ ‰ tu�§Qþ28|gÿn º„:­, QX·Ý§zQ�b]>Ž6R€³œ‚ä•(õ Z;…;Äí8hßéÄì üörgkŸ®T$ñÄ…ùèóš-#»¯`(ÖS2°ÝÒtr¥qx‘N>ÌwÑbï—ô\$sœn>ÄïØÇ¥NÙ½é‚#dìžj9‘¼¥Ü\„!l9 †lmlªÃoíåÀÌ£œ¹ ë“jTÛ÷»b35àbUþë.⪔G6e[eš(Î;~»!MŠ“U¿Z‚iPš¶^,£¸?¢ÈzR«.o›«û!ö§‚+öXvb{Gì›ã†Í~?™e�‹­EVÚ´e x`9=�u—¡a›™$÷xu)Ž«åŒ Ètþæ/‡[•³-ÿµAÿàgK rZ«¡Yì™~¬‚}è%û‡+ý=�|ggÀ䦞×ô‘òÎe²d+]"áÕŽ.>‰œÌ!T ¼® ßo‰ÝN½`%U“ƒªu±¸t”†mYº½ëÝa/ÈˉQ%Æ:Ó§3”¦&³²©ùefMÖÉ`w9ITÁ˜eã¸0ò¶]H­ýg.“nÇB¸4ÔZvFßœh�ó£µü\÷eb¶néh-·¦°‚¬~‡”_§)VM- ½ð³\ˆËnãíoÝ( ƒ #Pp`†.=_™Ù“�–&poÑ®Ð̯I˜¹Þº¸ÒÒ­*ËW÷y°l>¬‹ô ­²ÈËòþ;Wc˱Ē´Ÿ!Àþ©œ›b lX.+¸#F6–ñ¬ôNÏ<Ú"‰€[34Vpö‰îç+k°Ö€/·_ÿº5¤ f¢}hÜÚÚüýÓõ ÂýâO®j)Àh/Ìéý�¹²}ú9ñ‹=vJ¹pת~Ë6g¿ÿáDy:}j…Ø�ŽËŃ*žñƒDÐÞ\  íé˜w„i·“+–Çú£/”¸sûn-û¯nl�k~X¡iO¦ Ârq·ýõž³cGÂÐy4"Ÿ˜imëb&7çÂçóNHg,¢bÀEŒžómrºÂ0Oˆ3†v»œPºsXúòs=ѯ¹wÒƒ¯ôÓ¦s�‹I#ê¬d¶)£ìàÁ[z@æ·Éו=–?µÚº—rXÆÁÊ·7„ ´‘¢Tƒ%8!©�à�ÛU¶ç ëi×…{T�]Æ3|ƒÎx£·˜óA-üÌéyÄ*ŽöïNJ…?NPf5Zí]|8ÿ&jÛ€ènó¸r§m�'H†4Rü—€©©ø á}S³QÛXXo'‹Bl£ËTä§{µE隷 ‰œ,Ó„´é[J<\›Åù,8ù˜3Œ¿¯Í•e¥m­Ù+T±Æ¿h—€zùþŒà)ØW œk�°îx!'hXñ‹˜Ü¤þ_*¨>‡“ý[Böïlùxî9}v9¤D6…o×iÚ6sØ$×ÅCYæÎ3‚ë[“ý»�¥”ÔOdbÞ! &§„ v #F„)—2‹§Ïò:ø‹³g]Ì1™Sv.I^ý Àóú¼wÚÆÓz~›cQ¸®…§–š{tE+ïæ™G9a=üí;¸7@Ú$Ï3w=V¾÷ä)&è³ów &Òø#Ÿ±ãTEºD”e@I­N®L˜ÝÚáÛ´ÍŒó:1ƒg3ô̆4|°Îé'fç•”Õ�`ñE¢ùáÄ™ùêgV¹êD™>j2·¬Ï'8Ö*rg=‹†“{Ó+¬Ný¿’T£“µu¦ ã°Ö,5ÙMnÏ™í1Ì1âS‰Ùµ�•âóØÄ#ƒ|ÏjÚ�t©‚ã½Ü¨*Yh:áh,AçGC[¡�d®4P‚Ñ…üÖ5Ý)œÁ©` 4Ç,“‘+®é£"¹2¢¡ÑYHÞ‡KD¬-m»�IÁÎRXf–|Æè€Gd #R'Œp× �.ïp§�\ßdu}n�ÙºC ³Çâ+„êh-âÛä"Y–M}p'±Ë®åÔXñ(ÓwD(= ɯú"æPfAÙõk_½\Á‚º+@ˆúâé ²–Ðj HÔNÄÔkaê¡”öÆLdGwâK®àäøª¼ZÆÛ ¤,A&-@r%ÔÖ�Ï­¥Y˜Z•‹Ööò°uS×_’q�Dw½òà\YÎÛÍ~�9€¢ › ‰›Y®Ô)Á­h„ù×e™ˆ”‹Ùëä‹ù]³éZ#p·Þ]©]ýxÈÉçÁ0¬òÁŽÒC¾ˆúèù.ãmíÂa᪓×Ý7¨/îd›Y/e‹�]Ô÷CÞNÞèS8eªþ<ü]ùûpGT.5â°m£y�mgðÔ`UðÇû¸4…%JŽ\jâånå?ÍPôÄ9 uÍÕ/Ò�ò=¯Ô²Eˆ;îÌ\i©�1ÝÚ0Øspš.¸ßu °Ú„å±·Ã0òìÛ^ ‹3ÂFPú�ekކ–!ˆ•wE¯§ #O­„j&Äl‰sÇ)«¥1¨ÆøŸÛsßW»œ¿)© »?1i9»ûŽÈig$Aå“h]8+ Nf„8àoø²|fêk ÖR]ÕŸ¡uEßn‹57/‹4q$´œU•V…fû‚BÛÔ.FXŸ1¢ #-eu%½˜�}¬¨Ê]xÂp̯â±Y䌙É:ä&z„P.MGó× Úl† gÏÒ‚TGÛ” YnrìØOz bOÀÓ›tÇÏBªé.)î@Š�Nðܰî‹ÎLTR–n/?Eœ\¦J eK¹gº! ?1D2͘§ÉwN–o:Ç ùÕãùCâT#¤�fŸÕõ)à:XcŒ¿6{†cØMé�”'×Ýä*:L%hãy1 ›µ�µBÞtýxë1}Õ¬Ð5"‹Gl½Ø¢½ƒXÔóM!£�pŒÐuÆ1ÿˆ î¾}RµB–¢~Z>²Œ”ÁÃN�#»Ciò�ÏÔÉ¿³¶O¥i4üpsl�Úr¬†¦Ø»žléùWówY+ífÏѰkKEôúÁÂ"¾÷Ù…wý½å3êawWDI â�åègáÒÜ‚‚xÀ C w¢h&Ìé‘âSkµ"Å|Ëš| §MÏßéS¥®{­ŒhàÍ'Z™}N†}ÿ©ööùÃæÑ’æ…r€ÍkKû÷]¬¾w}“rgbÎUUæi¦¨×í7M{]uð­¨Q+ ÜZhŠÚ'Z ùuhGoבÂ(lôF†�Œžeyv¹„gŽ]²$}RÇ�®œ�dxge;ã{�h?¯bE«&ƒÔj¼9¯‘‡½ËÖm›ëîEJ#fkPбØè° kø&ö¡Büìu½¿nßî_3DÁHѼ”/c>ê4ÒØË,+Ä “&#˜ø7̸¢beލ¾ø«¸”è] ë=p3Z.N!òÉ…´@­ºôõ†ŠDã ršŒ�q¾^ˆ÷~�k>b¬�GË�—ïT3íê—ÙnSÊ„¯5Tí›k‡2ƒúÙðõ�ƒxÒç�;&h³Ð8É>p@èZUG¸®£º±�â&Éc“áÉ`;_!¥‚œ”uÁ´RÞ.†é–i9¸GˆÛ¸­¥+Ñr<¿Þt7šYG�îµÖº–‹1ÏéAà66ï%+@êã'Êý×¥3îu‹½Cý·ˆ�W [– ¯Œý#ðßÞ3FÆ òîàA‚Í^¾òJáK–õ42,ðbÛšŽÝ™AîŒ#’Ž×„ÊPVèÐÕÉ£˜ÿfƒ·ÝÌÔÙn‰ÿÑ_› cRylEH�=‡:œïŸ2FCS²Z_ÆdîOö6:Fq< c19IÛùè ®O.JïÙ»0mž 9XÂss Ö©·¨ç#DºíY�ÈÚSXlý\¨_V^‰ŠM Ð*íá7F;§òÿ6“ªkF“[€£Ž/»”êíª¤•ý }B/�A}mf/DÓ±$^çm„|¤¿ð¢÷�¹ç^ÇÅð(��@œ1H~û�[eï-·6×Ó `—סÐâ¼�zn¸°¤8TŒ¬i»ZXÑýa }ö~ +÷ºí@s䘬çßXž|!ñ!�xXó›ÉÇäp�|AüŠÒ~À—Ïšž€¾xÑiºêÿ…˜OSú5©eKS);:c8En|BÒ˜ cd$­±£“]Tü³À�Q›E�ÕéÌõî7eFFA,$ZÂüÐJ.,ÀLeA¦>ãŸg\øÊÑ<üÊã«äX=íBŠzVTFf›/¦MlpÑãÌuXéw6â\8ôN[»³¡þGGk¯é„¦][A›/‹*� ÙÛ[Ž{§ºÅµ0Pâ[hFG%ÇÁÇöbq'£´wp¤øI°o6½%m*¶òó çƒúHmqز½Á–œ7 »÷;ı±‚CTÒpl<ìRƒx¨Zz8ƒÍÅ’¬ÐöA Ø D¯ÛøöYûÈ ·q3�q6—$_¢ ‹îÓs(A„­¯;‹ôÛ%ì‡yOÈ�‡2VgþßeÑ…¿ä¸aÖlùÎtl|}ºÐlƵœ¢!ÿ½EZ`¹€›ä!Ñúþ­_½C¯Ð¶(�äk>�dQ¿¿k7ެò—\ÖàBÔð†’E@\d"ÈÊ ׫|ÆÃÐÏ;0 ¯Ä«t!?ŽøBÖß]<q½…0·±áçÍifŸ†ˆ)ÄÜCj_^08j{“_xfòžø†düÔÜl·šý¯Cvy¯óG Þ¿0ítsž³¤ÇkWòs¢ëú¥}ˆè÷"qü YÐþ²þGò°Ä—µOé¤v7ÝA¸üé;¿ð1- Í«Šü˜Å$蛾¼p Q)WÿJ8»ãû-Ijn)õô5›GÓF‡=R×\â;ëý�ÛÕ-¼GŸÚ¢ÚuÅœ7�ÃlqX¼aà #7.‚rÝ$th™"†ÙÈ‘]ºØ ˜¡ý4!Pú­Çœÿ¿Ã¥ãŠWÓ�ÀÆòè—³ûíþ¬~!˜2_“‘ph¯òŒ{"wÛÝ#âLI5ÇYYŸ†9â“ùl—M½EXÔÙk»rð~AíñîÒ\•õD/z)¢Þò²­v$1±.Ôs�Ñ-å¡ Ox"ÊIÁp^üÖš©�9ãSGèÒXd&U+æ’ÇÒ¾Kv�ØH©¶«tŒÅ »DŸþ¾Zv1›2—ž¤ÉÈt†a0\ͳþ5~²ÎÎ?„n÷ɽ®ÔõšèIÒð£ÊxzOÏðÜÙŽðÇÆZ)è?{ÿs¤sÅQ‘ðM;zšH×É•ºOè‡4‘Sæè5¤y8±å4—À#Ö`Ô™âY‡ é0Lù„�–wVJùÞ •ý»)>l¼\H’„vïu.¥Å��äj…H 0q¹ DÔÃ\§f ø.UäÍü}·QÇ­pްvÍ�Ví„6l%]N“Ë(ûC÷_”=˜z½‘×G?¹»Q7›¥2)³ëû°±ÓÞ`Çur.|•Á|ÓY&§‚)‚ýR„[jØ ´PÓ³‹�´™óq »<¤îî£]¥(X³BÛ�ü—þ§¸ÜñAˆØaÅÚ»£ÜqomÙîœå2�ä×!¨ûªÜ˜mÜ5„hã?ô¥sÓ0Ú¸ôËïÀ àÂ8Ô³jkÏÏ{ݦ-®ë}Lzï u§X�>‰ HœÊ<*(û¢lD"  ž"À× ûý´HðC\;Ä ßH÷2³€Âí�Óë�©.¯™Œ$3¾Ðak_±+ß}Ç)ã$V‚:Ž5$X‡ï<Àßñ•H­‘áW�UXÈ>šDòË0; Ì%¬\Æ %"�Ÿ£kd¼OeCÞ– ¡>;j|ÈvC5�˜|eY›G–Î[òÆÂ§…_*ñYM®À¡� �IRï‡4 'R{5¡—û䎅8Êñ{ñ]óÃAW‘›‹çk6$Çÿ»�²™�´^ŽÊ`§�çôV!Ê�O& ¡fÕ®Á„þµ(«­Ï mLmæÍÑ^*“lƒñç2‡`©ø~¦áÈþsOê›oï9V¦õÕm)£Ê«ë†î%9:ž›.¯³"}~H Èˆ'¨JêOQüÜâÔûSOÔ€‡.›Ãr-òÕ�gæÎª­Œ§ÝA÷gëLµ8#%Iš‚²„×~£U‹Ÿ‹w¸6&3•„ÉVÐ?ÆåT×dDÅša1XJ/…^¥ïî.@ S�“zz&/ºÌ Ð÷?�U£Î©ag5¯þß´Nþ0¹«1~Gê*2eND"¶\ªL›YĬHج—¶£Ž{ð_¡0ÍßQ5ïŒgËê¬á—˜¦Ê+ûš¹U¯äzÉT“*Sëy'v¡7Æê�k®Ý/ÔLô|Ì4;Ýlÿçà ]øa4Aymœ΄3…"î'>-àüÕ¡J‰sL%tg¿Ürá¿ûX1U¹eâ?–ÜìaÚd´ÀÔŽa/N¤†fçïlç†Ñ®”µ_=.rѤ‹Â…�g:u½EoKÏZw€úº†a­RQãO®qó6öï¼ \ÞÅ쨼©t¢€�Äò¯üÚ(æB3C9²éÀ2ë «q Òíîù’㥌†º¼ëëf Ð›Ð�Ê}b/ÑA±Wò©êÖ¤®6W= #×K�6ƒO»€ŽÒ8·…2so}Ï šÂ óõÅ×39)þõï{˜vо k™·û)¤ñ«› Ñš*ÁìÙwXð9õñ®3zO¥RõlÐ\R“Û:°WMébÉ)h2*Û¯ùWïç”bÃ&‚ª� “3Ä{X¯�å ŠÖÞ2�£~é÷+Ññ¥%›d”èaº&}ÒÉžwñž ŽÓ«CqO†ÁYÌíLŽùgÛ­Ü9t£Ä¤Ý^w°W�&#Öb òÏ�SŽðSTÕórAª¦×MòÞ~Ï®±¬RïUXÑjÑ0Ç„äÜ£X–cÅx· 2Î*"×Ca}2ªt1º1Ͷÿ™ˆ£Ý»_Ï˶Gâ(ëa¢uË9ÕiÏöÎÀ mø‰Ž¤t=âõÉDhΑÙ×DlOì©Ùh§”ü¤[6(õ’“´Rbÿ,+tجÌ3MÃÛ²I’q5ãÔx,Œíeó«ß1˜tºŸ€Á³ÎÌ›|5ÕÝc„ÿ ¼ <–ÂPàѤ­ä*g ÊìÙ‘\-|¦tJ°ÎÌX¼²ª”ʬY ܘâ9µ�ÒÉ‹–fø³dA[›Ž»PÅ,¶»™,^Ð[Tc”H|È„_øÉñ°­É[Çrƒ‚.Ôj¤Ý.%óÃWbj8²cä‘©\Ï–Q/ÂÆrB3tʆü!¢g.º"£±–å<`G5‡ið𳌚õõ}Iʸ¬î£ïõ¶Ú׊HT¦hý:Ù·Ö¶” „ÕHýAÑ»r)3À•!iÆo¿R1¹ó €»á˜§ÌyQâ;›’2�Ë îÝ»€Âû+g_ÏÞ¨×8{MЋ×�Dþ…XéaCS±NöÇñuùa ¶ ‚sø†}±-ò-­8 êYFpk�ö‘ÎÍìY.‹ºÌ”¥_œ÷oÜ×±Ä#e-¶§»—åõÂNºfš†}Þ­¸±ï�÷$FvKøÙm¥e›dŠ ±{¯ šPœVû�dŸ'ÂVÓrü.]d5'âú"9^ ‹Õ7ïÔXC|ëBòCÆ–NÊœ¡§¢‡¡ÊÏu‰¶åqlš^ëÈ13bÕ“!瘴`1  æõåD·u– öÂ/›qa™à¼†Ò¦¦ˆô£\&äI· 'Z@!ú+Â�dÃÓ ¬_7/µ‰í}3KŒÏkfö¿ó™üô�À‚æûƒõ¸×[{Þóš]ÈA¬³±â¸&ÈÒ?_­E¨ ±x~’U·¨ÜÁ�E`nL5x„©L!¦ÄK¡žìqŠ+M­ÁD Sñ�sÜä`–Ôï«!ÎÛ8LûXjCž4ð|*øLy² "žô”£ÌÑÑ ÿŸ?6²‡Ë)sç€b[±·¤Ód”YK«t+XU9L�s‘R0 %ÌLWò=<8 œÕПÓË�Ffá�(%´âYCÊôQ¼V¯[´·ÌŠz»a�D¡7–‘4ô{@¼©±ØÀ£Ä…DÍå+ò¬‡Ê׮³"¡ØÚ&Ö»÷ ë¸ó™4e¶9o.ŠL&IPt8,í/P[�©ÔªVRç¤Æÿ4GU‹¸±2Y÷ËqÅ"�(aÆ|{$Š™97e ô.¯%Cuqĵl‘ÒOyYÆBB×›«‹n@P<¡î±DM�ßê”fëµnZ1ë�¬æ¸Ùüog*Üûfo£ä¥µöhWêz‹ãêó Ѩ•€Í¥ª<á�&—ÑWŸ?@Ô xíDÞ+ÌÛ´9ÈCË.”D`UË'ˆËް魥%i¡|¾ëµw`7–!‘d7†‰ ZD~=×"$´7Ò‡-nï%¦›Ùìü‚¬ñÀg/ &dC£1¶ÔWRg�?Ì~ã¾ ß”<Ó—[HIác L¿‡É¹�–oó©�h�ÔÑ´2ãÆ-ÇåÒ3"�¥ʨùÉÜ…3lX�¯ÔNÏéÕÑÅæ€™Ãþi¾WÉÞ¨ó�Rȧj:LÀ—™­070³ó+ò¸3«Ñ i¼/6Ò(°Qg ­–|X�¤*WñÕ¿Z bÉhC’ˆÅ@]Qš ÖÞ™Žme­Ë ïÓÛA* p¦Óyå/XûfÛÏOŽ©²ô©Dz{ƒÈ£ÆüÝ­ž[ †ÃoQ!{ÎB4—¹7 Ì_xfÞ ‹·{k˜°Ãõ‘ïÒ²�t3ï©Ö™ ò÷ñîÇEzúå¡ß.ÇnÑ”Rû$k˜{�ç|Ș@E±Ð`#‡ú�õJñ�b"XJ°[?P‹m (îàUùÕûq Yǽá}0HÚGáÑÎj]5ÿIá�‡óT¤ÐŒ5̯̚¸c•ÒöE[PŠ”§;€í¤bñ8æÞ” è Z ,ÃRÆt)wJlò(cò‘¬k�cë$Å Ù wøà\컎:—�C-ë(•äF$? »Î­PÊ?`€WdÈ[?„“ÎjõDÃ�ª:À/„¿”æÆ}'íAZ HEnñ÷uèàíÑÅ%¥Lyž ®IRIþ\jMË!K'àNHÔÊp<:¨ÚBêÙ¡,ŵJ±ùíyc@gîA“%�‡}GÛÏåeÈ '¾=ô0;H_(âm[¡ ¢àÚl4†ñ$Â0´ �–)“b>ß8C�¨ô*¨kæ*Æ q©ºáKNQ | ÿ_YÞÝí§ÌÚ¥'ø·uf>sŸÚæ÷lCuDÓGøØ0º+ mây@~N€Ÿðêçü,á§ÅÙJiiEž�†yåö¡~lÎKRÑþ ô/à´Šú%~|$Ù‚£*�% dÞQÚlÁ;ƒ&‹Èõ�:¶x©�]eSuTŒ§yååû|=˜ÊPß«­KVJ„2¶Aθñé À"Ð0šçQ$†09P|ëc9Ë=ac0*œê„€€ÆOÚ‰À3Hgp4GV’Ÿ_ë�jÚ¢—YtðÆ}B e•‹W46Ù—®³cn¯&ÏÈõà!×ɘ-â(—îWgÏÉýÖ‡ÇícÎð8ƒ b•ï\—‹õ•k^�ƼÂüYg’ȇÕ=õÁ`(*�EÑŒ÷‚Èx‚6—~Δ"/êæÀíÆ'èÈ]sà1a�p�÷ñß&^û4—nÝšø=ín3(ä�ÊGì3=`¨8vÍ› œÚÄ{û.&žë……°q™ÇÌØ½b—™ �‡‹�„]8î½½±o%‡¦÷â9öù†„[j©@È/¯C 8#|»¼½Ùuïj!æø °;ó¸Ü,¢ÝúhâРýnq)‡ ½ ¬U˜ñì j*êœù‚Qýð*öˆ=’ÖéËûCÿ~Ö�–…æ$'óMÂ%»‰jôVj6º°‰®ùͦ ®åÉ^4‡t@!x‡a¶¸g»,×è5N¯eìüyƒq×Fdû‹Ò3B¶,¬u¤iMúSô.šå½RúQ«DQih–KÐXðtæo1 ©Å´�ø,û—‘t75!Üö€"*XJy·haÑkT€Ÿë\#X§ÎzFÎÊ,Â:þ‘Á�³|¶’G~ÌSÛ4êóB²Oqq&ÑÂÇò-etŠ.±þĦñoQ¢O’OQ“ 2�[4¹`+§&È„Îwl'@C[7 ™ÿÚ¶ÇýÔM5qóÓwLÔþÀ$H[>[ã¦InD+µ%,Àµä{q™˜2k{ªs¾ ³¦-E´Á·"Xi!ß×~¶—%CÏNçêy<•&{Ç�•½Oê­¿+Œê; ±r¤ªô}¢P/¬éFO°É¿[IZð¾xëý-bÃóÌe_P#êõ–i ÁŠßÚ}ü‡ƒ®¹™T’íf#fÞð¹Æ¼+ž ”Ò¯¶â F6R!�DâºPV"�4¾æuëX£¤p•eÎ)¯VyÛiµ4@ S£ È\Éý+Ô<’duØþ� ¾mÀUiu´"O„Bl‡¬¤÷UwY?p´[è Õ�Äs"äIFš"ÂV㌃’Á—ŽZCó� ¡‡’³Ð|Ë<{µ‰=PD÷6Ó4§ür-ör!-«þ$¼Ì5M× ´"¸[ˆKÚ¨!/�–6«qÔ!ñ—»½-Õ¢…~èÃh TKÔLjÅÁ£R†ŠÞµªSÜÈr†ô¦}Õv×fGY– ¾�ˆª?1¼™h“™]~f)˜gkå×òÅ%™;Ó•#ˆE Y¢ðhPÚ æ®£¾Ôä 븆Ù<–àÖ_Ó¢PȺŠOü¬;Ç7°¶FC±«³ßôm‡Ym¾mj@ÆÆ�:ß§<5âSyÓ ÓßYÝêòŠL2åÏí�42%}M15oÿ‚Ù”î$Í2/íPúÿ‰ý:(,…ÇG…J@ÈT�õË"î~P¤ˆI…jˆºÙd«úY×6ÔŽu0¼•fß‚EtUvÎä ž>ü°Û Y/äl=Õ•I6nÏe\æÞ±_t ‘éÞl¡Pä–ŸWÑ_cTeÓ&>Θ¤ªª⌢Â+Ñ$Fœ�Axƒt*@\ J- bˆmz`÷9LK�˜ºô¬º°Ÿ×çH7ï>íÌ 0¤Ö×1 M)he �ÔÙET€‡únÎ5BÚۨ˪ÊÎÆ<+H�l>^žÙ˜œêY�v³_ GK…ÿß²·¸kfO3ïqLÖ‡ÊÓ s–“„:dúLªš'ºíá‹Å�†÷ GgNkkw…b­Ì+€>–]ï�0ÄMzš£²+†âƒ³[Zɼ½¤fªæÝi`¸ß�œ+›U³ð¢Ð.…V¬G?Ö½~) aØô’U@ŒëžP‡™’p­Ô¨)¥6ðQy¾ÇÞM¥ŽÀË .))â.âûBfß5ìBIOŸ5nnµ"®36W £Ä)A†”VÃX5aƒøßÊ“ªO¿N—ª>e¡­Ò¸ÿºw›ôp2OY¥Æþ®«EK4–R.¼§ ÜàÌ÷¬¦à…Î úºI\Ë™…Ïz,õPCEØÚz,7H‘^‚ã1×™/ùf÷òôÏ+~CD •²Ž¦F# j¿v¨©Úi ùuŸ÷<©†9ãà ¶÷�”«zÍæ"‰4k*¸¢êõ’�n&FñOÏ€^¤N 2û%e—å\…}XÇníe³b;‹�Âà—mko¾‚˜U©ŠZ*DcŽN WÞƒ.>:DP)c�>ãsz’Âò×Â…©•<Íê8|F÷y¢l„龞P—„¤ÿäÙ�eAh®ƒíÉgB ̆¦ʇ�(Låp{°äTæµ;Ùsá§]`VÀ´¿¡¢qÏ;nÙ�Q>ëQeðKspÍë÷C›:|eg FçŠÑÊ•Fk~9™ô­h¥((Ol®Áa0hÏcñ#H…ÉÛ£Nƒ>dΪ,}ÄÈ?'Ó—LÃAH‰o…nÇ�±V‰hç†Éo'${Ã5Ô:ù¸ذŸÿkÿdGøl¦EP8.‡�ïˆm\øLÀIÜ7PLuƒ¾Þ¢;–ܺ“&t`ëê ±Ã¢”ºÕ¨Güc>Úµ>ôVY6´D¶RĦ70S¶®C>™‡®"Ñ£èÞ¤¥93ØæÎ¯_‡8Ìñ+…¿^ÃP¯šWû;”+çºÈ¡PÁa-gRxøé×±Q?4ž÷£Ø ªz%Ê)³r¨dûor€*FÛý³D4°¼¯RƒËX§''ùyôà ?ÝìZ×u@*áGšGÁ>ñžÙO|%@”ZýéË;!H±Ñ6bF÷�bŒ“a�/P.‚Ÿ…n<ŒŽ= Yùz^Ûª¯ÞÑ”†.T‹[sÁì§â?=ƒÎ¢feï„ivs5X‘bG©Z!èŒR V-…Þ•6@YïÀ-:¯ ·ù÷M†whuʤŽéõRÒ¨GñOÜÊŒ»ÜÆ9)Ã+Ý‚e„ž¾@âÖ‰�ûî»f|’‚Á�~‘¥kîÙæˆw[é´‘wöàxä8-Ž´ÿsá@(\™(ãlAs ³°¥ñÌÞ§.¡ku­I˜ž“p O•EÝ5˜¯”4D=ŽévúѾ²7Ì¢œ¥)cúþ°h¿NsÏ‚’ÿÝ'"pí¶zß·‰ uI¯O�-�2=5yÃ��à_;õë;¹þ•™©ôŒE¼¸”Ë·#òh'uÿ-ÈÆžÒüÈ*†9rYmS|Û§$¸TFlûF£­þòs¤ºó�o5á©eœMjž—R“¶ÂÿáÿøÊ QzÚ1;i¥é»È,tǬˆ. �ÃîÜ”[nÉOä»Go g$-�AJÉöŒÇ� Vbº›ÍÆã¬ÝÈÐÔäÏ'D^°eœÜžûG Âá�“3L2Ê�qö„-BµÆDe^@A #È­va›ññ ÔWêlrp¥¯&TŽÚ/Ö4ÒÈð+cUÉ�ìǰ ¯18{ö¾…„!лmáè}Û�MéZï™TžEdŠ Z(‰mh�Õ¤l(—ïgû"0OEY’¼µ�"%Žï§5´Pœ.Ùò¦/O“ÀVÕk,´"µÌMȬ·>l‘Æ+Ñd¦Û²„ª±qm<¯ßp£S´i¬†çP5A葉bÃ3ßZ½ïþQ�¾úèh)�¼Ì�ÁUºñ«ÒùI�,K«Ù¾ƒ�F¹¬�ݤ~g`?’…Üh†°ÄÑZjBÉÞƒ�ÁhÚaÊùDŽçÈ®ó=QHÇÑõûŹÝ1\«ýA:Â#®GÇ—¬<4ûïü7R{7çF~e�ܨ8‚ïò2•Ç@ ªƒšˆ|„/¦"œÐÍ$…+—R¤‡ kÑÊ;>ÆH‡%Ã$ï5�©[ßpÕOüv|·f‰E¿ÎÇtŽV+ëbe˪H¯ìÝÝGÈsú;þ­‡[ÚcÑ{S§%›ëƒìÐ%éšž3 ‚'d,îHfCé=džŽÏS·TÆÓß‚XìPG,�±dh›þFJ]õi¾AÍg–²â�7&*`¼ÃzÁ`ôziêÏo ~ËU⥈îSÕ‡H�VïÔó“Áñ" ²ha^¯×þУw“~ôÁŸI¶ OÛÆSwöŒì.Ñ=î­F.ŸGÿÄ1o¡Hì5Иö¾¹;nÁU;¢†Ó¤¦ãÒó§Zñ<”ÉIhé„cR�f­‰*ešñ-FâèàÖiJ' Àó¯&,£‹Y¸‰–“&¡!Aõ»ÙÁëóÖ›ØTãâzR͇¸ÞHE®0ZÔu·ÍQ;Æý—PäŠÿu´¦ÑW« _øGºöuµÏöY»¼r"‡RˆCíHL}“ºV]d+!Ý.•Ås¹ªuQå5µW…äˆq7;ùFXQîð,W²?ÞÄìw·ÚH‹ÅAé<€ZŸÙºЙ‚£ »Ì¿îI"AøR^Í'àe@f!°~sÐöù‘úÉ-™o’Ž9ÞZ™Š?�í"�Ø4(÷zͬB°ê¿WǪâ#=Ïš —2ØêðPTËè�êx7U³bl§8ȽͺR’ãZÖ…£¾”Û¤Y�õN¸º—µ^Ñ–jï½'ú&W‘9,Y‚¹ÖÉLT�×ÈAŸ·0èŽF uzÜ£†ìJìy!¾–â:£¸iDYÁ¼UþºHíN, z]ÞèŒ yV¬iÏÙª ™Ðxb\|ƒjü÷C`ßù+¨J›iKÛ4/äZ^!³ÞÅRí‚ÕóT ét ÉéÁ½·[}8t¦Ï޶h44}º°@{¨E^�³°&è�z-Ì¡äÕ^Ù0JB#Í>‡¤olëûQ~ �S´¦Às¥”“ŸëcÎQo œ‘5ÀÅ,¹~{êNœ†‚qž§•PÖäć]Àr+UJDÔˆ~­ •\ú3ëë׀ϻž5ìü×.Z·� îwsÍ{±±¬îÖG$¡áÌIZ�pðòƒÀÀ6ÜJøI +öh •kdMHå›þ°ÂAöc �j ÓK<]ÿ§Îç±�Wxb4O¢ðˆ¡"N£â÷?d\ÃÌæJþ×õi,uè!ó¿òMý sNV®É- F�4k·ÓšïI”Ž<>²:+X=ŒlÜ8¹‰iB#`/£ÜË'5é÷òŠñ<;ºþ}(ëÙ yÔÂŽp]ã|’µ’$øjqúÇð¬…ó¨²u0!¤< 5X‹ž S¡vf¸…ù²_›W€ ³à[C)µÿ¿¼ü[«:ƒ˜…MW?*�ÇrüÛ)j‘ÈIßž“„\d¹y}Úê¤âVýæ­ ä0bÃÒËë*S£éŠÎóŒõ„껾k�{övRS´^ófÉá†avY;ú"øqÆ~E¬ õœô:ž_ÃY�Ô€ZÚ­ßDð�g¥4C“$ü�Sp­JSÖQðÊ÷¬©XN ~ÆJïÛp¶[øÞv{\˜Q"Êík¡gó�«ÂæyØ�Ð`íɤ�ÎRdQV—™­~ï]6¯2Ã9¬ábrü¨¹QýGIšÑD—ÕÎwò—æ”4}Ú]n',¼Œ”>NaÒl¸¬1ŸñsÍñqâ �i:[æAúÊ “Ù”µ.x[áüTúN0çFÿ‰ ½à°ð†)XXN=\szS”9Ì.SNï꫞b=Ov¯³Çt·GiÍ{ŽX_î¶r)�jJe& wPƒ=ž´{/,Pò˜f g¶³íMt‰jD L  0\ ±²[ûcð¸3YÜ0¢QJñ WÇ@iJ…UÃ@Ÿy¦ú¹U=ÏkÒÛU ´ºµ‡�ËÒ›©ÔºÆuÓÎhup@}¹X,¯•þudªXâ±à¢Çó¦ËÝ¢‹Ù¹»•ŽÕ9®›ž|JÀ&ü â+ƒÑNR.ƒ ´¨Äß¼¯Í­ûô7¾Fo7kzñJ¤P]V‡‹ÔÉ¥€´„}–ÊQ‰�C‹ª;õj¿ŸßHG̦ªfD>ȃ#¦›'=¤)z^ü´_‘š·Ñ´86ùMÜ´„I‰'p6£"Ú±‘»�Dß,¤_ G†¸n90kß>7Àªy™Kxÿ ,šƒì$“%as3È'}²}úmùQû–цh¬XØ/PÒS6X_}ˆ@ézzȸrx“„àÂzYœ{¥UÇéŒ#…ù´¹¿#7‰kBŠ`/•›rcrá½t„*n” Ù*Ú¤=,-OÔkÉ -U;ňAACµ~]ðô嫽Æß,‚$$“Nv+çMFÝ<°Õ¥ç»l»L$ýŽeøD·�yÆ+›+o/R¼�"˜5nëí›ØIfj úô�–Y»9KÆ9üu/}S³¼·\vºãSl�ñÒ‡òô½Œrèà©Vâs ¯•ü¦Ä£xÊyKcmX^iœ;Rž®£ÕÑ1Ê?i&UÊt³~î,~6™Ëq;2iúòò]ÈeÂXL¢Ø'/_b`�~x4îö#Ÿƒ`vvà:²}o ¡¿g•·•UMåñf=2Μ[í�ö«Ž¼!·€�¤C.FUøŒ@vì"ø]¿cýAï¿lò÷ØòØxiuú¬÷Û¦�²TÇÇ:bŠ<28ˆ“ë‚;”éc¾¢‘Ëõ ûñÍWä"éÞã˜Ééw‰@±ô…¢Y~c–¼À‚ÁÜÅßw±•/¨(–s|Œ3©ý9ô2hèøøu9*ø»^7£“lÇò3äΩ»LÓéO ·Ë­ŸQìp«<ØúÈÖ3Å‚CŒà½˜¯¼8Ô�½Œ!o¦ž¹ÖöUJ6ÍWM­ÝñŸM¿�í1¿­¿×øÄ’/ dŽÆÙ KÓ¯xH“¼ÀýhD¦#EmX*¥å{APt�Øüd–®i�cøq+Ô+ÈpHû¿áÚ¶¡<÷ÈòFÇ{ÎÈŽPç»…Ù 7ùNÐØ—š& Œ\·½å„+¥hzzU4E/CtÔ3Hw%>/QH Ì3›–‹44#ÊX>P´‹¥›_™›©‡¼¥V1Ÿ- Н5l­#—ŽD]©—GqŽõµÑ˜HA½ë2æ«lȤºñ=ËOIG‹¨ôãZÌtÞÀ¬!èjéĈ¥:êÉͱ-êÏåQ ƒ’|j È䨴T¿Â >ôKð`íci!Æj =g«£·6Ábí—=GC ^ò…#ôõâðNamå}@¾äÍw†W^|z<ߎ5ý­ßc¸Ûp¬—Ù!Äâᙜþl!:œŸþ¹xÝÔznÛh®ºv"dLÏþѳRZòt¹·!­ØÀ6ƒ¿5N>.dDap 5ÿ#8i̤†JÓvãÔàpè¹ÙúÔö‚C;¬;¥2øé®Õ¯5Ÿ,¿Wì ¹¹Î*ù çK2׿¾õì;#6ˆÝE.Œ»7CŸoŽ2Û!b¼çÝâ²—ï+3U(u[ño¿³sÀ9ˬ(!&;`Š?O*%®L œÛRØy"Ö™˜µSRÀ<ßÕÛ7P5(ÃÄ…jµ’Ê›åïw ž«¡=÷.dñ÷ø-:IUÄêgò´¿:5àóEYæ$QEÏøç9gàØã0}¦ùŒÆM<ëe Ô1ÉÆ�Ùfð“�•é“9Aƺ“Û°~3ÀEùÞk°œ˜qXCÂ1ôЙþ» žl?‚pŠ@*j,øÇåÅÏÎ87 ;-˜C|mâLgÁ[1]¦T).ÐõÜ!‘íÙüÁZm®sAIŠR*gÑí�ÞŸ ãâ ÚúÕ À]ƒ¾¨6üa¬¶Øý’ƒ×¬›9­î‰¬_$žë^ ßààë3T(@Ìzæ ˜$¨eà‘H¯¬¶À¤rÅ~"DæìÈN]§c;Šè¬Ð)傃©·dµirÉù›Iêþ H•$ï™Ck%ý\ð�P4[OŠmËο�þåD$n -‚¿JMõõ+ Ÿ(x�ðyÅ:\™^ÚX;2´å<ü9¤×× ÈBÍÙ£)ˆÜjlì(¥á[l ½%ðôÅD1r’Ïää þ^kƒŠ§'ƒ8Ð#€­Ï8«@jùuYÀµ®|4A—ö6PÅîqP Ë‚GnL|‚×"Öª[æ£Åd#Rk] •­f�®fzÎh¨Âj«µ¨{øYÀ"²¬’Dû�Èç’ó:iÜßY²»qF²mÌömXï§d_în£O©¾zo\á˜]{¸ªÂk^ŠM’†¦(XS-á¹âT*]&G^Ò§mJFý�§×€²Ö~e^\8K„f×”‡Š-n [~¢ôáLQ¼'jݺªw§˜nÅË;¬V’±KTdóÕX9 �Hà¹[x·ßÓÂáÜ#ÇxDóÞ Çx…Ÿ´5�øÿ¨ÿrý=\B[™Û¥\ÔF6ã×Bߎr1«SVzÀSCŒŽŽ²ã뤫"¤° Uù”“¶bø';0´8îM˜œuµ.qõ¥ò|UŽ�C >V/a“ÙµM¯gý[ë²âš™¾V+N{œƒ²¶K8ÄRah™Üà³m<)Ö)Á’ånÍèMÊ©üÌýh�-s¦gyOÃ:C9–«~†ÕULÅiÐëÜòC~ʨß^…CsÇ;ûŸ‹8ÇÎÈJ‹ÀnÞøÿÏ͑ў ÍòÖ%™ê$\ øªp¯©S§¦`ø¡ü†–L4xøã™—¿,ÈL"ú…”Ž.푪õ:Rèêfp¡ÚÂB!§y°k먽PLÇOU/éx‘�‚J›’Oú¥¸§xy¦Ž%�*/wªU‘x¬HpÊÒ¹>Îà ±A†Î#‚…Ird€^²$ÒerŠpç½¥ ¸ä˜| —\#‡S[éZ(ò®u”kÑñâ[ •;zM€ÓßâŸ/¿�“ìXjÚ•4á°†�–îðL‰7Dëk|SÞs×_K¢a¼Ün, ¦’G0È#Q2N}½ÇRYή¨­ð ý°/ð£Ÿ&rQ¤·à¼ ½H7Ç–ølöH•y^Ö�MЀ¼?áKºþÓ½MsRÑÌßVöG�#ÄnþTÂßPæüGj"ö˜}–ŸD �ì2:Ž ,+ƒ{ª¿:†]^!§D^ru-ÉìÀØ<ß3«<û¨ªÙEá{åeK ‘]Q­"¿ŒFÕ(¯CTnhÚñ�S6=DAÖÌé^½D�ì›"WïЗíjÐãŸç!õ4ûGhÀ¨‹¸Tµÿæ9�ïò ÕÖ´’]T°íPÐДBK¨­+ñÃßo!ÔÁ9?3¾5~þѦ㪶ŽE §½·Øµ‹¦O<7¼ÃZsæLS\ºžÞ í®C�¥nHvOªv¶ ü8¥3ôgD·AyÈ .«¥÷±’Ä’?:ÖÙ©”�¶.W,®,'ueíV8J*И lŽPUdÄé¤ Ÿø {usIÖrªà£·Z…Ç�ñµa7€Ô*Ma+yc}bJSÿ,ýÒÔœd¦rÞíjKzÄ~ÝÀÔ$ƒæü�Q£Æ}¸V•2’WãÄ/Ï—ñÈèÔÜëG* Ò¤pZzÂÄM†(4nöQZø-¤!‘½6¿FáÄïa|Yßž^ÚŸ±`›Ž-‰ _jó~q¥§^cœÌ³á0k…†à±âJ•ùmÊX¥´S1‰£ç¯ï“S8†Y9,袎®a?�؉ÉvçWnÀ[¤„©" a¬³ÙkÄ×3[;ùÕ®iLcS~í¯l�§«RW-cù«àÕQ“›n·oöè;ØèÙìëÜ0”בÒLÌ_½‡ÒìÖÑ”\%#Ç¡©_ V—ñþÏ>1½·^/žîcñŸÈ¼žß‹á3Ød1’ŒÍ¼–a#&Nã­ÀÅw…Ø'5ø¸-­rQ|q¸ÜÜËBÍjÔJy§{*ì(g¯8ȤÌò!úø�øÀ zº=¡~?×ׄùo˜,î—Q;§r”Ë;nÑÚv=fÕoT¶i„#íV9ÓMsê4À¡o^\…ú?κ­ðùøCJÖ]´¡®ÜŠto0)§MF`ï— 7O‚6õ¢Q à�'â÷˜BvB(^ÃiÎЧ�–Žé�EpNá`|”ø7‹ÜCˇøÒó›§Ù*ÍQ‹¯–pØäæsÞ¼»ÌQ¤Î9KØÀÏ=b‚,So%hq1V²°œƒK� (ʃٯý1²&ÉO™YT.{H*d¥‰¬ WŠê¦µèí7éxáA©FÞ{ØñX.œcë•ÀOÔ{éiÛ‘jµIl3­.ZBk‚q¹‰�Ö$«^Ô¶±–>+‘MãV^\÷¢gœZœyŸ,ñÿá%^­�VîÛz®HP£ D 9:á™Lá@j«úgÇì n*— L#DÅeŒh‡ì˜e‰¢¼ö°KñŒ›ß<׿vÕ\Ó†\ÄÉ 0$Š> D|¢ 2ÒjÅð¶êÅ]áXºÍXé‰nŽá¦Ü£ûÆ+€]¶ë†r±^ý‡¤)ú€º FÎM·Œ°×ËCkÚR¤J˜ƒ<‚¦µñ«ÐeÕ÷ùP  &o%‹vë�U®^ÿ\—¦=|à-3Ý\EK‘Gp÷®gbMA;&ßáP(Q!Ö5‰ÐsMÀÓ^®²ñWüÕVpg¤RÌ¢×8ž™Ñþæ"'?Ò+Všøjã›`Q9ƒë…TR´>ms=l5µÐ£R Íg�7QÉ+Șgw0À=K°=Á¦>ꓚµEtyoø=„ìbૌ8ùKËD½˜ƒgèªÓ*[«ØZí"Ò¡¡„§²_q,õm=*�L‹4 þ4ð¶EiS¥X`Ÿi<!8=Ž<áû¢Ì \‚‚ÐFKÊÆÞØ,̬Ԝ”ÝE`>C�¹=Ž5)’èz-,))׃Ëqw�Æ]¶ê3Àú’Cñ+´|¥?�ïѯÝ!™!Ý5,âJ$˜j’€Š.ÿy|¬çž¦6Ý‹”4xAô„�çÌ‚N)8L,É¢¶ÓÒ[ftÞáë¢Òˆo"y)LtPX÷[1ubŒW¼ šùa¢–š²Ð}´uüÈzt7*Ò*”O!†{7ƒ=5`»‹v(cp­:pʸnº®¢/qsxO\OЯ’ç¶_ Ђ)…W5;±ÒðÃW}=½¡¥8$'Ó9›Byåx —ûNTpkƒ˜ñ #Zÿ4S¦u+äGé³;:�ž>JHJ0®P4QÿĬc£vø³Ü ÖÇí« ˜›pÆP¹„aÐ;LŽšžvKÉÇåz°’µQ2ˆg,‹Ø©!X©Ð)XÒfg½óžZ°ŒvÝL@ð¤3;¸§šš-=)ù ÿȂٯ[ûBþ ÀÇñ6 ÖÙý;èP¿Ú‹DqÖD­ûÑ�{[ly�Ž[è¹^þ:ª_CU_½7ÎÆL¹&Z«8Cн–Ò-ñÏñæêÊDùå¸õ2#½ìÕGê‰cõòÞq¡ÿu˜`÷©h¼à�áçô~½pîhäá¼Ñ[#² 'µŠèVËÛ ª¥DjÖ/�bÔE0ƒÜ?;—kNîfå{øvùŒV¹?`Cƒ>‘xçqC¢Ô ä»PIïp^‰†¾Z5sc-ÖqÍú“¤’‡Ó®c^ݪäŽÃáÙV6A™½ú ´®.'I³`£Þ/v“7ÈPÂXȺ�SŽ’im4‚yqŒJc¥Å£Ô(ø°o¢¨5&ùÅ ;{Í!zÊЫYØÆÃ�Ç¿AçL%ìõu†@ý–’¢}Iޏ'š¥óà¸m"B;~­¶çsð7=FÓ(RžÞžX‘~õ¿Xêµôr£è‚å �z…û_4¡Àøõ,Ús(¸T¶VÒ!§ë™�àÂSDÄûÂ’_·Ï)€Ûg×¶B×k¼D\I3yÆ£š Èë§“ª·wà/ú#À0$¯ U/öÂó*?Ñ1fAÖ?OFá†HÒìªÙ,“Ÿ¦wÁH_´Áþ&ržóqWƒz ,KÛç (©l¬Î[K_Vùò�V2jhˆ}&¨/·&žYZý¸bÙ"˜ƒ�§Æ«"ø?)¦„U¤y½|ØøAïKFÑESÖÀDCÁ©³{;‘بYž\èò\êYª×—"Í`D—5½I˜IÙ5ÐùíÞYíïøJfkÎÓÌs͵ÔfWàWÙ!t)ó™×8/q|f¬51¶�€xS’?íΨ °ºb|Lƒla‰CôáDV×W ‡â]"ØQ!¼^-ÛUC ‚enô¡$[ÿØžÔ†ºÚËë}�8W&ÒÏ/{¡Üþ;ÑS˺ǶtV&x¼=’ŒNþƒ(_<VZ³ËU¡í>èòò%j㯊”˜F#׃C �DuÅY”"ˆÂA2ú‡Tç<®øYøè¹)Ðhæ¶ÚTyØ)ý!rÕ8Œ(eK�V›£F¯ý‹µÏ7`ž¡«G”_Iø}B QÑŽÒJB7ÊØo�Ø'tâ]‚'§ëŽÑ°Õ¹qÅD�+ŸšªQÏBrUËÛ5n§Z¬ÍÁ=¸}Véþ)À}í¹ž�#Yé¥ÛTà£ÄldnkÝÿ2=(q‹5u¼ž&�vx…Lû~HQæí‹f4JFà iéµ*¼™ŽŠKâ‘� 1ë�a ;ânNæ¡Âˆ.VWÛŠ=D®ºþå£'¤Vù Cd(ŽT-ãôc1ôÖŸß—»‡ÊØü”;ñ!*Ò3H+±’¸Z¨Xs¶˜>ÔµaæêÖÒ=[äG )¿ÅÖ«ÿ¶žÙÓ ç¶oÀ jUûÓ•¼•õíø’Óõ«|4¿Ê<2WlÁŸuõ†&�é°Ñ‘ßZR•«Ø'E!î‹héÊ(ªKójs0Ì‹ö]sÏ[Afô“!OšÈGÌ̦pâš°Üç/›‹¶+q6c|Êå| 0Ñ’$TÕ®ÌeiBä~ÇðÝmk�LOSý5îÌsºäêdú§ÃÌÙnþ½3ŠA!i†.{qZ¶°8prÅBˆ ôϲ›Ý: $«–€·öß®~β»ZÃ`ß�C›z¡ÕÔqÞYÄ“^àÓCþã¡%£6ZçúñŒÞñ­º§²ÓÄÇ1LnI'Ö2,m(äiÿuÞÖX‰ÿÛ}'‘�%1[v., Ýǃx¢´Ò³ÓP�®8‰ªý0'â³c9q⦎£µMì£-æ8ÎJO7C•…¹v̾b›M¿éhÌõ,³~U¼R«}•xæ >ÛÈ”ÆSØ8k$Uþ'° FþeŸ€†ø’^ö9¿hûFé*Ô Yº¢—,÷¦úÆá,\F¾¿(µÅÙÆ^z‘XT÷àúÓE¡de�ùP§Ÿ¢ߌØ/(%ˆ¬‰@a#í\•èŠäËÛgÝ›è\£Z1ø#’ôw0í;)?‡ÑÃT!*2Öˆ­j”¨â 㯼Æ( ðņ�X·ä DŠöÞûE$|j×öÈœvL‘³¨ ¥@š÷oOŠÏ¶»dèÝ'÷$šcr1}Žª$Idÿå»ùA×8Î`›™3?#&µOß²Ð1õšu¸ìšÑ2Èàä�t¹UN èyÑ È(¡)n¢VC^(×L?:õ]QÀÐbžß%Ítƒé}‚É·û<´®�ØéQÆòJø\TKæÜ¶8§`oÏê@3ªÜÔ†_dÂxÕ!‹–f(¶éèjSñêÍÑš=‰+A?0f£4!u�å`õu oŸ€g:‡Sù×1‹wtrë–mÈÊ«â¦ÓÌQò׸Ódàj2·GÂò0@2n]Ak�ÙŒ¸³�¬E…›c"ï<„aÏx§Ö™*xA°+U»nípo6¤¾5±b4ýïtˆ …qÌF~Oä¿Õ³[�ßm Û£3Xï脬 ø›ìUÛסpjk%ú¾�y˜â|ÛM„Û�ø„WÔžÿaÅqå0KMì !»\ŽôêíO¥!S¾×4Ôñ¡š¯¥` ×%3÷#‰IL£uÞÚbq¼êð‡TèÂ?QóÝ ü«±sãõ•/S�D’0¦•Ì80fcž¼õ.åºx4¢ Œ³y—€��%+��˜™ ¯#TâúßU_8fɸ\Ô7Áöe&öôÀêe"•¹èÞDZXUó|�‡mr-!P„Ž Ž�Ù[ü™ ZÈý‹ÿÅ%j ºßD¼Jc™±½ µÀJ;Ô÷R=f./`Q’’À+wáu™ôÒNNlIUXpX:²Š#2–òX|ÏâV`ú~L™s�ÄöXQâOº�.Ž–xTó¨xs4§aU5SÔ�0ÑÞþ•Kô¡ž€[ÅZ×o»è„ñ=‚Üî$÷3´^ÄG^õ§�3d€v)ÌBËþƒ>x"¨ž¨¦í–ÌF¢7ÞšÂHzØRQî{uîÎ%–[ú‹¢_ó„ A0tL ^«ÑôXj8óŒZ(/C4ŠvjËü‹Ë ›wÝ^É\ïX­�_†©%Í^ ü‹KæÁMsè™Ã[pz›rØ”ÐM6A€¤Z·@C ÏÀ²l_»;t¶ªœ¥›òXiz¶³”|•V,Ù—ÿÂDEáb+L{íÎ*…‚i3@–D/›ÖÕå½ë&>ó>|0½sÞ RÅ”ÁgßCèBø8m'Á Z°M×1Ü•RÁ‘›ñZ?¤oœAmeþuînvô“.Äú)âVX¿#ŒÈ›pO�_U†Å:uGÙ6žwW¾Ûþn Õyô·Þ¤/€ñâ�Y©À9 îç„© í _ ܆Ã&ƒíõ>üb)0Opr:Ó(;þÉ|‹rØ)>Œô!'¯Ñ˜í­†ß.pkM@dWøj5V§uÚœrÃúGÆÃ–ä9àOXØÌ“•3)ÕŒ! ü4qù°VŠÂá¼¼?¤T*gòpnoÖ�Ÿ›ñù¥l~hFÞ˜oÜ:\Ú’LËÀ~†�ÛfæÀùËGDbxåÑé3Ì{‰Åµ§ñoÌ fwÓŠ,`=ÑöfõN¾'áz¬\°­K5„QXHŽ EHW ¥Þø» UVŒÁ?ÂS¶tƒœ¢ýFŠ…ÅÎR\‡‰Ä6uÌ™JìU+”8 X`AóÄÝzA�™•D›ˆõ è (F¤¦­Û³‰¨²æÈºK”3*ãº:{YhW/�·^¡D@,på^�-¨ÂâÝvÜVþ«ÛmƒÌ³ Éb7å`—"õžx§ ÁÑ×vIð@ |ó5¥_(êÜnåëlq°?ã6MñžèÒ¸ïØ«o•©eÏòáªy)’]¸xÃÅ ¿hÕ×5ôç#ÝRMUR7îTD …ªwP@ Ê»’!&8;RÖ¡Ù‘=@„S²÷¼qøò�UVôlÞ#JÉpY6Ë`5ÄL©§þ‹¨œ°ôÛ!gC¹èa¹›¹¾PA*mGhjÝ÷Ž-ŽbH$Ü..žb®‚äýfÏ´ÈÐ…qïLò±þͶ*`2>EÔÐt‘rbqO VnŒkeIPÍ2öxºLª=„óüm—oë„¶Úl§Õ3‰ÒBnÝižf¿©ªèÍt/yìŠLÀGãÄÐmè‘íR±Ÿ½5©’Õ! j>$öQ•Æ2i¡¾êL³àµ@6DEÍ�~ÛquÔùŒ$æ¤3sF†JœPL†×¶¥‡“’B]hx}�á*+-þŒKm°É°®\ÅHZÉ»IãZí¬fT‡5Ó�ãšõxÁ,aOú£,2�øÅ¿[/J÷A™é¼øž Xì ›U dݽšôIÁôµ'RGXlï¦}1J†|GmPD{t%e‘Òbe/Eµ†Îõ@,Qi0à<ï%³E‡'ut7®c îñ�ZœîÝ!Ûr/lW¯Âv$�å@(FíùüLò[Ò’ Na™–íF5‡R8ù{:›Ê}e˜r¤038Üý¥ßÊì ‹WPgÇŸ‡nÿ9QœßúÁO{'#Ø]\X8”'¬[}´›H`Tt�.Äádœb÷b£ ‰¨Th�GZY›]Dì÷5ö¨÷9âkÚ»!|Ÿ¾ûãÄìOD#Ú¯<>׃0%�Ô!]d*¥w)ËÍŽìŸP‰(V™d’ZùÚ_�S²Ò˜º½ôhÛ ^ š1Ï{¦›æ?ý<ñîè·ù ÎJw«­‹¹6\íÒFlºšxð]úVÕè”nÂÖ¦ƒâJCmƒ( [!PËò§AìX\w]œÄ¼ç5ÖXKZ„Œ,y‹*æÜ฽±[jŸŽÜü4KõMübYÓ¸ºÆù·§‰ü¾r|Ú(Çõë‘ï¥ Ô[Na Aæ2VÀ'ìá:“R+ú`œ!¢®›+ ò*wéæÍvKàµQ·Cúx¥4¶1OûÍ‹€Vb¯”†kÚ¼<Ò K“'Ë?²�¹•N³ëﺨM= WNR²g§Å�ÿøÝY¹2Tbúb%RlQÁaøš+;ú®Í ʵ2ž “êA` ?[ÕO®áãA6ÊõV¾²Î³º{„®c'‚»û©Š™´Fqq wp•WÖRætÕJU*5#ðgûUÒßw‰Î^®|sæ@qÕ¤ŸØUåÞÚ®ª†u9=üú˜®Ö†ìŒ΂¨*òõúüsFÙꙿ½›Ÿá勒ˆ?bß©"Á‚Q—sp{”#zPþ@.Ó°9*X=VhÕ1 Æ"ö÷…µ»²+sÃ|œàÎÅ¥>/¯Ôk é˜<4óF{¦J!«‚ü„ëïúdý´çÍzȰù3×/::^ß%“´¡`\O¬±•Q´kFfÄfyÚ è€¯%(ãEcŸ è—Ea5žaÆ÷¨ÓGß§"|çW@¼õ¸GÚ†iú�Ë¿K7 v…Ƽ‹|˜É¨ï×~Ø~4Qç$jL3–]’çÁòß|.‘£¤Ä¿�ƒ%:`õñ¿È-¿F¨º… R^6‡êéw%wܱæÇ9~:Ëè 4:iurT÷|aÐ#ÀÄ�Ü;ö¶SˆlçÙ÷b’7å„Ú“%sÉòÌýë� µýs>©ät3•�«Y^½ól�ó,Th=]#‹Ì¸Ogz\ÑØµ¿OŽÖ)²%þSwü¿!½‹ [£+ÅR�»Â–5j4¨ ßö# H‰gm ÅýIxU?$Y™¬!ÆDK¼ÇX¦ã”c˜cð8t`Ø—Ô^£‰™H׃³—™Åq&üHLJÙ¿ƒBŸö°bî §y[FÅOœW@1jÓ¿ÜIuR¸Bê ¬èÛÆø^”¼ÀgÞþ)*©Ó òð:xy©ôX覞S¡P$ˆ'2|�`+àzÍéYÂK‹§·ð.y¾q7€ágFˆó1·±9ç_§çSøÇþZMÞ–Qj–Ø/ŠM È¯.¬‹¤žÔþåš_ëzòØUTa·ö„~@p€yù ,·òzþ©‹�^&"õ½†H×ÿøô ˜¢%ùGm]‡FËE™^hÁ¡zèW’ð¬b—KÚ¯‰®âÔ#£Rp/æ—2Ë !©‹s –!Y O$ëïLiØOßùá¦GÛÏ¡µ}ëò�²?7ìÐS3åG„@b8²[*n;à=¡EžÙ…ãšh`úÍÖØ(a¥ƒÜNÕFNb°†¿l¬ ËèÉŽâë_Ñ¢_Ï·Sê¥l¡êÁÉŠj´X%+­eTŸ¤r‘[ ‘ÑT3T/üœ™ÒÆKäMäç‘!*´$¹Ós!owæÏ¯b–×ÎmÅ׳ bÔýÕ#,PvÈ/¤1矘þ‚Ý-^ôŠŠÿ¼QùÉ0*´2:âá„ íÿøÊ   '#Ö…9ÉK(B|Úݼ¬Ûc}´ «¸÷Ú¥ÓµœØÿŽ+TÝ J£™"î’]îiC'ry™œê§<ª 7ñôSšÍ@—�í¿’ 5Ä’�Å#Yd�}0ÙQ‡ë‹Õ§ÅëÕþ—ÅÛö5¡'ÒÅF�q¨XÁóìç� ÂüœÀB$¾hjÝB„Þ2ØÙl3Pô²‘Tb‰˜xÒD !´e§æ12á�êrP1+HùÁj�Ö¾J[XÌ™Jme²üV3çÛLwu<téô‡ðH4R>v×”à]ö(¶<£c"xeÖAyÿ2¨œ;»<Ìh�-rÖ3Ÿ4\sjP"ù–[}y›µ3D�¹‰÷¡½yW„+ƒ jZ¿RõájI…Í:`>›G8�t-A“� ÷ÅüKTiórß À¼™svÐðüNÕIrxKÀÕÉ‹ê ‰l¡"÷7ïýZŠÞ½YÙÌ>íÉ»„ T˜_ݬµ‰¶>ì˜/ü¦õJ®§áëæVmüe¢ æ]:ÇÖ`ÎÕÆíuWQðs‚.)å®OÓlÎR : &“ö)”àŽàÄ®'jSóßþzòh ©ÙFšéEÀ¼+EeO'ƃÊ$êàÑ›O;ÄS’:mlÒ¬Ì\^ÝÿfRí§CºC��I«×!á›ZwÌ:+Ã<<ø4*Û{·€8g;nX×$¹Ûiôm¸°dáÙ¯‚@èYæ—qÀá_8šÖαF#ÙQ™&é14BBÝ›ê;-”õïñÓ7R÷gàÃOßæ¯Ø{™ä.7mGðdyæâ�/}”‚{]ñˆd(äáx@b R4ð™· _å4#Ї½*lEÛM¬�‚×\™â’�(oÐ"ÑÅØ¡FGJ8þ% ™ñ¸ô hâ¯É+pˆÌmÛTk6ùæV20Þ-°<Ú§Qu“õÒ*¨½?8Ìfy6×܈Î?q¥cž”i¤_f�N·¨‘ãMé”¶Ä©Èh߇3f}Ý=£‡À;ÙøÂþ_ëjPš‡Ëv æÝôðÖ7UCŸÔ!pȸK‡Öm ¹ˆËö5ñË$Dñ˜á•!LS&ð¼i~~NÖ‚{CyCUu&¦×q•;A.0‰R#¡Z#;±ª}:{ôÐ5¤›§N¹!œ¯Õ*$O¹‹R HKû"= Rkù-s€o1¶2>1W<á☛£ITšØf?øÈö#éÅX­yÈ]]fÄ-ÊtNQI…Ž„:Ã`l ª‘kgq•®±ð`[8Ú䂺…å‚¿½¢DH¶�<)â íª <•nMc[Äéü��ù¨�ò¡šÌå|J𡥕)ìf…=¤ƒ¢ècÖ@J£3ÆÞÏì¾ý¬Î |UnN¼(ÏŽYqiL§°+#žŒáJfržšE‹C ¸¿Â *^f½éÿƒiÎ`òú«ÔC-å?0Á‰ŠE¤šlKy +ãÿ)“s®�=2±T•rÉþ™CÄRú£ š$L>žÍ¸¿¶Ë¾†“�Ũ 6‹ô .!’?f•Ñ“ÚÝt¤ØÀŽœtŒNœ?ŒœŒVÕZ|¢Ã| �È—%3D;Ça_Fl¶øPEnq¯‹Ž+韪ÕÌøïŠæ,WKÔ­Ê„|d�TD M$¢¨OUIegûY-Ÿ|DÄ"ÑTšŒ? I`…6<ÏÐl¯Á´4仿µÂ!1 iå<ÀŽPyƒ+ë¸Y`LÆ  �5Ô³8�õÚD •µ¡é‰ü³›â„ˆåܦŸW`zÝcÜå´@”RâØ¸{ÊpáqtÙÎÍ'=á°‰8ìä¡ß |0F¬€Zånå7X}Ä×½¿rÄ 7‰l_ia”¦ð²jz§O®uuŽ-sVà~ýë!za¼é>�çë†ù=fùÃÖÃÌlo«?öbi =pŠ�2R›gx¢Ž„¢²pkj«òöÔ m´¨¥¼,˜Å”ÖstÅ<¬¹ÆVh~“µ?f�Yb•™�¼8L.÷“1;‹Ý›è¢ ö³+‚äè"“*‰”¥!W^§®Ýˆêå56^PmÊ1ÒâJVÅ8m\CŒƒÓÕŒ$Ü\Ý †NÆy!Ò~+ gœTo› ÄPRb¿03 ›v÷ø_Ç«ic¡)žvëœcØÂÆÚŸ¼M×arÊ~Z,>}Lº]-}Tû.0úr¬i<¸µ�•4P[Ê{dk3‡tjdVi8Ü€¼Ï!_‘,@v':Š‚ÛȨO3tö‚ÐQµØòˆ—$o˜dõÝõD—È‹�ôÄ"u¶„��…&¹mÖø°@îJÅÜe¾Ã{À¾éïÙßEÅ�$˜rY<– 3÷Ëg@�÷ìÁÖY*˜³¾ôôSÁÛ 6Ö—ï‚㌋>Ë´ÖyQ{àxÉ_IžÙ˜í`f",Î_ èzUŠïY+;ÔßC‹ÃUåñÎ8Ì7û¨¿�ùLG/EE}È&gÇ{ƒ]è�ºAó̧`{$¢(¦:§I­LkA<¹,b•®ï#,¢©•ˆвyµdúÌJ=§È€";âëcù_¦y;œ[dœ:#ŲNKÇÙݺp‡°æ…ûG÷Ãu1�ô†´Ë Îþζ½Œâm+!-Ø©7É�`¬}Ì€?©õ�£ƒQw)=´&º‡Û*|è"餡ñ›Æ[þhÓ†;GƒI W†ÜâiåÎZå�aîjÛ&’ú–h£¯ød³Fâoô6çJ¼‰Ä.Þ]ÃävüÏ_‚vâˆßÌØ@…!Ô §‹=G w­ÍüšüN$₱�â |Ÿ1¤ÂÃOr€r Ü{€ø56¡„�6toHxi$°~¹þòÙüʼ–xhŠOiÖÌ)m¿ÂŸèv½žCaƒ\õd„ã¿Tåžz8»N¹ *¿?ÏÖÄo^Vð©LLaït’Á� {U•ö`Ñ�¾|ŽZ=Šá‚ ª.(.ÌZÝÈ+u8d5úACœÉK@©‚9 Šr!û­íkG!@/�ÉT‘KW•”Í Ù6žók¸ßJ^¢ˆe™Œì i6¬<k²&JÁú##Ž@ec )Ú¨æ@¥Ç34Ì�ç¿Ïq<×=Ù›1˜ Ñž‘ 1‘- #ZظS£TâkãÓ"ɸTQ‹¡u=Ö‡ý¤^–ŽS‚i ² TÊ[ c5…àÔ8¶ÛVRY+.d…1Ïsa˜6%”íê“*ÀèöcÌwœÉ ·š�èD_Ô¥÷Ÿ !½VÔ ÅK5cu†N¸¢œÞ3­®ÆO¢ß–„l:Á š()±½Ÿ@‰ùæ?϶ »HdZÍ|SU_}Ø‹9Ia–ŠóþN àqCšöùÙØí—„‰E¿ŽvÇ(™ñóKÒ~:Ò¬‚Q”µ[˜[�xàØ9ï¥IÞª1¹´Æ‹�ÌÇ1|$µ8?ýj1/zäêpe»dß½ÃÍêîìd ý; {̪¬d4лáS›À&`›Ð“=Ƕ)šn4 !”Bm¸E,9ïü=ÙOö+zcêP ö\Ì©IØU¬‘ŽÂº-ò2ò�–¿0¿”�v²3 {#ÒÑG>.Ða¼Ô/e�듌³9Q]ó2cÔUY�Ú‡8¡hÃ:Ÿœ ˜y_…Èù�¸—ªÈz‘tˆz‡Ãã|âci9:†"Ía}¸“ႬÀekL�¦ËÆÂÃûÒhwðÕè&cO µ-‰‹o…U†(f‰g¿÷­Œ‘/Æ�G@f,�#H¢Á 8SžÑ”¨ŠÝc(Kݲ¨¨Nôª�j6003ÞfW¿æŽ©j»¢?(}í¥—6nú!ó/Ë…Ä5žõÆ}ÿ§6tÀéÖ ŒÅs°†ÞŽ‡Î³óâ€ahgÚ‹T�éûn|#% ºZŽ òm¤Æå!¤«O=ó¼rÒÖ]d) ˜^¨ õlJÉ•}ú"Ph”N—éÒíû7ÀPˆ�P–À|¡Š¬gGb„tqZ¿|o¦DO¹”³—÷G߆pM Qòät{.˹4HvÚ¾¯·‚½ï¦óÉFàÞ"Ú‰nšZ.çĺ�³×ÍØS�> (gÿÏ#SíP1·»ås[Z?øñeå|+‘¨Po³Òâ½®¬÷ZÐ[{;.\¹|í’œ˜ì¢r"¨@»#{ëËbl+ŒÒEâ½ìu!ùæ÷è6Üd;¦PzñÓ»?®FÈÌ[•ž¦g#ÇÑÃ÷ÉWJkÑ‹iª!¯Ð‰’ ·Ž÷óøqv•ÎVkñ;œ(åÃ’—GëõØäí—ê£O¯–ïkÆZ&=Ñ6(Éê|ûsèC{SöYÄ¢ë*;ÃY׸OI­YÇ6ºLHnj%Îñžwΰé?è6J}àëæ$0QIÀ­­{9¬,Æ«!.6L�ê}Ø$*d⯣¸Mö¬WtÚ‡�›öá$ Rm3‰wB3ŒÑPf(¡gg{Æg=VÏê€oûÿßoî;õá8æVJ†í(sb´6¡¶n| «Eºôô�ÈÆå¸|¾R­­{%°™ZO_6†Ò=ºÇ3òíàvY€)šDÁGõŸ�®´6v‰�”HÂwà²ÆÛŸÝñí�´ÈB~%TZƒçÆ‘2/+ÚÑWÕKá8¶”K7Š·ëõ�'Õt¾gn]{âÜzZsÃómÇ6=ä¾ñuѸY©Â[^¨–Ö¹ÌC‰Ó_ªs4Ü9n ã[.å´Ðt¼‘ß±Ÿï?¹‰É·üKŒÑŽ'eÆÐ>¹¶³gm 2Þq€él<7”ñ„∱^þ)¥ÖÏ]Û™ OY÷D‹+^¹…òˆñžrÌÖ¢ë~`ìL V®B�¬í‰!ƒGvÕåë/45À zîóóþNέ1-þOí$jú/Ym÷ {éW¨ftñ”Þ%ÕÓíµC¯mW}Û`áˆ7Pšâ§uèÒ ”_÷× ß~ÆNAqo�¡Ýrzêzëõ)ã¿ò/�uaž)ä)¡%2æ ¨¹ôÓuIÑ:ò`(¯oK.a‡Zƒsˆ”MOFtet @ôàž]țпC\Êö øŒ€¹jø ºùÒ¿¿Pý¬&B ( ~ó]Àfÿ÷¸Óh3f¨%™‚ Ôõgë0dK�Eø&˜½ØÙamV-Ž�´@+³pö?Jˆ]vtúEcA©ƒð:Aõ€áð…ƒ_‘lf3·™ñ½Ã%åN.ÆÕ¼Ù‹×€œÚös™³vmp}áì{åðõË`3%ÂÜ«61ÊŠ,$‚‘PA+‹»äij³•Äoêf€~›e{É##ßç”&,³„ÐtNÀ¤wå`rj0ö5ÕD”©�²ÿ…–AzË‚F�ÞrÏ»&Ž˜#|Ú�tw™½¼ìº*|k }9^¡³T¾Û“¢ÀϪU|‚òºóÆ+µ}ÙñÄ‹mÕLDÙ=O¼7§KSÛiŠÙ}Ž-à$fˆU´<Ò]S-šxÜÌÙdi¯÷ð?ÍXßÙ¡¬ ×èçŠí!õ˜Z,® $iŽº´ki€ñ­"Ö·•Ô<òÞÞ¦q æ©[‰¡zçù}ؠ˦X“@\~ªë»-"Çöº­+Öµ1±€Å¡9U Ec_³|º-Xz�ÒP«›€ãš†¨Zö—¶†çOë¾Ä/€•!fä’i¢&ó"i݇Ì�(ì|,Ñᢂ!f.*°a/xÃÆR÷jïþá'»P¦õÌJ‡x%E=Œ”x„Ÿ«xSöÖÄ—X ûT;À™b?éfæOC~Åu�ü¤à¼s_µô+ ¸û÷šªu¡tÔhðÞ‡¤¯ÆâÑçâó±6G%WrÄþ%PÝÝðéÊT+­#è�ÇÏRÿ¶ý†¾UÏÛÒLd©Ð¼ó™]Œñ¶ò ‚È…½ÙÉI£ªê2l?îÀ�1d�ú˜á¨F€?!„S¿)Ö}D~>‚*eˆ4Åâù¿Ï†7•§� €Eïåì¯OªÑÃÁ¬q½ø�uèTî&ͬbñèUÕAØ×åœzÚd¯ƒ(‘�!ÿ£ic4NVI¼€ÙÞBÂqG_iÚ®¹û7'”tt|˱‚üÕDéA‚§þÞËÊãcÐ[ †Où”?&·ßD^bÝÎý¯î’n¹$6o!xû†¿v†Dñ'«îüÈNo À/p—±?¼ò©¦W»tÃÚ×\UOž©™ÐKçžßR2�^H¾ž7g`Šÿî‹á«pê'$Sv§œPÒðÛ™žhÐzWT„dÅO8}Öa3戫[Ùªº{g-�KnÛ·^9ˆ9ŠÛè*ñ°™;G[•yM­’©¹‘CèJ–§Y$wìG\žà"ÝMEc?rÉùæ‚<¸ãä¢vºôÅ2ù¬l½NÏ}áˆÁs&¥ ±ô9ZEÀά�Îkpy1fnß•iEw¿/!w÷Ö`(X%‘ì%ÓêåžÑà 8”uþ²1í‰Ó%,t—IÈÂùisÓ '½¿�[¨t³½€ öãܸtçÛ‘üÖ [üì͵ïžÏìƒÂ¶FSŽ—WæQfÀ“™ŽÍåFÁîþhi#7þ¹ºóÉÙ8Ãg Cº éF�®‡D)ñùßh5UÎè¬6¾eÃädëÔºdz¨ašÜ?µkhZJŒû¹è·’¤ñ>WÏÅÄy-ä¡êÍ ØÌhÉ>ºñpâ.,f¼Õ‹®.*篯Q´J�P‘1Ö\‰7“æ�+;Ãø4.ÎèÁH’+²Àw†ôú§G�•bñõ�}ĽW,ã "ž-q‡ìAõŒ ŒO7ü=&ìàa›¢—€O7¯Ýtv|ª_Êæñ’Å5vS>ŸÐhé~éÝç8¦6R´˜syÇ� "Äz2¾$¢OÕ*Oê¹öM«\ª!ïÙ¹ÿ¤‡hÅìC¼Æ×GS¯ïb•œ[!Ç¿�|bñ§êПÚПáúl˜„z o¾HÃ^ü¡S|ÆíˆHV”â‹“° z_ê;ð©¾>âþnTHøïwf|HÂMÚO šaW@:ãxš )Ýy/UÛiTH3z £Õ2cx¬*âੌ›ô h}Uûqu£àªèmIÓÖ¯�Ò—8®CJ¨¹[ŠÓÊÆ�7ŸQ„Úžzª‚!ž¢ó÷Õ3:D´Â�çzÿåÈèŸ ±¤ì-[<ßeÞÞ(vYÐ]>æÍL! -ûK-Os( ½˜4…ÙA7�c^K52~r!bP„> çWzÔ}b�‹€Îúo9àä_«¥¡r)'Âá)ߦòµÿÁ<ÿ„tXBæiÀغad@¨±j‡DD­w[€…¹ ,ýiª€ É>ñi2FÁ a(ƒ’ 8K!O.,’àóTUuAËIÖ@�bŽH­qE´f8#EOR`jH�5Ÿc»¤Ø“QÚï�Ímö‡aõf¹¦«Ë㵎óWZ6`;ÓgFV�è GÉïo¹Tœ�÷6ó›¡ ;¯fMdE’T¯¬f=n¸Ó¬°Œ¹KÆA[ì?°B*#:£@¨§�uJC+÷ÇVªªÓ�é–ÝßVsâä5È€doêÑx=¾Ž7.`ë!Ð<¼ÌÇŬíBÜ—?Ö°01¿,ÒÉ\ $éèZírfÙB†Ð©ƒ óÌBN»û¹9 úߦh 7iB­Äÿ»¼í-.Õõð¬tšŠG¶NŽjR~¹ ¾OpŠèþ$Ë–šn@9 æýk ÅÄO4É”ªàU—~Á6¢Ö¼l¤oƒ·UD�¬%n”«Sœ�¹^竜 «jZùT•ä|µž‚Á›ÂuL„�‹äý?£¹Ôí…§m`«®�°D’;‡~â ݘñíÊNŠ,Jú¸ó–ñIœ+hÞ°|XÚNeÜkpÒ b&ÁUsJ,ï?ï•�¿$|�ؾpÅ œ1Iè¬%Cþ0¦ϾHÈl R¶—Ú:Œà4óÀÕ¡)DŽØ4Ï&,ß oâa§×>~í-”þž™”©¿*Ño‰IÁ<Äb%÷yõC½ü/ìÒ£Õ!YßXaïÑ6™ž¡„:¼\QÓe„ïZL–<,¸�_UÙ¹fRÈ $Ë0yqjá]Ú§z.iˆ�$e5“›F]ŒŒ°ÈòáYáR÷Ëbƒ‹t¨1 ›O~tv¤ðˆª*ãý"÷--1îd†’ÐàD…ìáªÄòÒ~o�ËÑU1–F¸/5¼ˆj}Fi&qþ©wI‘Æ…®Š¶LE³oÜùk”¶î&o?øÍÄñ•ݰ³vè:P 0Ðf3„ ôì ’|µF²˜ª¡7ÑS·Ž�4ò¾ÑÂÕ:ÁC|æµ?½,^Q"Â*£�%ÔK &ÛšV–Qºƒ�}@6Ú²Ük•¬…Á´•ÙÀuje> Vn¨�L³(zŒ“Õl–ñ‡MìyB1d£Œó؈0I›-GUQ²¦ÑôÓ½ÊLÓ@8€5ÔÛé§¿u¥åsNoÁB2µ„‹Qó§ÖW§[ÒZƒ”º jR+W;“ÂV—\ø#[ç@ ˆ(7y-²öàÙ«hê¸q®8I˜�5™´çšOóšÒ³z[îÇÃñMź0ö/lÐ ú_¡Éœâ Yàþ §v5ImçÃwxØdM$¨‰‚;5Qk+/�c¡,‹�¾á«Œj8ÓÒÁÂØÐÃyŒ X•nmiÇyð+²ô´\)<5lüøLdÿMÎ;[;U“¶î×3†Ê„üNØ…Þ=ˆÕDÆN˜ùj.~©pc t,Œ<Ȳ`?IvHpTâ>ÃIÖrLìOþðqõÂ_ty®œDÛ³Ò*d‰/î‚)ÂT�&…tïííWT@‹á£Š^?:çžÄAÑ×TÙ*Ä߆^˜d‡N7‹¶â?´€¶º²Ï&‰XÆè¿¢BsEO6V_ëzßÖ¤Kº)= ãÌKL2P Œ«{$�öpä„¡.9h®¡Ùô"èZ£MwrÇþ—7¹‰:ê:º¶¯ j_Å_*Õ¶fx*hÊ:×?`€ŠçÖ�¯¥yMëkõÆÑAA( ¸@ÌH³á”ôÜ“T´µ5îôäÁPÃûõלÔ4c�7¾LkJÜ´ìÕÓ�>ìåÃÛ°q¶ &q¶Õ¬Zëì‡ç`‚"ÓXÇH„ ë‚FKÀÙ Æ”îÞÐs "¡¯é ^½>ªmëï.³kŠ/f.¬�Ô8bâŸ1qþ1NoŽ5 *ù:�Ðy@hp¶Hr“÷!ÜÆàxoÁ<É̵³1eº¨+wê aË'Á;Üʼn�%a2­F€¬3-Žë¯ì^ò>³ÊÙ[> äÿ³/8ÉãöŽ_ÅÈØÔŒvùãQfD×e‹�IÞKE ªvF¹~……àr΀Sc•‰e`_°h“Æca™; Ž#YðS”á%Qm¤!� Š.k LcúZ$¯š�Xï2<3æÊ’þ½‘'žlÅÊ®–·µ ¼•¤gÞ çqÄ4 »zJ¨m¯‘t¯,X¾qtˆK™+Ôä�®ì$ÙÅSë•%å;zë3+k‘³ Í€Å(úÁù^ªÉ—ø%Øõ걄.' PzÌP²!I?INwã¼ÕÉL(¦[0­ðF§ä ÁÆL‡ï‡¶.ÆxßÃ’du ã‡Õ^k,1Þ—4¸æ·gé©(ƒ¶®_0~Ø\ù5y‚-¯KðÖÿƒ²Q3¡]†±ŒB—UE™ È“%jéàRˆ¹1©WõĉÀNåÉ›9ÝÞçÑøßˆþð�“bþçe~ ”má~±Ž5¸Sϯ|ET@�Št÷É`ǯÖÓë)p•?Êï³Iíè› C4/ý·öûÆâRÁ—£c©)»°PW°«ýÿ÷¼^û›yÎPy‚8Ör¯÷”C¯H�)5ø‘5�eï㼋?R‚�Îr¢×¿!wœÐüd_÷Î¥I¡Cà /hÉT·³Ñx�Xü˜ «±>«êT’Üvþ_‘e&³CîÝ|9Ðì.hÑ×nxfUx€€û4pÛ@ìB:æ;µc°Ž€Ëe› ñ*Ô´¿¡ÛÑ\ÃßUÙﺴSÕªNÚL¤±f9·—d’�{„›ŠM¯áƒÐÆe¸Î-%+€ô>Û&6éúMS55ÔªDxö[|F&DPß·ö |ÄgúÚ?%3ëSYM/*ÅYÄŠ$³ï7ÐÆ @{ýüåHÞ»¦�¦2æUSì<-êò{ö�²í‘kÅQï-Yê5¾Ú[v5.þŠˆèL#éöw0哸iˆ&ïŽ�9?±G0?¨"Ç8{ãÝ…!¡etÞ®ž¦„¥iL‚JêÁsA“֌ߩ&´ó©˜ÃÃÞÔ›¤"Ì JzúݸcLIHV?7.>…�� Ï—®/€Û[÷îó�,‚§Äy¿�u]쵤ȑr–Ö²ãK•âñ!ôÌóylÚý²#™XÒî¬dE›DbÇŠ'êú'Š!z}¹Š¢^l—r%Æ R€8 ËÙ¢‹úBC2$8¬æšú¿7Û–ì«ÚÅ/|˜ ük•+ôr˜'0›¿]ƒÊjÚ³�QìÓf¤áãá�Êó©`€žPŸñ%Pÿˆ¯½‹„Kkr6�a¢ÊÔ|¤«¬e‚ѪíèÜT¸l2›9 î1zìmy¥�g/+|F5´6QýÖp”ÍXþ SÀ•í`÷¾8œIäë÷þpêöÅ'Ë&zÖ� ¦+T�°G¬�Æ5õØ~S×e0d>ª÷ùèJqÜßu€ë0I:¬&™h€hWÎîn~�N¡¾%æÓÁˆXê“’ц7‘V[�6õ~?ÔþªüíÅݯŸS¸#>¤6 Eë–sÀ šäÈ|ÏNô œ˜P©K蹤]*,· !îO¼9ý‹çÞW§aeECÇEâ<º–Xg¥7Å {]è•éã5òC ï\(8•\þÁODÀpÙ’î�Lpk¤ÞgÄÂ@Ó±‘é°A¤�, §8ÿÑ)‰�‹ »¢{™�ÀÒíyµ~«£Q›.ˆž‚T6¡ìC%íu‹DhY¿ñLvypZ 6ͼXFÆy?øUò<ú"þ¥ã•Ö�x²ÕlFZ¢æ ôÆOhÀÜü”&„ÿ­rn·Õü_ü;lH¿“«Ò/ßšÊ�ey¿`dï¾÷X…Qljeø©‘8FÜV+}#½BðöøS×@5cxêsÔŠÞ�y{Nmo'î [aÊ; /ªß8C27nìN÷{åðj´ï%SF,þgõô…fÎÐÑêF´ÄÑ7¨CŸ¸p´B­Ï;{x*FÇ^n¾9H³mû¬ ºX·Ÿmé:o;f™Pm¯“WD—ÅR¸0îDUrÞÖâÈa£/ndkíU“ÁàÞ7 ‹0è> ΔÃ7SQL‹;T"ðB+Á– ž¨Å n2«hFq0»òÝeM\%««®«5¶‘ç”:.q·Š‰PÐÔ_·‡{ë^±ojËca,ì'öþŠu>ô�•šk+îf†Á3y(ÓÂÙÏ2/CëÕ�^ Û“í¬9Ýñ)Ç�}ÞV¨ËÂá2Ä„ð£,®G†õyÿÉé1…Ë×O”š¸ˆVBŽÀNZ­Moè}äsõ²…È|xÀR+ß``M{4g_–ûb¤TM¢uÖîßÉÔ࡯>*œ¯dÉ~§:äjwÕÖ#Ö>·ötãx§¿ì›2ôÜð?Ý’aªÍäÊWó@œºŒ¿¨ÎE¡D¨ÔÕZ,å §dWzCO/Õ™x""ðÁÊ%!‰!]�ö„)ˆC룲¨rCjɦHøT'`ü|Ý%Xâ`­¡Å÷m ùåÆÝ¾ÖJ}âÛ{'2 }½½ŸË/æÄ…?2åšÛ6¨´Ýå„KyÕd¹Lÿpäv†çÝÀ«Û1¦dìÛ5Vöœ“C`CÚ‚Pœ$ç)šVDàÑ»e¸Aâ:ùŒ�ŽUfWi!ÒX™}UBb'ˆóŠ�}µª†Û†š=­‡Æ×²R7RŸ‡´ž@m”YP š3k©J?ÈóŽè%»êíNtá…j:ùžjDg!7$(ƒ7©¶›·!V:j+µ¸D#Pu[¼„úo^‚oP˜yåÜ Å(¶,AÖ¤/…ˆ~y~ô¦ªª;þ�ŒñvM¾ÔÝÿd¸…éû¶%g¸}1I_˜ßb›ñâç=Ï)—ýÉ+ÓwÍÁ¼¨«Î8lA/9„ÙWjZâ÷;öÖ’¾çµlÏìQÎwÚmƒ‘ „ê<*¿÷4W+2D¤¾è´ÏÖrUµs$5ôøÆ»¡½ò*mòÔEï…;%²�;&a°XQPìt }V¼„‹´"±ŒfMµÊõz ƒ ®×�¶’õœ»È|·œhüèe�…bI¨‰ƒC°ûŒÁûhÙ&MʸVÍm7Õ¬ .®öaANÛ<ÁqÆGõ«Îˆã@}¨'Æëë#FÏ|¨”HÞí‹·€9(ôÒ[Cu>"Ù‚ÔÐkl„›Â…7‡à©¿mÍŒùˆf;ܪÈÍ<'[šlµ7 Ÿ¥z.Â^H§ŒZEq± ÇÊ)êÞJûBïyŽƒ³kÕíEdVþÛn£g%ñ-”5Ê@f >»)C"sûJ‚2õJkÁê‚29a�…þÑ…ªÑÔ&1ôô}ÆG{ÉK|±f–ÌåŒÉ>�¾¥ä>’ÚH‚`IݳÜ?I·¢p�L ñÿ¸\’�wÍÎ…ü釂Uù Ñ#ш"ü©üôѶ/ ;À]ý_yŠ­žùOWÌЧë�˜&`›_³´z[õæã˜¦ŠË¹>w2Òn¹VMhŸüСÈË1h^#!M;e¯Ê{Ë 3“™ËÈ:pš,œ&¿.Z¶� eˆ¿(5\î4zUÎÈ„éK*޿ŬéÞÁ^º±zQO ÓY¤v*´3ëýÃþ mW÷_o²V;̧@§‘´Vº ¨d(•c¤wǺõ�ÏEåøº–Þ¦‡ 0Ñ‚ìKlÚA^ˆì�T.äuô¹ÙÝ÷Úˉ².´TR÷{ì+´AÄ�JN„ˆZõpJ–¡õWy0²·  4¥»ç»‹÷ŸNÉW¹øËõu9Ÿ³(ð ͧ%2ž .i¹GlV³]òdç7,EeÎê¶¥É5µNÙ[›ïü† WŒg·'^?@Ž�ŽNÙmx’0d³%§™¬c[N�Îÿ~Ý.³“/_Û²ÊW†A”:ÙOÄ�Ù¼ £«)zJš�ÿ*eöÔi¾:úG޾4&K‚Åe¨{i€“¼úuî3•šHeÅÝáhùš!�ø÷Ö ™ìkô Ö'cqÕ¬BÑžU§«Î-€‰ \îÈ¥´ -îíH¥Uá[O)ÙÒ,Ý{± /ˆm“©4‚¢Ç™'$,X_Þ˜«-Š&gŠoó2mdDg’RØ&Åàïv²Ë�Wâ®ÿKÔâ+æù¾s¦ o"ôÝÈšÊEÀ®š„ø<}MÌ­å=ȃÔÝðÿ3pc?ØâéITÓ\ÊÑØ=¿O`ÉíÄï6˜ÿ�2?¿Ó3Mà9_¥˜Hò¥Ì›ÞŒrÕYÌúáÙ>FZ¦£Í�ŒãÙ8[é˜Ô«i›…PÀÀÕkv³Z†“G¯)|Õ«v?Nû¢cî'‰lýL†¾’Áµ}†ŠÙ„Wyb|Á:Ô2ùBõ·jP9-—fØ>]k‹y ]=«¶—åEòŒùÿb½¾‰›ž��b4l0Àá™?'öÔkÝí¾ÇÒ„u†Þ™ù.iG€v¡½_Ò/Ü^\ùn“¤´ q¿á�â “ê‹:Pc韷•NˆO݇Ä7êP åiY¥M2])ãAïZyÎzËÏîù„ªè:Réö C1ÊŸ S$ví0ë06_�+7Ëöa<âݮ緲ö×>…\ V›ƒ�tÀ�ãØEP�ä 45pq8�SF„ÆX˜G=HŒ ø¥õˆiK ð¤£ì™bðu¶n3®S€Øþ°ë}㎲Z@ég” tXÕWöà)ÜÌ®‚ê¯x˜ß ¤øÉ_çÕH*'SÁ÷1dC¸ëXx"êGzyGTžÖR¦d‡BPPNÓ¹gÂrÑ(¯E×}ø™RO�Ѝ^‚l›ö8­s_E”pÚ}:߉[7#†Jeç4I`‡�ˆ²™ÊÌшqÔ8IEêe10·ÖÉÅÖÈXÑ’Ka³áId´\àí£>ùF¦ˆ~d>üýúµwëšJì›:ÌÀ^ySy;›¤þ5_ DéÀªOòL)åqC<@ºàÙ¯YÎà›f ¸FÍ¡�ûH�Äöçj'é>¶ïÌ÷ðdg¸À88ÝM™Zä ÎÚo ëUl¦£(ANóÛ0£}˜YÒ ¡­Ò/{´…8E �ð÷yî�¼öàÏ|Pxi”m–+-ê>'»L‰Ü„!1ð`L@]òŒÃµƒ/hóÊw8nܵ€¬Eó2�¼Œ*±æãjâÊwÿžÀD2»<1nÄÊͶVN¯)RýHÞ§#/Añ�ÌE›r}¼…±r̯À]½ Oàþº}€*2ÏágP§v¡µ×þSë÷p°â–ýiÑ¢DnG®ito˜0¸ÂO¡äV™K(B™'Û»ÖÉ#éÚdo6åFC�¦üö~^Í<æ]LVñ‰Q­¹°¸x\@Hœ° Fì“ugÿ‹fFØ;OH@OùÁª~¸Q žFÖTz~A$øS+~»B[¤#lDÌó ¢eÕÔ CjäÌÏ´¨þŽ…27×YåY ËÁOÿÁ¤Á�Ð.Ñ@²üσˆeuõãgÚ£žŸ'zë>HW:U�F…C>Ófb[U¦<«}Õ{\8‰d©§Ü0xl2VUŽ� ŒGÏ ßwŒ†?ötTGô²ÎNB\ôj¿�‰èæü©Ú²^•nOE,Ä^E¦ê}C “ÓÎ9…Ná2ŠP¹ ^q~ŸÜƒðD ¨þ”£ÂåŽËkû4à1|ª´1�,HסK_¥üáf) Á ¯2k¨òŸÈŸ ø9‚pÞb)î¨ÜÉ®¿æ'‚ßI,2o†"ôFX³8r޽y™l!Ýí*Ï~²©\ TFnsõi˜�ÜM=Zw(Ý%Äü>ó)OïC1ºC•¦ìM8¥éçðÕÜlÚŠk¦Yz {èmЮöÔ½O²x ¯´ØŠ-ÀNeÌ®8“úzÒj›ÁœT\ºÁø7‚*÷ÛѦR´±wÂëSÿv.ÆJVH'ÜFeJrÀ¸Û'öW½ÕZIñÆh¿K¿¾ÁüÄš$*¬Ä›ž�¥IάХ³óþÜÉÏ© n¸Õ­•A–ƒ±Û%H,<ê–ƒyU{œ† �9‡•Â뛣‘ë7½ÌÏ<ƾáíùÕ¾ š~MìTQìEB¿²v !~áͱÒv§ëîLáœyÏ.A|ÆjÉ£•Ö®˜Жrh8yê1—±lš¡bò²øvÿ†ÿòf�„»7WŽÌˆ˜þê S´KÁ\’%Xœg‹orÍз´¬1™ZÙ›!EÌ�´Z·ßóÇJMpÄ3"”Ôó‘5÷¬tˆƒØ†EŸ×?\\ùH«Î¢k¤™Nü_Ÿ¢Üf*�cwê"îMf“s—4sûNìwîH†ËsÜêÐæJf+….kÎoµ°‹TÆÆ, @uÝÆ›Ç×ðÝi¸”2«—Ú;ª‚í7âŠÒfí öPª-Rã·TQXˆý™ëñ™n-Náà1d¦Öà8Æ—-»^éï��rv)”#Z å½`Z;ÞwÚ‘~s-˜2#§(…�çûø£ÑµÃñ“!x®ÎEÖçü kh‹«êP[„®êÙØ†¾kû`R´,—E#Ù[r×™$¨ÞÈÃ[7Í�¸Ø�$¼×•,bðŠÄ#Öv+eüÅ_ #·Öë!S)ª2Îc°œßz*çcÆóÒäá £¥Û¹5 \ß�Õx0…2ñË8ºAÁmEž$S&G§ð¶s\ú�D¨odvADâ×g¬Ö–q‹®Lظ(™´Àë.Â@FC# t³¯3Y-GΕ°îm›$ø¥Whø¿ƒp6XÖJh�N(PošÕXY僴ë1bl1½^ö¬w�˜Ôg<BÃ+ø‹ï|q».QºŽ”ù‰Ý›V"zF�KªHuy‹¢®Í# uüø(Ü“cØ¡j¨¡¸]ûCL/ëö,oý²‡rÜ(¶œP™A™ [- –ï˜)t¡’ Ì“…�Ô¥¯€BÉê Ù U•èË-½¿•³£¶I‚Ù_.æBE*ísE.V¤û2“Ÿƒ ν¤­sÛ:nérT7ü�ì3Ð(å6ã¢ÆÓä2êõô£#[�L¸ Zˆ&×INü?ðþUjˆÎŠáZj ”Ó ŽÔoVϘköÊ[QÊ Îfa¸ØlT°íDü3-Ùê(rz•…v£/#ƾ4+óÃÆÁ3Ž4¡KuÜ䯮!]w;2% Ù Kn™;º²!Þc=9õl«`shÄ/KøÃ»’g—eà �ýÍŽÄGŠBtØÚî/\4[(m¡ð‰œ%Â&Žk^‰@÷7mx-BÐUƒ®^3�¹‚Ôaå…%€qžg�\ ïáDCŒ¨åÿ;QÃÞÈn;=-¬V/I�Y’Ñ Ê‘Ø°¬Ù;¾U–Ö¨3ŒðÓÓ~ÉÍ¿s$á,÷MvqmSc½\½1š¨¯SÅã"c¢8O’ô^~]yI=—p>´Ôä¶ßgwfA|·0¿“û`BP€«_R™1Q€ÏèB®‘ynóu·_³³=r�W Æî ÏÌÆ±vá�û±ï™ÄbˆÄI˜X”ôîßÔáßÍJV¯¨S"å˳î|'ïÛ�ÛJþx1âH4x“iFzÐübúJùD«›xrå�1”š è Ø^H)èAÊìt6‰SNÜ÷y¸oÕWD‚²€mˆH2€ÄFçeï&%9ñObÍý×.SXɈš¿j¹­�rÎe0»ø‹c Ë.üDÉP]Œãéó×È)€ú*�”@OL‰æŠ’l(ŸÂZ~:h#�4–;¡AÊp=æ2,*&€xûÞ{HÝ$ ss7ªæ©ÁÞ»mËTÆÕ˜î  ç�b~õ¾ÃÁ¢¹zîØ+�X€ßí®\& ºœ„ª€c‡õ¾²é�u$7ÿôäZ9ÞŒ5Ú<œË½Ô¯ôüÚ|1ŸÍ�ÂÓHmlTpak7Tø¼ŠÙ'M@/àn¤_®¶^õmåÍŒ‹/- w _¶ªL¹J;ÿa²‰ª�¸ÝÖÚà6ùg à¦qÿ7ÿs±Y�êõæsãP±[á5˜ÔËÎdMOÝfMºÝ÷>ØGó®ÿ¯f=êA÷ýn•¬æCM†(�½O”Öîl�œ¸£«ÅBï`‡íX� ¯u‚ûàß¿ò`ïùÌé8ÆSª5gÊ®l[]½­ç(ËÂr¸ÀóI\9{&TU¸¼ ¾Š9iÖ&”ö­æÙ6ÉÛA-N뛘Š%Ãõeä3\‹’Ý^ZÌ´¼óÑyâñýÑÒÁteFVå^¥‹—0õI[feþ…Õ6=�볚gÇzûߘPGáÅ šÚá‹É“8™ždÞ�”™ÐºLË©Õ_ê)Ô-JA÷˜ï6 n[f@ëR8m�SÂ¶ßøâÌOþ8¢H݈–…4±B’œ>zŒõÔào?rTÍÿ½JªÏY*fÇtKä}WTG2`ÔóWwS±þ÷K”Ì“cT è‹�ÿ\ûмnH¿àË̸bŒ±˜-Lm :_rD?#Ÿ#еŠ ˆVýw“42*£ñðW("ûË×70½ûyéZ·éá2)­úÅ3‚=¹Æ™ÃO?ÓMío¯k«w¯°þ½%$D6wÍËéjíÙ–›Y¿ƒ="„5æÏ©²¼$PÚÁ#yS¤Ó×÷+­ó‚íãÛDÂ]ý7ÿ�¤Ø·¢ ¥8‘®¤8æ£ge�îf„/t~\C*Ú¢£Ðüu£2`F蜿çáZÕV<ÚŽF)ŸçD��våÁ¯({EËd¢æsz­§Qµô8-lË™äKGʬ;êÇUߣÝ|Â+±0³Ñ0YÉ’jïüæéR÷|fM¾l™W?ï�Ó‘~GyB°óÞòý¿}!JàG~]wìäc¦À†øý¼#Ùô½}~?þÌ�`°æ)‚ÇݳRòÐ…§GÙ�;‡¨¡'Ï‘Ž˜1mŽoÒñ‚½‹äJ„B¹—eÝ#Ÿ1à1ïsNu“0{âè ¸5â-WN¿á¸™ÃÜÙ?-¢~¥e˜âgTeüñŸÞ¬u²­qbË„9߬&Ìߤ!-6†Y&Û¯óz^ÛFa* ±e)|¾½œAë­fãje£´ø‚;øôN’=Ÿ¤ü¯{2´Q�UmhÓ6hÒàU¢­>„[„@eCsB� Hnç•ÊfíÑ¢xXô)IA;Pù\Ÿ5á®.vòiTšSxž5nÖ ¼© µ{FY��� å;ß zéÊh®S/óµRçUal·ÙIZÝÐÃ"Øè|öô@žƒxEþZÐãupÑóh1®U%RlmÃ’~D‘t4þö5pJ�PSÆyÔ„dîQb”'þ#ñäæ/[7öQβ3ÿí9‡j‹Ê‘º³½]èGn;Ê#BÇj|bò¤6º‚SšÏJåbaˆ…Ž3Éí|ß#Žœ%"N_ÒyFãÐ�Ú`OžHêôdôåO—‹KÈb�jIþ9¥CTgZ#¿ÄTØËè‰&`Øyä²·ê ±m’©ÐD´#9ú‹D ÷¹µˆ�ç°ò)É%�A…6¶‰å·Ÿ>s\77Îè%›kœ"@*άEˉò‰S‡˜¸{o(@?éPCVÈÏíðÿpÉŠF­ê#†ô»Ø²³Þî8êýFôµÆrÎ-V­òNÐ6˜vDPbJû�WßrÜþî@�P­–¦>6!Aû’KþG;ñMïF5‹ZÀ(Ý·Žo¹ /cc'«|�ÚÉFö0™þ aZD5-4m~YþOÖ%3養,2Ôtq¥¢77îlžÞ¢È.‹‰¤ó¤æ6™(»j0ÂÄ\e0L B2îPΨä%S¾]NÛxseGnö-[¿Ï‘.¿ÜBñ ¼Z]àäçq‹—nÀ/™0ö­2p^ˆ¹ZÍ$/©ãíÎr2C±*óùÃ5ôŽIó{To®çFõ§é6é{@h“Œ¯ƒ�Ëj”ÉžA'ôt;½çGõy’bNiÈTàF~è\[ƒJs ôO…YÊ-ÂLüiB$ɯ˜¶IªqôŒˆmg�1¶1.ä-1öyÚýkI­í�ÂÑð4) !ª¿™ÃÁØ)2>OQªy«Tõ YRÁŽ{¸õ#%2¾ÌÐÝ*pTaa×ÓMåÛã¹Áôô;œÙï¯7�ËÖœoòXbJä®ó2@åšÝ"ñTk¦nÈÁרXzõ8ìpNÚ¯é­&Dα½EnL– 4Z„KÔÏFˆ6¦k´èsïJÆÑ–n2¤—÷:#Ÿö{ÖðÊÍ?°KJ>â;Q'Ê™*|\ð¢äš‹À„ äYöG<€„ÈØ(g–óÕÏ!ŠmÔ¨ˆ‘#ió´öPÊ¢åªÆ<.ޱ5lýÔ³fuàSyÃÔjBX‡×é_¨¡a3|‚¾ºOÞE�Uyóó çO+n\ �ãŽ&–T�z²ú6âÄŒ2:HÞù�dØœú¬>°þ¿aõ¡Ðm®…ÏÁžÁ&‘Eܽýli·“µ%‡]Ñãe5C‡é¤¹T¡ðªê\O›?t¤�&‰ZM­.[q€­‹0,>~†˜ž7\�CØîB’¤M“ÕùK@wnb[ïñ³5�k%¹êÏÞ/eqoFÍä!‘ußK1JˆVÎ}µ¦xs Ø¿Ðî&±kÄy§fŒò‚6¯Åý‘çËC)x7>ïZ3]i3N±€·a##”\Èv«T w(u'ÎÂmÉ�( î§#àã7%T¢Ty¸Í:qß[X˜y섈 &„>ï[VËH¨ÃØîpëR9ÁJ9¯Ϋ48]m¥ÞŸš¥ý8,>·U GÉùìQqã¸]Wñ4݉œà�_�ókyŠ˜ÉÂF”ü×€^ƒJMö›v±ŒÁ-–*yœP‡±í!�€s7Цoü›•‘-@ÖnǭȸÔâ3ìãpan„ú°ý‡ˆk¥�¢ƒÁŠ‚¾|á§Î¾“ú^ùÙñtïÏþFxè“0C[l®ì„hD#Ôk an€J"„ Ìê,EŠÌ «°Óïð"t€&ïÀ¡è¶¤Ím�žwR¿Õi57yâÎä+KVî)‰{x üŠú+ÖLoÖ¢ÛädæƒÂøÌ´¦Æ¢¼}‘5«xôïÀ á7ŠOy ¡ØNA2·¥z’§ã>FqÊí~¢�m51¹Þ mHZþõgžB�z x?t ¼ý’ôv”t†ÈpÎáä'#] �öxk8Ì _цÀ˜ªv®·ÓÁÃ8ý壳 ³¢9�d¤×ØÁk7O„&ÎÅδà£quM¦¸jQOD ’«zP›Éh¸ S3 ef2®ÕR,ý 1•A[¨”xœ›KÄ2?|-}åÛýAR¦°­ÿkÄß@!LVf~ÄWfvöë Ñ�Äç—9ÃT¢¤¯‘§=…4L—+Ú(YÓÅoÔ«f�§q0 4ý¨}€DݳëœrSÌjp{Œ}ëwç�š�-JmÝ­Çsp¡|ÁÿU5£MñàrtNÊwÇ›ö€=Å‘lC>ïWSzqNAI rØSº»¸ š»Ïóñƒx£ÜyôÓ~Ô9kª VŒ¾£@ÞrElr³VQËÁɸb(Ðákaá y–T“Ì•º ˜�9 SÆK墨áä‹~£­XJs•z úSZñO;#N?é[Í ]¾íY)y��ˆTrø›‘¿Özº&XÝe܉®ÃÎäü—BðÍj…3øáßLN´¸Uc¥ÜZùH=žÖ%J!>#Á‘«¿"gX-jÒFB²¾¬¦ÙHÔßßBØ-â¸áðØ%wN[uÙ�ûm��AŸSD!Hsb:ïãÔ.à(ôËE£>Ä¿€Ú ºˆGݘ‚…Š~Z½ÌÞ fj„ ¼ÄdǪnˆø9Ÿqÿ¦Uììè„ÔÄÐ1AùŠ‹`]ÂXcê„=Ãh¿…æ¼B䈧ì<*ìRš� wæ3=÷…w”û-Îæ|m"q¾ød䯒�û"4³ß‘‹û»ØrÊÞ®pÉõñYÌ)ö–¥ý«âg6@È×TÙ&Wpò…®Ê®>ò�êF u š9SU¢�S ÌJ5ÈÓJó#xaÚ¸’>ß/P/ý‚¥¼ñ=ÙÛZ>Æ7‚:›ÀJôrŸÜ’ù@íšM#)/j‘@ öTØÚG7ßãä'êe‚äNjš¯^R ãÇ(«ˆ*ò-¾B÷bÑÙ^Ÿ îâ�ìŒ0z‹{ãÅì%ðö̽l’˜kÊ‹tÑx ]ÿ‰Dw0ɰ=>�caðh[[Þ¢' úèÏá G)Jfû’ Adü*>v û@·1SËv)ƒ´Q¿ž­£bÞF±‹6bޤœ“뙉6B½ì¤_ýuÏb~[©´^póø¹9j¸]Gz“pvëð€ 2kÚÍî{}íãGy aÙT™òoÔÊÇÎjÔïTn.²ãáñUeèÕ%".®Xv ¯ƒ£~5µÁÍi2óe¸…H¸n¯ÀÉK~™q>[¹%Áˆ ñ[w‘˜¡Qáe~EnAØØÿBíÁi§íÇàÊXhãBŒûs2©ðØÛóñò³{½K´’/à›žV‰Q:9ý"[Õ­÷£›'uÁÿ•ÇX?¬PY¤Þ×OzÁ;¹Q²að¸>ä§›ÌÔµêɤ§ü”VÝ+6æÁäyRSY°f À*{FaɼȀ4ÒC;éÄ�7#¸:—¦="]ÃpàÕa%iÞ#5¡–½Ê=rÌ-Å»¸èáÚzS‘è%k!jl¦'zÉÏMVjZb»k^â+Ò§%¿۰O†>÷öµy–€¤1ešà«™ÊáÞt°Í]Ør£ëW½evÇ¥côXSã[È HK�|Ð:³«ZyÑ¥ë(KPþù#åx —ßjI’o6aýГ�œs†D¥sóìý;ƒsÉÁ_"…0Øx¾œ™LP›ÖZ¤�!`'ÓHu¬ÙXŸßtŒ¸`)ì£UîwF§üõ¤ìXq‰ýþ>ðu«ò¬`×�Ù,Ä8ÖùKt >úÜaðñwI=r›å›·Ü�ÓŒs.CZ1¾“P§²´I�ýIÕ/¤y6ôlù]KF‘gsE22P�R¸‹wƆcwäÂUz4(æRK©¦Þž> ·+Á»µÉÎý#üzŸÂø?sÁm›XXø Úvm˜Bõ^$ª÷+Š<Ô5 ð{ÕÄ¥Ž jk‹&™´þÌ]¨+t•`±=ËÉ–�‚íáhMÕ� DT)Qæt-ˆ¦rV•lºF;ëœV½"ô‹,.Þ†�Ý>bç(2.êr3•4kÙ@“ôiVÆrÞú Aë3@e �«!øO²÷"ÙámÅÞÊÄA@o`§¿ÍL$&šƒMš_A°ÔÃfucšûÒôÛÛ/¹@È0°dšD3¿ôã¯ÙOgöÄ ê¨ËH´p|†Q*iÛú¶nµ? {Öü»4«n•~îPŠ·®pS¦’ˆ¨{Ï@r)vó‰·ø‚E®Ï©ÖÈêˆå÷øÑÀ+U–3érhI÷Áé-Óð»D¿,Ïm¼ÈØï,s¬ðGªÝ:³8“/ß.Ùhhò…; "‚Ø4‡€feÒŽcD�¨V÷8Òòx•ËØî5:&�âÔ逗¬ì¾YË�uY(ˆEë-ôÛÈÁ莒Êã«Ô÷ò¼Ú~qÏ?=Eü#B ¢hÀš_ä:ijxo–ånŒ „=UÏësã?ÖUG £ïf¥ÒÅó*öÁÞ6ßÄÁÙ�†ìg‰Ø"5ý ‹9ÞºóËMiPìüD_p”w©ÿü1+ÛP@ŽZ왈Ÿ«zÌ É�{#KàæóbS‘»�ós 1égÑ=Ï»É�ú® t«®é!*¾¤jIÁô²¤Ù�¶Q¹xá~ótXŒt �‚__ ë‚D±�rg+p†lJo~Ýu\AÓ¾�èˆ!�ÊÓ2³ñ-LëH»j'{a�ÏMÆ¡„´ƒ¯nǘ!#Øw÷Ú>ÕjæЦÑ"\|@¸Æ|ÉEŠ£'Åš ^ŽaõY@¾ùÄ™ã«o”Sˆ)Ú(Ä¥Ì{BÜó`¶â~§…àc¥.œx“±—5¦H½ÄÐEçë(UÝ;…2ÜSÃá,)¶œ0ÎÁ°t8€§ÏÔõƒŸÇ%Q‘ÿ�#êä·s4>z–ïÀ ê×5Ô( …PØcuK+ªß<²Ðwüu �Ýn8ü1$—Ð%ÌŸdâg㪳Eƒ-pȼêAvÝ�3)âý?IJ Nôk&#WÊO:¶š¹ñ*~•Xþnã&|'�AO˜¤!cÐÿÎ*mqÐ¿Š  “îHžˆÕŽ¿ŠFs+æÏ»ñ¬ÿR§(öéM2w¥¡ÅzË(eÕë›KmǬ9– �$;wô´gz±±R¡Öø°u…_¯:Á[bß ¤ÿƒÛ”ÓŒ;¢Ñ~ÜöE´B5’M:&7üfdž÷ï%›‚”Ê×X‰Ëà7> »õ¶…oEYâ¦R^IË^, ÿìæeê‡z8‡9$X9jÇÁzÑ©Âß:/ GAõ!ŽX71#ù Œ¡‡ aØÝ«b%˜I E,¬f·âÝÂŽ×-ÜÐÅ&òàhúó\½žùœF!ŸË$ø~ ,8G×q‡±Íë”Í‹dnÊ÷N`Uäç —’‰zç® ¶yÙzlxg3ROS ,Óh%ÉéjÐÿ(bß}Ü52ôfÍôÓ!Ä‘u<ÈÐù·>Û蜲Þg`%¦žZ• ”kùÍ.6/…õïS1н…PÕüÂÚx†o *P ]»�–*ÞõÁÈniÌë•ND‘¤ÏÅèG[e$5«#íâ‚ )­Ì¸a˜–”o¾A"rf‚8e.$|=õcàm–ç%êíu;騛q€ÏúdW�a³y5ж¨,ˆG�f_°LÐ[ÓòdH�Àèú3bªJîڅʼnm=¿˜~ r±ØJ.K,þÜ�Șã‚Ufü:ðKTr£¶?…DW¨œ8mØîU<þàÓý™aùÓ“�Ë€óš}S‘ WâP´[W4Ë>÷ŸØ‹KìÉÓ oŒðËý·M|†cÍ}'_’Tiþ®Ðrmòêît‡Î%á p�`k[„@ÞCÛí-$ÃÍ£ •]s6#)ŒÒòc·(®®Ö•§þ i#áVEƦ!m™"ž0¢»Úh{î!éãþt�)yYZQ`©;¯«¦‹Õß.ƒ°®G³>4ü'¿ÎÚ‡ÍzÞä¢l;RÔN±4ÃK·xáÌéýh“Ó Pàö/ìÖ|ÂÃ�¤ÏÒÝ*g^‘ (’Äj@ϱ¾$Vª² «Û`Áÿ•x®³]*…¦�µÑY¶}Åùy|@ÃxB”`-H7,º ٯτE.5’0¶ò>:œ­…´¹¯öd®Dÿqi9Ž?4ª«•ÁWŠk>†¼úó�ýGH‚3Á4Ð`% ¼€fú,ƒ·º4Œ´‰èƒ£Í줻'ôl�HrÔ\Ù$=ê~’ÑC8øÊÜT_LO¥{±'‰?2/Ô-’ü†RçmS\—0;»Á(8|Ê’�%·%ûçŒõu€³òR}}í†nnIó¤í}}ó;lʃ×>�Øé�ä¿äpÕ˜Òõô¬gD×ä5Fd‰= ‰ñKg¬Õ;‰íc´z(î6ˆà,Ê’Hóžk…ü3UÇW Z߉N×ܾÒFy>&äß•~ÙNó ¿ú¼e ZÀµ)O‘dOKj•#f…î´IGt™Fã22=é�7�§Ëš÷»¶%"i¸÷З7ýØZ´úê6É*P±‡DN&™ J;ãÝá ÃÇTH}žÉÙÙ¬ÌUWeg*¿ÈN_>!‚(C!ªQ`G½±è‰údˆdrçÕC¡< ÖA±& =)JèŒ]ÓC¾³Ü ^Щò±ÇýÎØÆbÁkÎ £è¸4¨u{¦1�3¬ÿmÅÑ^8B‘ÝL¡�~×ÑÛˆ›ïBFªœ_m<‘£×ÆKn—¹ÕM(–UŽèsKŒŒÊŽq}l*ˆzâTrEÜcjT¼#üÊ|ϸk·Ç¡Ôù‹~†Ö\oÚö3múK,Õ+°Müݵ]ÑïŠÎå/™L•R51ù&ÚŠVú¡'ö^øéû—–áEÐsý�æ…×NvôU‹UK²)Êš'jAûæ;|´ °‰ m–¥ÂVgìceëDÖÆÖ;\ïŸÄ«j£½8¦¡ð]9«-ʼn4ùýëR0üpm‡Ì�œ-Èæ@K0¥M_¡—Ÿ·y©Ò›�´"¡åóŒ–óaW@†2Û Ñí.£iâ¾1Ò¯`Ìߨwp»ÝƒË½ê‘örÒÖ™ZÿíÎ>"ìáÉÖ…8¯±‘:éÍxªoòõ)?ʃßCjËšÞ¢ÎnDÎTA†Ã¢õÞx˜ÓþA†JI(XŸÕš€nöøm¹•kîºÊ³¨Þ>æ¹üª;Ÿ¦çH'“\O‰ayG¶Õ³÷�D}úðˆ8˜s£VJ&’ÝL"õôTf>VðJ[ów’‰=‡¡îà3Þü­ô4ȉ?SPo1>:ý"kj ü]‰àÕ†ixXÖÏ>ÚZBdÅÿ=À™ðñ·µc÷/чN7™ftèÄ%�/4î?²·9«¾Å«˜s/fûÂ/8wÁ›•—UûšášñžÞƒ—ìlì–®è\§ñ¸[�©žLD"‰Sö´^¶JW2²ÛR‚ά¹ÄŸ/X@Z"‘-nèeÈæö÷¤ùòü‰kmiõã$¹tKF™®�E½›�Tâ¹yqNùÐx Ðíþ}—eÕJõÚ^jAŠx{·ñ\\†òzé;f"U‡p�{óæ€ýÕá´-w£½úÁZѪØ ØSÔ©Ç]õ¶Öloû©²Y½n¾¦N?ü=L9!Aò×07¯8)tW¤"7|>&vDr?a½Â ”ú b¬•”š–ÈmØÍŸ®]~¢hdÓµ|X”^ÂGqz]á絪˜b¿-ÝÅCŸß3<| q�yw�ª|ˆ,ŽÃâ•ú¬Ö¹I ™­GUPA®ƒj?\«ìŠ{´ôtž€ãŸ`£¤$aøÛÁês¾Ò‡÷ÃÑ(×&êú;‚µ^é }�=98®Î¿€^õ�8”Tx·Šúyâ‚“((¯™yôgî}ÒJm+íoå×A�ñu_/Î÷9³Å(–"¥_"ï«1§Cù\råû Ä0FOÔZ­È¥Æ–j�h[' ªAžxöoìxð•Àåá3¡v²’Æ�HhC͉Bcó2Á)̉÷´’TÕåñ/Çè l"‚`F’¿î�¯S4ùŠhˆåt·ö“gR×�´ bûÛzòL x⤾aæ`î4-Çà /žAÉEÄ’Yg˜ë´•¬£À”Â7o´¼WdGœj/ýÎ,ŠéPk–ŸWÈ�x;Ű@½—ÏëiÑGa $ ò/ä¹{¸ŒÁ~Ý5×€»àwåÚA%™u�À,¯»3¶É—‹„*ýÃ4î[�ŸâÈ,ÇZÀE …?ï»-Ê£1¬Ý°�™_Á¡å ¶äøQÛW§Xó×MÑÐS³‰m“ÎÓ”Àø ΛÿÄ,z�´Ã< 5²u!&„óóã?nßnx™Ûù¥©Ji‡¼BÆ„5v%%Ô Æ�ª–‰Ã½÷ç9 §bå¢Ñ>âZBhw²2L¾¬k‚)Tó¯.òsGN3CÒcO¿É+,-ï¼°ÑÁì$‹b‰›GxLèÏçѬ(X°²l/ðuR)W :§Ò£S¤ÛÀ 3{Qy ñž^¼†åìùÙû‚9ø¡ßvù­HÈ$’^nýråJlnô­'qË5ˆ?h®'aÿ/h~£†óðŒ{`ÍÚª\­ø„˜ÍØŸ?Úü±HÄ­6€svøÏ£¸8ke¸ÔÅ–ì…_$ga´•D ̘›ÈpÞ—µ±Jo¯Wø`G©/ÌÔoÌoèB¹¶gÀ¿öÍž³MQ”*�f E2™ÜXJÉûÚ"¹² ÿøÊ :ÁC½ÙêÈkm7s Ü€ª{³µžúKÚÕúþÛTËü³óšµÀ9U9§³³Æ± ÀÉ’“•=.\>³À˦¸´ |`¸§�x+/42R0B!•"§húó!Œ–bÇ©Öu­Aå£YÕöò3Џ!P�&`pŽJb Šà•ÛÄŠ‹´$¶òø‡íÓsI?{£ó¤;<C 4[+s¡¸ªQPË�ã‘Û—Ë®?©O FõíÊú¢ºß‡ ±Ðîn‡’—o ŸÔ ´¥‚”U4ÜÇV�„ɱÖsKR»…(i¤uÏ?úSâFZ�`̱â9Bü#ƒcŠ ”_(£^ŽéÌ—Y¡B<¦'°­â.Ý(°3œö¥‰Q`ÎÜÓ¤ñÇupR˜±âvÿ ŽÎ¹ë>ÀóbØ4zb~à=ù–”�ÍÔ¤c[8ó%*•)ÔZ PœF]jc±€“#weßœÄ|+è¹§^¹ç°•o‚3 k”ñŸT£âX†mò!ó^�+ç\–ƒ…ìo³GDV“�à›Ï£«µpù¿ð³RÝd|áÊJî„ ~gðC�q’Fo�ðe* ZNFrm™{Ÿe= ½ã&R®$ÎKœž7hÆ«LíAÜkƒA£én×4QÐnx”æYCÿH ¾À¢…³åOn˜17Æá÷TØ®Óö“Wæ$qL¦ˆÈob`|±r[¡»4M̱òaÿÆ6ï}ºCäwb&Ø Õñ…Bµ‚µNOO|" áWÌǼýÒ,q·“9Å ”Ãq§§ ?ïm„U¶ÔÌ÷Ó�´ÐذR¿p¢œæd±å£�k©wÆ×†6烔ãsÄ Ê ·ìÿôzÓÒšoNÿ[yŸ”Эr »Ý$÷Øï†™ì9|Dƒ^D˜ ¦‰ pÅÖ±Ô1Šr –Ldü!ˆ°ÍÓÊÓþÆÃ(ð–øÜ#ž “‹$ä'ÓŒë%‡+ø='v“d�HÁR­=mœhEl¦SÛÀËæë…½’¾Ç8Âú9WÅ@™„ÆAKÛ4ÁÌø£›¿Ë\•Â¥3¥µ“ áÈ©%ºA¼‰\�™°&%›W€¦8\ºGhX©0–?Êóy6'nñ—kSæÝ¼q¯FÎl1�„ÞW¬Q!”�²Ë#¬ûé%Úù³àBÍèa¶ˆGŠÍ/ýSýäõšj�’rÖ»/?ýZ@ýT€Ê�+[λñ½û¸l[—#]z\¹~h,Ë=u ôJĶ_k ë = wÇ‹A�ž²$êÎÏÁZfÉkQ…9 C‘å•ñ±mqÃ5ƒ~®@>®LÏœ%>EBH3_.K ‘Bœ¨pˆK“X,#BjÝ}?��««$Y1)Íà š q v2ó t ÑMÝ6Тܪõ�: «™$̓Á³¼¦N±�QH@4ž€3M¥ão·[á9D§l %mEUÖà&Våx« mú«g“ÍuO_!ðqÓ4ü´bE9×àQfxm ÀÞwý«ƒúÇ@ãfÒ/ÞzEîŒÛÙv�¸ .}p�ð©0«q爑ñ2š)˜oÿ¼÷ÓýÎ7[Ct?OíÍÇ?Eé`8‡?)‘äÊ{ô¹ö_meÅ'ÊÔp«â„2°ÔÿÑIN‰ªÔ`Ø0phËy8y¼Žf�µ¾²§TôòϬŒÁK6œ þ…_¿‡a“"-Ü…oû;Ë“‚À›}š€ÀQú ÇÇÅ[Ñ3,‹7ÀþÎu*¦¼k,$+"5’�ןª{êíSPˆçt“eÌ[]1úK{?[íÖž^o­dq­.‘v­·�†Áš5ž‰†Óàù™ÿùþcÂc�¿Œ–’ *SùfQ–b­x¯0¦$vëѭ裯’Ì…Àu jÔ@\2åHj]F®e?”žU °éQ5œ{ÜþSί¶Q´~ʘÂL¨SIHå3©+´Ì÷;.Î%Š éV 6Àšòh`ö8�³,>ô@,|{£%2S™ ½´‡°¸õÛä“—!lRÛ:ì)LnQÁY>Kž¼¯°®Œ†ú‹=í¶‘$ÝÞ^yZèD�»çÏR¾’¨Ü}û#%ö5mF{ß»y.§Xëбš1£ú9ÓZÚwáúÝ<ïÁ‚mñší%²³m¸�}®‡·´/a”B²ÇV%f¯‰Xü™hÜŽLlü1ûc¢”߇uy¼Îå‘ÉÄxy¨¥¬Š‚ë[-q °ùÙEÓ¸”Û‹û®:vßÞ¢!È+÷šëo"u¢›«WiW¾È�Æ9C—G"Èšø¬�§ \›‘ãmãâ³Q’o쑈Hót; ¡çl^5‚ƒ£%<‡r[#žEÚ¥[ìÙj$ßH$FhñÍó>ᦙÙ3`¸`Î`ËÊŠ´aCoí—Ô†Bm${]]‘ í,U™£«™Úž¾F¼$_eùkÖ¶}d§Ê $ßñâËÑY¥…ÃkLy!šoo=yÜj¼ ÄîNÁIw³¯PhÛ ¸.•¯ýÃL�ñjš]C‘Ƶúfÿ ͺ‘!Æzù*sÐf¢Wé/I¦;î û%zÑ®Tn"Î2Îψ±JP™šÔ_Æ‚è«-÷‡\ÒÜ{mÍYºâbñ›·Y¢V)çk÷*YÁ –ÇRæ§—šêm:0¾‚œ/ÑC¦ëRe b“¦VÄPec^t -å|'h&–Ö,˜¯k:TA‰§ÉE±Lja—)šïwnì–ç`g�qˆ>[k£¾9ÞØ >ZÔÛ f¬�P`Ãõd¨¬w`ì4uüKb¡À›G÷–5†°Öo.ÝO«â-À´¥HM˜ú•ìKSͽï�÷Š=Ρ`_=!²d« �¨ØV ¼�ÁV¬½èo1q¶®à°Ð˜Vãh I¿ÿdÜBކ¹/Zª\”Ì8ž .Éj5Â0C"¿àO¨-ºHebÄô®Ôý¥’Üo^p÷.?;„<Л«”7¾‚€ª£|N¡Ó±�=_ÑòsbWNs2óØ5+pÄ\B›'H`3>ã§€¢aÂ@ç{3 !ûä–U 9súöûàSús:³45ïµP¸�/W‰4.³”ö‰XÜìÚƒj�,gÿ0p€¹ í%}hôíô×áÎaz Éw8^ô¿Ë”нxmäÝ›óÔ'ùç©»Ô»¿£Ð‘t>Ãâãߨ•n Q)'ûkâ 6ÌÇI-[¦m-wéx2ª� )U CÜY²‹Í0»ÆÚ­N"ˆ3ƒAî­•ÝN™UHR¦ ²9´‡@‹M…ÐOµu°�/a*/eéÁuø1¾œH̃•Å‹ÄëËmälWqi]�Öåt±¢¿AøçTA<˜�¼h¢I…®jaàÔïÑ&lݦV;5sÏýÃôÀkÔkËóÉL7)æHPÖ°óMž˜Ü`·Ä+è6‚(¤ ö¸ ±î–8�*ü‚^ó³ä‚fH�‘€³½®¾U~˜íâÔmB5`¢µ®¤Ÿ6]ÝøöþÖZ?["]¾ÞÔAsÀ—ÛýÛÞFíë®9/ýØñÏÊ n$Oœƒå›t¿÷Òãé†N¹tiC¸dp�½õ—‚Î :£NH¾OoUç-" *µÓtïv'�-QpÛ»N¦:³�v7ØŽŽå[“·x¦ÂÀ>¾��à°Ø%”£ÎvMh¬·áP$/­÷­Sõð <àI^tô‰NœFª!Ï®¬¥ ™ L¸;^bIº|èAwÈ/ü H•élñª=pH´¯jnFò´,+:šðiwo ”u Ëë|Òà‘Šü¦PÆB~Y°Ñ·’>çBé�³ª�ãLl³ñ3ë6ç6¼Þùë§IݶÌGÌûé½Àƒ©òi;6U–ÆeÃ;Ó—>y‹ù_ç¦ÙÓ ~Mòn:Q²Wùô’¨Þß`m„»‰Ë~o¤1°‘Ý×Ä—5M:nt².}ñ>�-1¸PõÆÉ,ÆÃºBìc˜ËÖe²³Œ‚[­Œº965õ¶|�vÇ;‘KC^ðh ¸µ¡�F¼aD%Ebg­é– Z‰�ðÁ/Ѩ¥oWw6¤Y:Qu%YÛV9Ã$7èå‡�§ìË6Cî‹LÖ BQñÇîj¯F´ˆsÁsz©c´¶J1Óù–Po´&úE#ÙKÜèÇtF}5>âýÑAdˆçæ�:™†ÁqâßMGÉXÂäf¾A*îì£ �…° –WRÌå z»º*­ÄÒv�l–¦ ~ÂJ‡ˆÂ]¤/²ø(�ì [o\޹Û†ûXÍiê´¬H ×UõâÁíì0Ë )”ëR¯2N…[œ&[L«EwÊù—”€‹És½Üçnn�º}y‰F:ÂL9­•«vÎQÍ-ö ¾7£ýcvº?Ó¾x Œ«ªÔ¸­v~y‹ËfI�N.Ÿq4õÈP‚#g´èö+NZ%uVñ‡Æý/"ýA\$ÈŒ¼ÈÝhñD]qðÈÈÇþãÚõâ%L~òYÔ¯Žb¢úª`3(Ñ€Yÿ‰ŽjV©®q°•…¬âA±2Dæ°äÞ‚9Þ.·®-Níag‹_5xH?YýyÅ ýaþ)�<˜TÍKªÕ%q6§[Í*”„_U¿ðäãÉ3 ø±"Ë�öYf¼ÃO�ï`ÿ¨‘þ“g˜î®´Í#¿ qÏšÕ5Ž7î½£L6+¶HfÕÄÉ'O–¡Ÿ`Ÿ´nM�'çïk XDâEÿ°ç=ê|‰­a±õ�ÌäzËÒS~ÇŽO q+…YÚÄ>Ö¶¢¶®ÔÔ,x'ÃQt„Ä”’ªv—×d =sŤïeáñ¢W.~‰ç0ü´ÆyBÿ%=þ—n�[LiI?­—U~Iàó`Ïú|2B �Êb´"g˜Ùªþ±©UžTº½kù«íGí k^£ç×ïBs¶)+!®×õÄGau zÜI3r§:C§5�D¸7Є¹©[ÊxFs°F)%|‡í,A9Œú·Ú"Ñ" J[ÓDï Ù÷ ‘´Ã Úµ6Å‘ïŽÆ–¾‡ù ¨Y=‡z÷_œjÔß²“ùñŸÚ�Â/ˆ ÃÊ‹›Q! å Ym†?‚›€LYÂå=mzrÁÉËIä‚ÇUÈ Ÿ–ÓÖÒ´ïRï<´n \†+¼2PU \ËÂÞþíN!–A6?r¦T¢71ÎÇ�Àec  5�6ÚGõ£ ‰…?u÷� !@2Û>�’wá…,}¥¡N‹­ß_oƒNJš¤Ò6CW†¢m|7²q?Ð 9C.NF™Ñ‹£S«õ­¯‘\�ŠÁás"÷*�b#Æ-h #À—•y=ÇŸ—tOõ+AC¼*w-C;wýPèõ¥?¶šêü†³$À°Fo p*ŠLÀ~S<Á™‚ð�ݦˆ6”äžQ°Ãí�B7;^&}Ÿ„–ÐTYÜÍ¿î,›4!YëÄvÿKšW"–޺Èð,KN)ì)pšF ®¹VJ ½XçLZÏR…h€¦Ø CҘŠa9çÁgê3åª>SÍØL=ŒsCÐFÙ@Nà2/£*ÕÐØl¦:¸V¥5Ÿi™_vŽ…]‚•ˆáC@,Gñ»è�ÈÐôsä‘Y�„vß(-íGR¥�(‚�!›ð{¾X> m–}¥¦~ý"§4# Óâ<Çêo}+ð^fÓ•TN¦%æIv¬#‚ᘎvw6Òx›Ï›üÃàCmF†`ð­xæ �~Û4UͨK –›ðºâDA=Aô€ÿ‘­a¨Se ⟅QS[göù·!täÔñÛý fj3rÃeÚ­mÅòPMÕ.Ö^0šûý]€Añ�6”ðJ¬ö�’§Œè�yxÂØÒ¢_œ`ñ„Ü7Üö;J7ß—s0âvsdžªãËl=Tg �~Ñî ã4,É�ÀÏè@qÁ>�ól$¡ó°)-¼ë 3Yõ�œaò…î”úÃ$¿P:‹–Ÿ×ƒˆËöwjÜmH~ø ‘òÎÿø}ÎÖß6G¦™Ò)ÅœVgˆþH�åìiß7{´ëï¾}_)N Ä‚´¾�³Ù²piÄL'@'Aƒ¦:[Ç>1ŸÎA—ó¼\×·Ë�\ÖZÆšz»H÷í¬ï‰Üº@¤‡B^ÿV4-ØߨÊe¼3\:+SB:ŒVÈp—7šÝ=%L€>ÎÞðõHßäx9öž�~Ð(ŒH|CeZÕ¡Nø4ëâºØGN(çVû0H‘ÇÚ?|UûV÷mṯ¹|4<ì‡ÑæÇDö ¬|¡ÂÂîYmž~ßšñ§>ÝJ8¨|Z ÎQ0LÆCnë’.Ѝ9ÃÆ�xÑZòú2àT·$?ïØÕŸ:SÐú©FW̵Ʒ‡´cŸº‰àA!àà1H@L"7«fyü¬„¡û1¿Ç¾1óåœKŠÕ9ùonÝâ]™òþÿ¶Ûšñ®¬´uLl;§á$¬¸î‰Tÿ�Μێyž3ˆÿµZMnf1'Œ¶Ìfˆ¸bö\Ì8dw ƒ‡«Z* šª�ÜíÞr«èv¡  ”˜[RÓòƒ¢E?Ë®žçþxÝM'“(Âe$† €w�^w/&Í»®¥@j™€Ò‚´”1³ öÑ«1|²‘Ú¯½ºîú`ðÇ›|“Zu ÆX�}Iƒät56Q€W Fª!ÝÚO-£o’îÅж¨2:j^Ô)¼úV¬ ˆmûŒ¶‘�æ“àÍVÀµª<\‡d#Ý@–�–PÌø>öè Îü†6ͬOåÔçâñëzö4ÿ§ZúÛCTt_ˆ‰`²¬`:ô�ñèË9„µ–æ,<\a÷ÿ@gËÍ™ R”,ËÒ¬Ioœ»º š;7ŸÚרäþÉçÂ<€¬‘‰‰æˆÂô¡Cðïÿ· ÿFN(Ô>¼(ÜçëêÁ›¢RÇîBÄÒJ;…Z(çËw=À»3RôCc”ääéã6]åÖ5óUÍ�%�<®Dçä¡ÈÍ�¡dúMa±b²º”%Q�$XZè›z9èV¨ým4¸q³^ùË Ø!J¬w”ô·†oQûlmÕ²½µêº#›à˜‚ÙÉ=ªOë |g;Q¬“ˆRQLÇ£L:z^‡Zh›·'ăv‰s`ó|œ,'[X@øé€¡Úzñr漡ÓÞòmÕ½~+".æÂ}auãWd`ý/¢5©üˆÇkѸ€Íñ§\6~±ÆHIèp�^ÑtìuLM!sÍCHפ¥¾£×!%~*¡¼1ÄR ®Á<$¤ò¦‡àš4k‘ŸA™ Åw0KÙù’ÿbÇüŽIè1’Éá²$cxÏË  41æÏÏùÑ¿I'ãRdbîûXØÓ¥�TŠ cêÝŠÞRÛ»a†3I‡ýÀó‚B约“w1©ô]Zë5ÜàÝx­z�R`Ô°XĨ·r sé›r¿p–D~²³_®�¥™°û¢–wÎq¤Y9Œê+ä-Ñuzž§Û‰uôü¾t�\ çØô�§WA�öœùªqd¾*;³¥ñTb·eœ?dX�™  ‡÷“׫áÎý™ æI K tgñÌÑi+ñ]×Ôv Ú°&ï ›w¶jh5¹»áK àF«l«oåF4èôuâÇ÷ÿ?­Í\Þê8MÓXù­ 6 µCs~-é~ñv<{µ‰I�²6ƒ´  :!o:cS•/£!è30[YØ¥Ž&’Ρ²å±ð§eÔ«ã«•u¨ÇYÞ»¿1ËŸ7ÐáŸ{6i…‹s-À{Æ0ý’v�al2C,/Ò>œì^p„+ߥémXEµ{Ð4ïÏ·hþsúyR0†üaÑI…Q.Ô$Ư+Ä^ÓÞ]² Í52½ úI=ñ×駢俗Fàcô¬Ï³ŠÃ§îÁ´ìx\Zq þCgÙF«2þ˜B«yÈš6ÝØöMÿ®GÙäªiýWëÒ´«žÜH 1é1ª—U|æåø#¬á5’>cy∗ØÛ£œö¨áRÀZï‹ï—‚ñ(ÏóåæÂÓÊM ©¡ÌðŠø&ÉÀÊr};½ä2ka–QüåZ—OÖä)@f ÏöcÉ 1~êÍR˜ëWõ�‚ø™ß;Œêr¦UEÒD´ÝÖäU˶•cÐéCþ#ZýpÐ]>SçÆ”’M³¿ç�â2E…@.ŒñK.Õ�¬qN¦ZM¢|tÕë´¸1±q†cŽ¡žuë0ûR2ö¼£ÙN{íûUé …"²–¢M´8Gzû^Õ¶ýC­ñSÉvt³<ö5¨¾¨G…‹…„÷-Íרþ;Æ3vJpF¡Uôk¯¢Œhlrús ßx’‰#Tt Þ¸}‘Pb*3 Vp5úÀ¿:œ ¹æ`Ĉ�ÄLlü.›Õ��?Âzž#èݧ³e-æœdPæ5è$hïBÕ˜�ªê�åí~íêßyúìºGsM7HAó÷�,ÎÝ{þ[ûV�™r”B‰˜!Å“ ›ípθÐÃÈ@«ÐÜmUj㪠£bäè2‰AæFoɺY^)sÓÇÒÊE8n›ubp³ÕsÙŸl±Ç¿GVòxl4Ž�Šª<øZ8â’:ö)ߌ·ˆ»t¨£4´GÛKgˆ(/°þiÍ_Õ¢à’ê3–sûŠrç•’ÉOÛŸ¹Ðž.gA…¹còÃFB�Îûk>…Å)¡ñ`OŠÖAó¢- K&aWy½ˆv3%Øx#œ™cÓ¯Í.7i b¢™àË»ÔâòÜjhçú™mµÎûo”$�«Ž_¦Ê�½©ïø©Ìݳd@U¶t?¶¶¦pÄÉ»�9MÍÕÛKT;v[Þ˜Ð—Æ ²½–^ù/vLµ:fžçXÏ+¼ TqbƒɎɶáQwÆy6PöS«xè*{Zl΢÷õa ôb J¹·&WK„§&ÖwžT ÙÔáÆP æ‹BqŠe "÷ů›OŒC½ùl¾�ÝΕŠì3-oÖ‹-éÃDˆ`í¡6ÒhÙähÁk'Ây¹Âvâš ÕXgJZâÉZÉ­@ÂfóXEþV—HJð¾ ÷­¢¢É wƒu3VÄ™ŠŒÖÉçVá±,N÷kSº´)”V¥²…UGäacqb<_þƒR;]8ZjyÁS�1óÌýÞu6ã:�ÛF.u6. Ve'Ã@¢¹ôøy½£ù¾‹ij«,z„ý´œkpêíC2÷N $~ŽEKO�“ J†"Î@õô^l‚n�� ï“hV�sʹ¡S­à©Ü×ϰ4ü4.ß\ŸU±”&ïƒHºh %’s,àîßfLDnM1G3í¥À!¯xÕŒ'›_g!xšd.j¯R’ãéA‹–Ù×äš²u‰á–¸ ñª.8²¹„ŸiªÏ½ Ë#TYUö¥ñna�‚…¡›RÑ|€¸ÝÆ‚PZÛæµ®V¬�z†.t0ð&ûBÁ9)Øo+³Yš]ÐØ3øh[Èfj—9Ýv箨ôå°X6—+OCSØ)«óoÓ¿ùNê#ùÏÌROYÞòÞ‰¸¼„Í2 ¼…yÒd Ë·…¦  ŽÎ ¤µ)½\exáàWuýyݶ ëxå³Ñô$ÆŸ–šW QŽ`Þ_µTõ*ÅǯHP¼ºæÃî,W ì®§�Sg�{ãÃTt§]} éÿõNÔÄù×¹Š�H£�ÿi3øˆëÖ”3Bب]ÃIÌ"®uSóó% åbá›å"vèýE ‡;sõÐJ c):ÌüµÙ±ø>5å˜HH‰38«óûª~�´vR‹ìUÈ?ó¤r2öDê|K=ÌHȹvÊ­ðG«M �¼0fÏäc—D=ÿRØ¢§:„ÛAS‡‘FÒ<‘6wŒ?ÙõþE¿˜[…åJž©Y~`~nk$âŒOe�;?wjðé|qè§V»Šwã1cO››TbCx‚m¼Z·‚w&cŸo•Gd[Í?¼Xð¿û5/½½m´#néó�IÈù2ŒW…4Í\ÀÜÆ<®z’‹_gV»d¼X0yìERâcNÏìG1bÞ¢Õ”˜&œðËK;¹¿¡±ØBS¾þföpŸ‚ˆ‘ÝouA· ¶”2qĺL $mÚ$ÕÄj.ÿø„+‘WÔ¨%{±Ë㫺y–ÓkÃJÓ«lÖE·¬\2žÎ¤”‚íA£†h÷ÃM"^ ›�ünÖâ±m AÕÕd‚Ëü¹ßG‡×€iŒÀr$*u_kÅÒ;5=ÖÏ;‚yäøI'y$fã?š+±…2Ê7Ñd!î”Õ�ÈÚMõØ’>Ù>û�J‹2ÃŽ¡ß KAzØUSº*È/lÐnŠKëO¡8º’¨ŒÆ.Ðß_ vЇÓBÀ)Õ¥ä{AOÁþoIE鈓p"¸yâ*âVÒ«[6Æä.—cÕŒô;Á |j²“~T8ƒÙŠèHTW%èÿÀ©#N}Wú&¤Ž¦!LW‹GÑ™ï+,ë `¤gº-µ–¿´Õë&o¿‚üÿ¡î¸ùû°ð®B¸Á'�¸¸0­£<ëãçžvŠõåªÈmÁþ€%Ìr¾ç&Ýk4Ju Ë�:B5A4óR âI¸X+¤æäa®{º²Ë¼”ÏML¸¸±�©ƒ¶ ”ç�¹¸{;{�|?Ž õb Þö‹`‚Äa�ÄÛ1NHîlpsV�µ¬pÁO+£Oý 7k¡°kĦØEÈÉj̇`¸tù�Ò'+ªøFC˜¦0pøKC&Õí§VUÇv—‘îN˜­[a04Š E²×:hé—% ?³Ç‡©FaÞ0rÉJ•§0÷ÌÞwÕ�žZš´^ó™*¡]|Ù) }õÏܣ̥° ˜NwÖ^øøo§G^Q^c['yw³“îqºá±ë¿1Äž‹„uuç“}Ðs—aÞŽ$,&ì ž¶§L`Š[äþoI,ªððþvoü‚CØèùÁeÜËïžnàý@~G¿[e:å]!ª;7ǯƻ.ªÝ{L$ƒr¬ci"ü"—µ“aÇ�áw2´^l�úEÒe"‰ià9ô±ùØáF]LdøØ�¶Iøð*´}Âu5/y6¢¶Vz(×;©¿~ ÕÍòcò�¹ee*_‡¤–X©û÷ãíÎâæ“C&C˜*á\1�'?´<ü¸úõp$ú(ô(„=ðû“<�t²a¤ÓÏ:,öµd Œg+3¹ &òl:Ss„r¨º~tý´Ú›qSiÌÄ8E<× Dv«5àúcј-÷è ði“á *pû˜Œ ô žŠjY>FPÎ2BWÂGÒ7_ é&õ3â·�é5fX:‰»¥Cníøñæ6mñOþâÿÞ�æòMûæ› š —f–8•hv˜š0ôÙ�[?OøZÀDÌŒù�3'µ·�ÑYsd2Š~SÊ:zBjn„—®õ’WV‰º±}QI«°X´có mÏ0ô)bM¶a\C½i–dNEŽÍk¹£¥gqÏôOý.ßí Ë="JJU±zT3º‘h)~QðÆ¢ÿ#ÅšßÒþyò=ø4ß= ˆžŽš^05®mKëB¨RâõÈ3ÖùÔßÒ®øcÀÌ0RüÌ=Lo©óØ"vvEaÃ"ØO�6Î)F&I™«í°ÞÍ¥™„ïE%¹å¦õ`ÜàNbƒN�¾Ò¥ëÞJPRÿU�T) bnr‚, ì¯?•„Æ"ôèOH”I3ϯÙ%<Ú¶—˜é»×®�ƒ Áà®ÒÆœ´}¹ ÉÄK„-y›…<ê7Ý0moDcäÝuv7LÂböåÇÍš eo��vA€ bŒYBJ†ü|ñµ²¾)�¨ù3‹�Ç·"ã“�Ç×õ4n�GÆ­INDMþÃКE‚ý°#êL“û¬åÓ&u�_]¥þO¶%¶sËœ|û}Õæ­… }™Ø°Y9–�>ã%�+þ{OJZªÆ@Ó|ãÍ©Rãÿ¾ûÊQ<«ÌëƒöÓ}ñ´ XÞT4&î™;|®êjø5Aqv¾uòp¹Œ©°xÊ„&t�Ì©ÕeÂr‰5@›]Ó\ ·€pœÊ;w¿ÉgEhJ˜SòŠ©Ô” ã¾.ºäUùWpÝÇÛ3V>Á:$kvo•´3šÕY¨Â ,•ª%x@~XÍï8&™kÓ¬Ü{Õš:wé�¥r*ÐúŸ6ÙJÒŽfx�˜ß¡êŸv¥ÐÑVœÙ¥·é².#bŒ7ñ‡Ý-·v‡iƒÖL¬Òn‡ɺ!¡¿7ŒÃ´ÏtpùŠ'û£bà¥w#\/`} ÏpGh’€Ž®©’o\A¥»–x\íäëÞ*lS¶J’n[-:˘7aÀÇ!Êósà%'èÛé®Ñûð‘Þ+Lz\ÛÓ®¶,ú nÎW Bk@žŸMJ/Õæ�<;œd50h…ZÇT½©žPãþâa¤OýmæwXQŽêJ¡”e+CÕ–w÷n³ÿJ]O[ˆ‚üéŒZ3¬H9šãÿÍð¬a}å¶w-V™È…)kßÒ§Ê-8ïs.Ò ‹l7åaáä2CjÕD8Õ(\†ß©…#´tM*Zá7茟!ëTìã ]I‹€Šô\\kf¼6tM„ߺ¥û‰1ÕÁÌÀbé8´à3³AЃï,M‡hò~F¡yMHùª fèq�¨Ý»:µsEË{ÄÍyéáLTQ†ŒO©– éÉ¢BjÇFîCø¬Ñ5Ã̶&‡òÓˆR*¶ä�„s…2eìF&àÞ½àϯxØM)„ô!ˆËN/ –^ á@¿?Ãaeèy­i×Ï6ÿ—ªwn+!„»g¤©}‹S”NÚÌ·é¢}—¹x�Bpã2�³&ç)¹ $°â_è5mé÷ÙþÅÅ’–à;þ¤,ÓÌõ“Ú·^+ªFÍÃÌ¡,§ø“”ü¤…ôÄ4:°�p@R`¹‹÷×úM/gÇȵfÌH ßÎIÃ¥È0œ;±ÐžËl§|2,jœ< )b–vÈÁ±ôÏÅ·a×våÙð†ì„¹(Á¬=(ýmÖnEäõ5>¬].;©Ø¹-e›�H k€Û³Çn€‹¦k^£ó%ä&ø¸ðè2¦–ÒÅÿ¬O’2|Þ¢œÖE9/‘;]/ '³+�„„W>7§æt' ž Úú…+TyõUí In[Ž@†î„6p…#¤2ꇢ"dãb†¿š Ä=Ç©½«¤â‚×Û)��:°Eﯴ–µ'Óî¯)ˆ»ÍÖ(G±ï.(?Ìj¥(êXP9æÔ,ï!fœmÒ"èY´WnïHô J ]}mØ:µI ˆBoÒ¯À�ãhF ØïÙt_}ß ¶WŸþ;«w/ÊÜ÷´YP�>§�O$KŽnÃÉ– C°õæºÃªÉÊO]0D�üAÁ ¦}~ØË]FH—5Å]U³;ÕéF4}…qÞÓ|(bG_§U9?Œ2F'ƒ¾V!„Ýz G­RäløzD†Ø­O0î&ž]Xãú S¯G¢é‹ìZBàªÀ‘’BìT5ÿøÊ ØSþb©ôgû�±l¥ìf)K2-²q›±Å ¹_%�¯xCŸ�Ю B™Zš¢î“ -ñìû€$˜ò„0ð§2Ý€k;9ìjeÒírb… 1î[±©W9ËÄŠ–õU ¤AÞ‚è­Ïî …�16—ì鲸�ðÍÇ”¥õ݇tÉSM.¢šsÐ~-CKLŒ©qÛf»š—U§ a&Q+`!ÿKÀ:)+nÚÞ”†Ã‹Kì¸Ê˜;ÞmÞ¬X‹×sc§‰pX™åõ±ºeT*æ6�LNæœžÔ Ý}õ·Pb# ]’ì¤|ˆƒ¤Wn ýéÝ­ˆGï(‚â�!ªx“'ÎT‚§Éàdsá�šñ1/©y’vÔ9uüiÄ KŸ@Ç„2â‹9ºjl¢N @ÏÆÕì Ìä8  *ƒÅ)¨RóE/»šm¨ ¢'Ñ©˜¨Ð ‚]ÎW°©¿]%á3í^ˆ?þ5÷„ùgœ`ì<z,6PüÂLìùé;££xUyw›¯¿¾i”³ÂLÅ2šoÖ{}‰9Ã=N»ÀæÖ}‰PÛ5×ÏWäѪŒA|zTˆzß”×uôš6ÃÄ©·±T¯èA›ÿy¨´;Fj¬³Bä ô�ïê²ý³ÒZ>ô�›e\³nçãÛÀ�,È‚)8Ír&hfÌ]W@îˆáÇ)I¤S4—›•jëZך©ˆÖ—ñ0O¨Òp†Ó«6j*�4fXJ òÌcÍb6jJ¿{¡çoB·ßõð¿C • NÇ»lÛÝrò…Óm^Æoò�"¢ý�ήšÓ[?ä‰Ò �9}’|å6Eå\"ù}ž8†Ô1‡í  ûÀõç@‚uèº6wézO´•Ó|ÆhäTø.šLO|ñDh¡)ÃÚ£%7Ýêɱƥ} A¯EmlT''¨´êM8]îÌT§¯™ŸàÖ×�f´º�DÅ3{N÷q#Bÿ ™Rø>Ĉ Óî‡g›}÷HK{û2×9…$±±F¶óô…ÙM[8aý6p“ûÛ�an˜Ç?þˆ8ÝP.–ÿîk¸bn’ ³ùüê…`&óPõǿŠS±k9í…‘³¼l÷‘0›+ÆØ÷߸Ëu)*/À'uaE¬`Âo¾ú~I-<š�~í�¾Š ½§¶ãa”ÀQPä³ó¨94{ Çœ°ð8yµÙŽ£ÝW¹ÍÅIuáк4�ËUÿª¹ëÝðP»ÚŠ×Î_þñOå �a+iq•h׬Kx¶% ‡x’g š‡nÆ…ùÔ4&™2�õ¶×�®ñ.Vy9Ž÷Ѣϙ+„1“|ÿ€úS4aÎjMS†¥™,ëY_…XL&þz&!íDøúô[94üÚXú7Žû4º,æ)2è¹�uWqˆ·çÙ ¢M9ÄL]ç2 É†:‹™‹[©UR¸C,¿žH¸aᶪ[Ãs,2«i*æL *óüLh½Q æøMöíjuûð¯î»�Xž5-ï��Âøâ "ŒÊ×pS«cvî}‘¯C®;ÞÛK2�óê6ŸkÕ 1+ˆ®’çðÜ€@>1ø•B¼±ÅX�ÂúWè–9ºÈn]KÆkª–…Êç¾ccXu>9‘Ü,–48t*nœŽ±"ë½|˜ïœ´‹S‡½<¼^~žþ'²QЪ/(fµáA€h~¤Ø»0ƒ�/àØZÿJ×þ[q�‹;«°­�LpÈLò¥;”±ùìªÓ5‘wëL•ü� ~Ɖê€(÷僢[x– ç—I^‘úœCÝÄáÜ£ú¬‡œÈSذÚʾ >˜*óÕYl£ (—Êê¿» Ôr ƒtÌJæû›êÎÎøy’qÞ«¬ŽlM^Ãqh’ëÄÁè:¦ûNkìW}wS¾CÝ xNÝ1³#_´¾ç®7)?£xãkwA3Ù«LPlÆ•*ȇå„dŒ¾_5­Äý?§k­Ád×Å�Õ9'¨rI_ûðìÜ'Æ­ûõ=oy7ž1Âú{k›ß¯IùNúbKž­7Å?ßS‰/,MÑn5çAÕ JzFš�µ6]“¦Ÿ÷}€Q½"#Ò0Ýýi¾�4pE± ÈX8¢!õ\ð"»Ö·Hç¸P^ ÂåC S­©¨ÕG«óîdª´y š]ªì_ ´Âš. `vÙ— Œx|la©1Ù1$ù¥¿XŒÕ[PCYŸæÍE\G€6wMÂM϶½BTuh®üá÷´Ô›•;äOúÜ} OÜ--ñIëÞv\£¬Á.˜‚-–pÊ€/¼¶¬;8z¤„D0À 2çU2ÃG©6ìu¬æ“Ò” êz Ô|†}ȲïÂÀL*dŒâŠ‹ º`Â} (vbÌ#V$R%ˆ·x€iÄn‰½;‰üã]éMãM3îþñ‚�èß³IÌI\éÄy�o©¼_ø8äxðQ8?Ïw¼Ó¬éµs§8ê02psKF"íÝ‘>Ÿ¯,a|rG:ˆs©Âï9!V×î÷ïù^ývq]�9Þ?Ñ6V˜—NÕøoß*ðEp¨ÿ]:Q.ooÔ Î, ¢’ЉX‡cÔŽ$=ÕÎçÊ­WnåMr€[‚ÐV5¤¨Ë/8Ïþõ°pÇþˆ¹÷N6-S†ßìÿÁ�`û`éjŒ8˜8f;œ6$áÆåDܻ뱆û´/âˆ2‹~±ˆ„‹ „ž×3ÞsÉï˜Åj�Æ"å~ÉŸ‘téíDä�¶F·WïéXí¨ÎòSêÊ_žÎ‰”‚Q†3,¤ZëÁ/äg¯|žx‰°#é.šÔN´ñÝìäª Ç*ybc‰QTÎ�@C¯�ÁHÓ›îJT ¢þ„…~cô0Uø£–49x}ksëÕÖvy-èÞ‡çºžÈøcO5àލõ­›„€f�$“@ÆÒ½_ÈØ=�œ£¼÷°¸›×¶È¡ÒÚ®¾¬áWzkŠ=Ð~]@‚OFâÖî—�b ,�تŸ„Xžÿ]  ùfàí8KöÅ8~Œw…îɪZ@_ä’}ìÔÉ[+–R` ÑvCÁV•©àÆgb¶ª› ÆyúQÛ¦e„õ¶{m87œ­ïÈï-mº—Ÿõù¦OeX8”‹êhä5ý‘c´öÉN5nBnv)9¯sãB4¯aL'Žü#M¡/ú+•Ô�›ÊQÿq¶'ízPf{FÊ{€j®Œ{\|H¡cùØpÌ’Ïn|â/%XuÈ®\Þ÷ªÒà QE vLXV8›á-nBE8 çEA>•ÞS!ÿ2•ýz³‰\]™­ß‘EÒ8 Ö§±U#ˆLæB“À+ÙA0íÎ#¥ ØÝµíÓÊùdbð¶\>Ñ9gª«2‰ØÑä„ÊÑ4ó›ÙêÜJœ~WcÉjiÂ8yùU"W•`ëvئ´­•pWŠ�nžÚði\@5¾GÑçK<Ëš­ 6€$ô’Ù¨ÚÝùöJJÐJB”��úéç¾¹<˜9÷%©ÒJëïìˆà¤üŸÁ2+=)+UˆgóºA‹×W‘¤Í8Ñ·ªì´Á[Nàä�¿õUP-,˜_�WÃTÉcÊï7Ôjƒí÷Ù¬^� Ô‰çfIã`ek]~˜eF)0á/sÐØ�#Ï ˜/Ï3\–1dNâm%Š]½5›¨ß.Á'ò4÷QnÀCÕz_‘%…«Eþ ÎsM.à ’Üäë3U’,1 !úA›Ô~^•¥:>Ïè"¼8›�­´vxï.*èI!½‡ªÎ½ºôa—¦›tóq©’Ø®NE¡Õ Í»0ºJ-çâî[žâõ¦Ê8±9c³TÒ—ÐîÚP2«v¾xódž9 L/_@Ì0�¾Ÿðƒã"=þ}vœ,v��ë#�†e�F4Æ*嘸J!]Ñ”øÐ�Z8žÕg­GR†åwç3åò"¥À3yFò¦É­Ç$õ­ó¾È'!,Y‘YSªºyê ÝÙy°ÿ ¿‡iҼŔï©ÚíP¾6‰ð·T¸áøÍ¬_Wb‚:`fQº¸.ô…H9J:?[•ÑÔP¤(bLï.ÿ Ü̦}¦ïƒ|Úgš�|7‚p?¦ I9í±9è¼CÜMÿÛ/+¿C9[æ˜�¸³@ÃD÷>›æ7T)‰vœû'ˆ�Þö™[^‹ó$¬ØdóÛ0—ÈŽ¥×jÖñÑJ÷à›jÛÆð35Ò‵²–?h ÆSsÅŸ?Ð$÷™¼J6p/L»æq¥¯%4…¼.èäkz($ÿÐ`Ôrøª¥Ãú#¸~ÕDB¦7VÙ #©IöCp�s–6ã“ÖÎlGñïäIÙãÛT÷òÕ\Þ¢x™f}ÂóÛ�(´jͰâ<2�vÏ»s@ß1—;ÓÞJ�ç¦ã,r@ÙaýŠcŽË÷ÄbØŠ’÷Ú÷OóXbiD›Ž%®i«�¿<Ë=ñ´ný§ >¶Üz9ó¾Û” Î…^,Êžƒr è­Æ“5ˆKà9xÿÉÁR8šFW”KÑY‡Iãp2b Ù~,cæY‚f°ï¸’;ìE& áæÖ——W·9S×ÀqÎ;â#B;Çnzùêí’¹¼§Ï,a¨XðªÁéß�Ç7�†c*£«ÍïžÛïSS½W€Aç€ñ禛¿\‡Ì �p†–Ç(y®°5¸¿ŽñâëÆþH­²�ŸlS†Û³ù&)_(Ö×ðÖY�O:¢Ç“ œ†[i«>PŽg¬€,#©~Õ.î�o;a]o<¹ÓöðªMÐt—2ÆxžÖ�쌄†BÛq«bÍ’{¶UŽz[ãZ&üýòlEÝÒª•qlAG´ùsýˆýfd˜hç?üM‰ÏpÁ¹ßâ‘«h Œ“ý ’�8€ŠP˜œº‘ô �t&ú+uOæÂ�9 ’b»QÎý6ðrc·Ô®NA“ÃÉ�ˆa‡3Ç6‡TÖò`” ,ÞÏÌ×ká­êÍGÆ›Š\*Æç6”²Ÿo ‚½0P˜%} ]êú!�#&ÞIMC�œ�…cZOz—hõ “ª¨Ð¯1fQu΃b"öÌ�©NÍ> aÙ´ dªqßz `Ë;íc¨múÊ‹õú2yæq/•d¿•Ò0Dð�h.�³ýí¯Æb¶ac%!y°+WëÙuIáYàêFÎqIàV�üÞ õ[¦Ž%ƒw#íšÆ‹Œ�@û�õMÕ›îoéå~P¶©•¶B“<òsº|¨¹¶F%ð—¯ë÷ðjÑ™õêž@huõƒ>maOkO¥ n[:jšKÜ+‘çás`ú#8hLµÉjëÎ!…íøý˯õõ îÀÏø�˜$º½¥C?Õ“ú¿=ÁB>ðåÕ~.Ô‹ÐåT^¢ód1Á<–æãú‘øL£H=�Rì¡"ÉVo¼ó1r Y(‡ �KÚ°N¡§¾Æt®Ïš—äVÑÇZÿ|9¨O¼ëxß"ßâ‹A•ÆÏ.`î4ž°æ/]žh^ 0_ ÆþÅÚñ4Õ�¢ ÀÌô€¯Ê€ÐïVë“á ÆI{lÁÎÏ¡ìÏõÏ^ƒˆ'éÎWȾä½3bÔæìøú¼9i{6SÌÑ‹¸¿vñï™Ï2w’®6mkÏA¯B}PÉ¡÷Š6Ó .,•£p×uÑ�Ö 95Ç´,ž3VÙdýÄX¿5vI6Ð×:F4ý«oWnUBX_û‚ Ë ü¹GÚø eˆ |ó�z™ÿÐöÅatJ¹m—‘Døä Bªˆ¾^5»ªh9Øx$= ‚Wb)zÏzÝKý¶} Í~÷]ÄPÀ×;Ž×(Þç±_ A4üú} ¯¥ª�,xâY*ŒÒâmËœ9~Ùì‹83ìdá|OÉÉp5¼ŒÓÚ ¼ö×'�Ç5� `œ\g™Ø3‚O{—YÉMд€)f¯Æ$¡–9ñŽoÈtª2éFæ‘ÛSð6|²ÑÉûäE ‡Çä o‹¸Ó2AW*kéeý&¿6 òÿCÂ-FuA¸¢Ä‘+=¼Øq„*Õ™{ãmÝk™6Évë—çn*°öÿòwl=!W †¹ øF‚Üg6Õ&¢³–ªöݪ¹¨¬ nx#Wïr±f<ÝF¾êÌ)Bz×T�Ý~b¯�ý_žž8‘+ã+~šôvßÌN@úT�g–Š ºoH�Ê#„ŠªŸè¯äd…ÀnŸ†:÷P=Úâ«XèäÕ'ÙlÁr©02ª¥ã—7ndHã—eƒÌ¦4Gs�P8b�Á!�¸ã}g¹»Ô‹m1œ`¶Šn‡¯ q§ˆŽÊ gk�ê¨a¸u0iC8–á‰î棗âb– å  ã6ÊwX[­6b:ÓPÚÏRªH4ÚR‡‘–·Ãn”7ªôh³¦®v³­Cî¼’º! ÖwÚkËyØ,Úq‘Ç‹©Ã©ƒ*/‘ô³SµJ©8ìí,«ìÏ 8µø…idÂÂÇꤛä9šÉ“ÌÔĄ̟ FlZÁ}!dŒ¶ÒJ‚¾1`½¨%@˜ÃÂß“¹ZUýxM=|Áaâ!½œ¼‹O Ó‰æñì`Ô"ÜXllƒÍ’}7½h¸Sºih¤Â:·±¯þ˜SN½ësÛŠÒ0EQeôÕ’/ZXQ›aÀKÂÍm�ROñ¦Ø¯ÀînÔȼUmÝòˆ•+Xª7tP 4OU&ðŽèoŒ&âÍM´zéWò%+}Q¦”¯˜i¯Š‘~˜šš%¢ßÿ—/dÙ vâ,.ñº„ô{Û”=ZõâA+Ôm¢aú8w Yt˪ËwÂhöaíïú°~û­í˜âD”±?XX3�GÑ2ö,éþÔÅ'g{‰à1Cƒ½¡|á)ndik‚Ëø¹·O”6ô˜`nY?�¼çV$ÔÃ*Øýz-û}„ŠàË«z'ƒs©ys·vw¼XŒ¶Ê3þcZFP·Ö+T}Ú~Â-]9¿_¬ ܃”)éÆÇ½„ÜMdrWiªd³Sôh—ì¥n8›…ÞñÃ;\òO9#¡ Ô< °÷ZRe.Gã~â®�c·‘˜îì@H¶D˜îY`îô¯øXù˜M9¾ÎKTÝ~¸ ëÆ@x[ºõrYºk˜’é]ë�ƒRý–ø[Œo:™;¿‚KD›m™1F à&2qÜZ-¶·*�Š5¿‚P¬^±ô´×Ë6wMûì´!7K¾È_.Õ­©ºM!§ü›�daòBËð”–FßS[P³,Ñ£d›_ˆ*Ã89aË«v.fc»`8•®Vœ: %Å6n¸-ƒ)ãI�î°ÒéY“éþÄ¿´!³v:<›ÑßáíɘëLÍÒ­R�hë9àÕô¶ gãUôμæÓ_û�xs÷�ÁùXÎbY©�ÒÃÒúV‰‰ÒA]6gÈ-O ~é1Ö9­q{F~a¥K-]ìmÁÆä�ó°e¿Œ¶»o=÷kâÓ‰‘#gµ˜3éøÝYb§º¿È­'/ñwˆ×·Û“XÝ6Tµj®Qõ®0Z Ââ¡ÍDÁ;¶à�6qÖ_µwù…¡÷˜#b˜‹Ùâ„q]ÔŠ<矄i½ÏPö‡V1Ç„&[så瘦à\ æ¿(ê Iªc‡£dûdBkE6™‡CaG D�ÄÎÞÿ"|#@êŽêñÑl|»åϰˆj[²e³±HƺYŠLLFUÌéðímÉŠ¥o[âÂ2÷rsšDEŠeÉFnGåÞ&‘=¤hÃ^»�7¢ôj-8”� ý0×8óX‹x©…ôÏ_ƒwò¹·|ÏgèÍd�ƒS Ê™i�DŽ¡HÃÒ¡É[De4@v&‰ ï‚Ö9/М¦m|)À 3¦® ߺaZ3@ŠwR ¼|»ë|ö÷Ǹ\°±×èï¨ú,¼e¬±^É¥Q"7†ĆÈgŽCÅØ’Â?žà•dÅKOI­�¸d¥®pøÉüֽԪ—¼dx›º�Ü>ûG“áƒú«Æ´¤y¹!÷Ñ,C¾wh#DD˜VÚt•H~_¤1]ôeI€ïÀؾó ‰ƒE`„å™DEÇÿ‹rìÌFy 'eWï(8Þ²iÝ‘&B{ ¤êaxaxõÇ¥\%–�(ãövDuðÊî©wy3á ë%Ÿ­V¾V‘IÇ�w^ú®üfŽ~žP–æú4Î"Ýù²UÁƒzà­�‘\f±2#i\ç+F ¨HBãH# )­·ï™G`ÝÜ)ÈÑe0ãW¬h¬¿4Túf}÷˜Ë³´ö¥Þ€õ·x€ŒVÀ‡™Ä-™"t Y†˜P©šúöÚÍí‹æÝŒ·,’¥LñÙ¯O&Û×ðnÂ"F�éËqqî¨Ë%Xä¹ÏM¼¤¤fþ“S]ƒ}qííøô(‚ÆÈw<Š{=™jݵsú�ñ5Dl„YB"ö‰¥õ&Wü_$…¶jë9cöþqÿõå™GÞ‘ª5gèõûžÃ-rˆ*¼‚+ðË|®çTy”߈/lj*¨EÑÁ’¸iS©,g“º/r¤(cªê=ª™,P{Û5ú‘’§U°Z¡Äޤ’‡ ÓPò*°»ÑFü*T'¨Ûò3öN±¹u½øR¼=Ò1dIëB>m¥3ó$C;1Ç«¨'Œ+ã“�=.¤Qú¨³¤[`_´­_sGþa³¢VsjE1š3¡w×0²ó…Èhø3…Ûâ�zAâIíDñ1À ßSî¢ð±TÈš…� KÛ�ØÒ³1*ßqSË�!öù>+UeXÝ™ù1“H10’æÁOÞóŒH¦gTnl¸%fŵòg˜§à› ÒÝ/qf`µ³ðU\ŒœªÃ>[ô웿íh\áïïžÌÉ÷=;‡"z¹y.Ãæ%“ôñŸDžÈ&µ#AÒ#HîŠÕw&ø sZÚ§Û)¯5s°¾’‹¬ÕîÌa9 (Æ’µ»«ï€>ŽUá“ÿ?‹¶Áù¦ÒßOyq;ÔjDz`ÕHíl ¦:ÏWl'ÇÿÔ8õ‘-À»¶M”ÏÕ:\,໣P–9:G¿ßÁbÚnÅeŸ(É&0T¢óœÆ¹ÉþìÕUr2›ZŸ[468J4Õqx4MÇgÇ#NG3˜a ¯9ª«H"úyïæçhD!I‚—ɾàb 6Wó;o«¼·67vå¶•Éó häͽ8Œ[Ž'r*£g®•ÚX²þ@ÎŽˆ¼å&ÊC«.x*þ �2s‡cË=õ.‘òd¿4­!øÀTÚ ééJ ÀT%ù •´C)"Nªïhr§­Ó?ƒ �i:zÉŸ‘-­¢�›e.ƒÃ*ÃÂWÉ:“[ªå…Ü:Ï@<]KŒ�ê`FqçÂØ³ s¯Œ£ÑDVx´a·l¦)×ÚUv%*5ëÚ<^ki“oCß㿵¡n íK�ß+Éz Ñ9J ËN#³åü­}{ëï'ÈU2/cî«A‡¯‰pÇ`¯è¬jaËuÀ97ĉ0b (Ä!N¹TÌØPy�]»”EB,qª¯þî%¢$e/FL«› æ�èû-‚óqŸtA÷òsœv).Õëܘ۷ùzk¯„0f!BÁ_Ð#q)�ZTÀ_,—ŸßÞ;tRqJWB; àßÑœS–*hÿåâÆþÕ�áóCäêgK˜s�ìÉ{㥺lüL¿VÀ džØ[ø3Îÿ÷põ: è§U üeH%»@tµ¶Ì.«ÖšÏˆWÑzÓ×øBïÖ–#T¯EŸYá a@v6çÎ6z¿*À‹Ö�ÀH BðèÄ•òÙÝæ©]‰¼bÖJÏÝ“¹œ×|_ò!šôˆ‰f´ú]Òû¥Ú\¥_- ‰†'8±~¾²oÉŽ áèÒú¡k¿Ñµ:¨Úè�íž–!D˜"�òeAqƒ 2žP¼Æý–ܾ8–³¤dÇ’a5ù _Íx“+¸W^ç úu"¸ÏãéšC‹‰úßåc\pF.)å>|ëïD$7„‹F4à�o6ïÔSí¤*khe7 Tj}8RHóQßð¾@€R •¤x�ڹĺ+!‘ö�µç°¶œ$®áÏ=ć†p›PJKc=&ªX 2»‚hÝÎu#ªéË•Û;|ŸkòHNyìä�Æid¸8I ‹_ÕŒëoÙø¹°ýÈÛ�ÔΨR¼cÁY—PëS€ëra3öÞÝŸ\{³ÀmÛ01õN»E×ÓrmÕ�DY'r× „È ¢Bþ»g[i9.¨4ÖÇåÜd—%0;eE¬FA~geýè¨ zÏ?§e-'?Px>hgbšB+˜Vcb[ZÛtkkÏÛúÐ¥4.{ûUû×n”ñi5d˜ä\̼°uhŸ|X\Ã;YjA†èÞl-þè_®z™'ø¾C2ãÀ[6À„q¬.¿¦Å—…-OúL€éå.É<%ØpRxF/¸°o»a?>ys»Õ4@×¢ÕͤOhNð†uí Jm6]�1—´VuC&µÐ’²žû‡¥SÖêãy¤‰˜EAÓ— sæ<ÌÇEw]±é¶ðwÆm>ûzÁ”d2ù½°£B¿í1=E\õ!¨‚¨ÙN¡z„^Ó@¬ÌÇûT¥Þi9÷ è|› òÓ")#Ë#z 1©ŸªÞ yžÅ¡R€hOõtŸ«ó迬"ÝWîáë]wü¸àQ&v;××IŸ4Ž1¿âó¦"·MB€:*3õñŸŽJÈ<+“Rñ8Óvë¤Þ–løv-êyiéc­¶ÿë_‚W€Š�L”eîGP¨Z3t¯O«Ã“1†’­î•›�ŧ¡�0³ v`fOz„DÀúCO™|Ÿ+ÄâÅò= ±…^ÎØV4ªãXÌçiv�o ¦~�Ø�>åœÜÓÜJ¥AA¾ƒS¡iVø†R�x Näª�ÆÎ”3Î|èSDEQo¦¬îÃ�…¾n[·¯ïòãÎ4Éá ¡Ù\ó G€²v ve@Ž¡àq燤‚2J±4à4»Ýhgöá)?›µ.[¾ºîJÚ6E¶ñŒn# ™ôùdÉbµkŽèPáÚ¦ÌPß–eWá2P.n<›Ñ¥ÌOOðO„‹Ÿ£¿Z�^ÔÙµŠ¸+Äæ§gD“)zg(œÓ^Nïã8¢%{ŸünÍ2cÙÈ Tµ £'<ŒGyô=ºô@áĪO]�°2€ˆX ;jhv~"ËFÌ‚Ñ,›±ÓsQÙ9ÍJ奬~ƒÂ¸v+[hWÅ{3MÝÖŒÅÐô¬!}ÝÞº6"<§m2éÛa Vʹ‰ìŒ#Å"ù¬­™A-_ß[Éu˜—Lóèe vÕÖ–©¨V*%â juBÎ êpgVŒÆÌ�&½²³…|‹,Q‹•°:xưÌ�N}¨²ñDHiˆì>\tV®›Rïï²ß¨x „F$Q<ì»ÚZ”Øv‡µÝ)>5MJÐ&�+~ã,iÝ?ÿZ¨ŠéÙ#È8L—I ÚΤ$ÜÚm Mxc3óeg º˜Iæ§F‹a†ØW…Re¨[䦙 õ )¡ý@™mª<Ï|%e�6Dz?µYzîõ/uòšì·-¦îaànpïäζò<&-Mh—û:¡y3 ‘Òþ„¡¶Ø-ÇL9N´Û·¾ïÃØ�Kq‹7wç Q†ÊÚ§üÆ1«?*àÜwÁB g”¸ž±;y¯1ì‚õ#LJÃË´ðnIš£�„¢(­ãÇAÊD6ç5´ÐY¹™½³„HØu ™8Ô•«aU`žÑ@ê“:‚ ,übcò¸|*~žp¾ãÑ �I†åY ^u+ø�Xð(•-çÒpH9IŸ^7ñâéØhýÔM¨b�q…p1A»,hæÉR­<2Ò^÷ãŒò'·BþíUsuãa¬ª�¸‚œ;Ñ)~‡¢ÏæÄ䊶 ÄሜN çQ½˜É—ž@çûˆ€^�™­�l0Ëŵ*±ýƒªk*Îæ•ÐX&sj‰Í~Q݇ˆéµ7ªÞûDò·ÜŽcJÂ~Ù¬Îp*vÂsý—»Ëê^$NÂjO*X¿¤&¢ôõº·ÿ9ÈPpS®zõêeúÆà!É�F½ÕEÓW„\§(¹h¾(9"e²=Ptxß'|×ý¢°ïÞy�7M‹†æ‚bq‰—’z5†dY9ÕqþT‹²Ì¶¨ üTfד/ñ{¾_¯½ À(ÓƒTûÖ¬Ó ô2‰n×Ïã6~Ͻ[z371«×mÒ†Õ4ÅCÔ’©ðªGØ Eé¸NÅ$àjïÖ¸á�°$ì; r0úɲì@¬ÉÞî‰wP?a l˜ó‘á#§'WˆrZB„­„%‹×��üûÝRNÝk1ú"øÅzxˡʷˆ•„ÀŒMŸIÅhÝ�B¡ªÊ_ËÝ£½Z¶À’‚^WáOÉ JűPò&–•3ßARâ§`5*ý‚)¸5çñ¶õ ,Ñ¿·S”¡„\ÇÊ0’Ö/ŠþÑ% ½©ùׂ:µÌ_#<ççt~¨[Up73ò“΃Qcü¼ÓáZ“Ÿ9°Œ -HîâfÝP®­r‰·?¨³¯x¶|<å¨GòU½ƒâujJÞüÚ±…¾êçÂn,RS3S ){Vt¯QÌ—ü„n™Š…”€¥ô1«¶jJ}wý˜'¯[0/ÓðÓ…�˜u¥Ê¬îN|¶¼­÷Å,µz­‡½cì·í„,Ö+ç+0©U�T¨Tl»-8Í:´fv4œ‰)ÌQ-Zz9F}–¨’HQÜþß’zî�Vœ8ª.h´£vú§)Œ4¸Aø&)JN˜š_¼KL4Ä©Ñ÷”À¡Ç«Cü{�”Å8'h¬7�¿xxQ.rUuJ ž.=žñY!è_É�~&ë¿Ö8´E\WI™¶G4àäÏÇ”÷ŸžÑ ¯[�“.§˜Ãafÿ µe¹ý·™7ÿ4!Ë)òãVó’ýh@ÜJOÆ…uÛ&莭6Á÷ˆüæ­Ú¼=Cy•°´™`•~TG1RƒÌæû£È"0²� ¼0ÖÞÉ�˱ ô"–AWfcÎŒJ*ÿâß¶SOi¸S8l¹…ËiÓ—§Žr”LUi·=€’ØU*4D£è™}ÕæÓ€>hÚéˆ~2R”¸­¿5bí(«¿1WŽ]š@hÖWÏMÎ q‹)ˆÞŒq–ö0â—Æ¾Qÿ·ç� <�q=ļDO¾¥KCàé¹ßlø,‘ï~ûv«£”ª•9̹VS"j6¢lIÄLÔy­&=g»!{˜ªâ?:âi·ÌJš¤²ð¹Qo°½!2ÕV1Ç2HñŒÇ vÊ’EÒ>™S!©On¬Ûàwhm›säŠ >ì\a QÇ2D´“6J_|p¹ŽSFeR2SêWñÜ–ff¢V ÅÐ@dJ¤zã¥ö‡¹ÇÇú†#¼k�¿%ÏV-™ß¥”>º‰m3Ê«A@9ÿ€j¯ÅzÃ"à¹RnEÿøÊ y[bs¬x¢‹+¼5ü¿¨”V¾Ùèë ´'âô‹?å<”heßøÙ¼xÓs©Nk±}�Üáµ|#P`oZ4íeT×å€)¾,s^Jø£Ò¦›c9ÅÁá¡d»+0ïçÝÁkì:½tÆñÏXÂŒ°aô|O&߉Ty¹³dåΪÚóÄŸ³or%ž_”¶”õí\F@&rK�¥Ùnp?�!+ܱ¶þkV59aŽ©›mKšû\ÚDð­�í=Ö©'XÀ·e£@´3)ðE$àtçy¶G -hoöyò£þ¥Ê’E�Ÿ`¯KÜÛ…}¿-ÏX÷ZÖt�Á«œ9ҽʊ¿tÇrÏüúõ–7ïÜQ$mYQÌûªËÍÿŽP"£Š#ay²EÜ•Ð5ö�Ú9I8¡<1ö©�0°Üü㈳Àw17@§2¸èÄv*`�Y]à“Îx®kšö¤"0ê,aíà aØè ExtÈ‚u,Ôq<õÅŠè»!Ê`—®º=3VK’�Hð9ÚÊ>Ÿ,1Ò‘Þ5Âæ‡&rŒ¥]“@Kø%6íu ª¸gnY3kº|ßKã8‰ÍSÑ… j—¥ÕÈd@˜ñ�6a‚zÿ ¾fœù3?t'-,aƒ"aÎRër £u·Qk'À|™8¢YC‡a÷8i¦un˜"§ù<”4r]^r”¤Uðîêï(X?×+ÝJxÚ §þ†4E‘Ð&(廒 ÄÖú{ædÔʪ1,‘U\YªŽ¬Y&(¹X²%Qò¬óò¤[„"ëŒoñcÂ0d1w5g¤'!Sc¢ Q‘Š5ÙãŸëb˜XÇÆ#¬J�,U·–š†TÏÐM²h@Â…5Šéñf3sV-N4Ê}"¨Pk2ç $”šo9õ±r”nžzgí´ÝexÎü‡°x"¦¸q›�8gŠ£²¸©[¶¦â<ö  ÐA–)gâÞz¨Òs?*âǰò„>Ç;«É-Ç! ú@'K3Z;~Ӄνa£Y];b�Æ!J`îE åE1BjX‘ÙÝõa¶¶f"�ûP¾[ÂŒ:ºãcµ4ßEŸÙÖ÷�òÉIPá.ï|!‰O_» 1GKÚ·�ùŸ¶P̪jÒ£VeR‘|æŠü«}£x’”nôâ°(œöëq»ì!þCT‰Ð€£ I)Ù¼í´_žÚ•" ¶Ö’3ðÎùvzã Löê^ê¦Ô‹ïñŸ.É\UúŸÀ&ˆ4ýจs~Ý=è".êŽÔÖ ˆ£DG) ÝÎõçHAàR¾ÎÍŠáß8iO¶¥=ã°''˜ Q*˜ã‡@œ”^mì`»Et®KÈhîÎÍ+²kíHI`kÓÌõoФ‡ßxÙÊâ§ùö IÁ'§v)Ý^©®2;i_m¥.q/Éõ•Ú» ¹yo"Ó°Øîãáq¯+ÕZ7R첃+9ä¶Úõ@�#¬ áëöÄ}ƨ¸™LAµâË«nY -K"�ĵåÿ×è³ËdŽu~~ó^Ë42š!ß!™Ð„]eùÕ{û桨)­6�sIþsË%£(8R®†8s&Ñb—ì&îô1¼Éé• Žjøè6‰ÓX;çàßfßÂ&”é`~ß� ÖTG¨ÙبYP$9¡ôŒr…üª@kÿz£�¦´l¸™èІÊÞyó f5Û[L'cáüã<~¤!]t%Üß­ºÂICÇÜ%»¶[RÔ"DÈ»Ä!Ÿ/–Âg\Õð­ ,àÝɽIH†í;š ­ëÔ˜»@`¸Œÿ°ÊKZ¬�‰¢,Ê/·´ºÁ”î¢@°d�v²®G>w–»­y"Ì.ª_pËëLœê<Æ¥à¹C§¾^§•¯à«&Û¢“¨s¨ÛñZ9üDìƒ?âiØÝ°QÜK‰NfGF¿ŒÞ ²‚ï¾ï�~Dãú[½rÔn„‚³sÔ{ÓôDæ\Õ¶<›Äú¤)È�k¥Zù[-¯GZ÷«ÔÑ+´YŽzõAAÑ� 6R �[2¡´SRkØ|E÷ÊצÜÏÞdböVKÎëø›[8ñx.ÞN8Ùhÿôû*Xä€d¶~™äµKq žáÍIÉ,nI˜òó 4sV >·Í¬Ës÷ ”�Qó»Æ6 ±eÞ†ˆ.¼ cQ¿ŸJ¨ºkÎ/†|²Dƒ`¶à½2Þ§ ;è7XZ÷‡9wUŠB’R¨í:üÞÀûFòÄ Ûs»µiñïæ˜Ëîj�¡ú²•Ymmîåžl‚kÕŠr8µôwŠ ŽÞ~cYÀÈ"ñG9w°¸É¡^é(ÜÞ›ÏÜ‹5“\XƳ1ÅTš6R"p$@Å's $AtàÔñü•¬î»n»-éÇ�Ðó¼MêÀ€³5VyâUž‘î }#f„är2¼¦ )FÓ0·Æ›Ãìe†ªˆb;Æjù¨ |š Ú¡ÊrC‘Ò3¨ªððJÐóF"Xæ4�¸'³Zý=ne1l;¯SÂgÉÈ d.aS"çèø‡>¶Ø¹ 6xPÍj<ÛTd»Sñ¾°#u$¼={ãè}vÀ¹ÁcO9huǬÏoÿ¯ð ©,�¾è‹2Xœ Þ,·:«�• Ôaœz(¼RÞƒuÄï|¤Aþ«.ÞKpû˜Máñú—Œ¬ˆ/ÔÅà» Y6š;Ñ>aÍpaʲÙ`Oh¼e›^kc] è:ýÐÝã÷€å\»¿ËòâHÄþ-ÝÚaý)ÝW‰Ðû‹Ö˜ôP%WuwܪëlOYâ$§Ù!ÉJ_òì%«;lŠø bú`cüñ€ÉíNš_éô„åò*t¾¬'Vù[¥î¤Ûfé[Y2K'�ÞÏpI¥gn‰„QÒH]Ìë“Óo"’¹SøšÌÐ}À_È£Tï1HµÂª€á,éS“y›MÉuâ’Í7:U™JØZªSGhÇœX0ÆvWõÓRrÓÏ,)KV �j ¢Lc¾ òë¡#¹©�í�ˆü•O‘÷‘ˆ¦I´*ÜÒj>Nà4¦‰˜L}PS;:âÇ eÉåü[Mfð¢Àólã#íƒD÷]é *“I7 H3U³ƒé˜� 2aFcvMý E¸Ê#/È d:ªRõímue…Ú]  ‰"Ölÿ3hŸ;Á…ñí»ì.5ƒ­ÈD–ý©ðOW•êH û›½ef »�!=­{%´Ä㎓ø‚�˺Å1ËMGÙ{š¬4¾’üw =X«ÀL©·›~K¼iMI¾n�QL¨»¦ ¿R£cþòŠxþ4»OR2X\Ý9E„Çåw.I„²b£ÅXÇÿÂâïãs;áíwÆâ¦$Änô>‚g~tñÏñ€}§%çö+‡yåû×4I>ß ÝŠÚ%9ïáZû�Äh`þþY<–[O‹­y™’ÂhÅõh˜›ƒü „d0xï�XÔÌæ9SÛ&„dH#nÜp·È%ÝÜ¥ydW: p,2±=k^º¬dì6*\Õ’Y§ehÚ ç†AH)t ¿r1�m4Aÿûy@|§!7>š£üsJ-§ M�„°Òãyú¾Àrº‰[MçpVÜÖšò€tðcþp‡(ÅhÞ •Í“†Íf�Yó3³x4àÁWåw̲Ü×Üðó¹­¨ Ö¾ø{G‹I€šÈòëÇí#¼Ô&CÑÓzÿkbœ<\+¸½†‚"%Eÿö³ŒúÒ ¦u� $$1?'¾àÜ£„ÏNmy®›OÆ;L¦úN§‘íoôjPË[€ˆ'Ï8Šázæ¾Þ£è�#£SM§Á;ä$} +1v´+ý¡?öépQ¸F`ƒôð¸|¢Ფé�„»ôqÆSHÆØkÖ/Ž_¸a‹ ÞhŒáIDIèÛö7ìáÔ4[-´µõKƒPÖøÄÎX{e#nØKëzß¦Ø %xèñC  ˆ´òÕ/!k90¦ô÷Õï›ÕT ? Sý 6ž÷Ñz(ۮݥÞ>=á �à‰P|J·ûØI´,ß ¥BÙtIøÞmj/C(¥<ãºUg—¥' wYb9dضZ¢  ú#mÏZ8éèøöŽ#ÍéÞAõ;s›x—ßSÎ vû¤^Fê>½�F׺殠•3Ï%ÅJÞ—Z¾‹P™´Ö³šÄÍzNïQ€Í·‹óþÀèW§H1”#�).¼³hJDÎW­|k$Æ{ì±r~ Õ²lžœ<Ôà�袭V¬ нêX�xÕO"ÒŽÅüUh:�u‘ZQ�Ng»Øˆë¿°£1L°‹:FN1æ�¬úÜïÖð†‡6L¯­ÞJÙÓ$ô^S^9 Ñ9ˆžþÁ&¿'ýª¨ç¶ð ,î,ÉÆ¿Û"{'åv[æó¦¯Ôq~‘ÛGÜ @}x’ÿ$qÈU÷ȲFc×é¥a—kúŠ�(°P_>üÐÜ7å@[\Œº9.œù-WÆØG²yòèèÒcˆš ´ÅkŠÚ…R©,”:Œ3Z‹lVÓ6F±æ-ü1ÒË[šÕôûæu[cR¹hM $ó«ò£©AÎ`?ÒÈ=÷ot2 @¶nÔ•.Â{ I$’µ×65B*-Çîã±f×(Õ«#S@nf)´ ;E(´”ÎùV�iwä™dèŽî ™Sù›§‰0~eûxÞÞ,ñé‰(©‚½dG&kR‘Ëýîòy©œ�Ñaw§‹¸*½çP•Ï#¹ˆøfìBÌ~‹Ú®ze«š­z´·ZåÌWÝFÂÔâý¦»Û}A�RЯŠVünÙ®­#{(x„}ŠrkgöKõèŽáõi¼.Qê$˜4ϰÏkÖ%¬þ¼ÞcímÛdüšªÙ 1 Mÿxê-$„™âbÙP€Y,5G_í?cµâ\@¸'CÈN œ'[´‹ßâ%-ä·ôù½×¨šc¯‘Ðo�d_О!žÔÖ´ËôÈ5™×É$§^�òcØ]´�¬[}ý#1ã©Ù‡è4ž/7‚PÅžŠ@tA%®‹b›µÛSìѳT"s.$óÉã,P>¿ÌÂõQÍ$”ù~ƒNZÙLW3ïMºû±Q嫚†Õ� #F�:Éår�xcI7ukÆðÅ€]È™³Ý~â ‰ b^ßÛƒ¹,8@Âß�ì·\K›oשƒÕ/c 2àã€8mÙ.-4;‹®HÜ]ÍV¾èÛ‘1ÍdLz-94¨£WYrvüÿB;Kµ©HÎ6X4µ§¾ÎqŽËs±èœáŠž»³©º%+i©U5ÿÏ .¡9¤#VeÅš`-`X޶å¢çM-„ÑêÞlM8#þ9ó÷ʯ¢7Ás»¥ìd�)_ÙBW0óó‡³1Žäòq%9(²º¼7g„Ë–ÝD‹Äš5�÷a·¿°ÿPµ®górcÑoÝ ˆ·Dû<iQ´MÁqžÂ”Há7Ðâfké?ëÂm+ù²7Q6õ½rœ]v.˼º�Ýý~ÈwÇ9“¨ÊŒÅÏR d¸:•~A{Ð “ðÙ¹:‚Uy%WÅ_ðáƒHǘýP”àIC'ßkaÍ�šSBg©•üônÝ©®ÕÀ¼búýÕéN1>æŒp'ØåÉa' Âp˜ “fÓ7•¾HSúÌøb'ñ6ªÚkP�qê�À”wy$¶àÏÓ ´¯úèr]°eCsëÈH#„$èHä6-öî‚�J \ô¬À2ý¦“ÒÇ@â¤bП"ÏÀ“–VüR{ÁýntÞ¡¡R]Û6¥ë0þÓg€ ©{_´B˜½ ,¿›¹b`öœ{%º²ï%5Ë�lÔîÛ ÿn#ã–º ŸDþ“VAæ&kœ…Z›<�aã�fw#*hˆrXLPS|±+¢ni¹_˜ƒcƒKKÍH)(@w7n]®×@ÿo¢ûá×0â°Í3è—PÛ‡o_®žŠ¸ë¦» `΢�iÝɰ�ßã1Ý4§¢ˆ÷"俯,®³žÄ¾>Òcþ âº×00FÅ ¦¦Íð'æ|2ôÞ‚;s:yB˵ko6·�"B{ÿYñ(TîkD K:÷ç1¿ŒöˆÝ‚í ;s¢¦ Á‡øy7ãß9¸�S¶JâW²Ô¢š'£EnÞQ]!²D% ¤‚zhÕni°ª—KxöxSOZñ­EBʼn¾HÿØ9¥KÎ"�êðàÀ=š»…ˆ1¬¤écÉvifG`Eö™¡¸ :©Þ>U°Å�ù–Ey¦žAäGw¸*Í4Ü9º O{#G~Í5ìRÇ¢†¯ÌËÅÄv·˜ö9 ˜g�:µLÁì¢*£¦àÛ�'sšx=èûëö·4kÜt;yÚjà€iç0jäÇQ�Hò&,ð€‡œWBwyÜ�hìwã ¾/SÙ8ds£Íc¼’±“ö0%þ›fxm£ÿÚ¸°4×7ÌKL2Q—LE§ãU3r4¤ÚJÖS¤j7×èD[ª“ò›y„¾çEjòtY!䋎Õð‹Laß.ª4ïPÖNs^`9°[ÂCèÀ¶� /{Ž\9³0N£•ö�{ $P¯œÖÄæZÊ ?Á£­I–ÿ‹ý©·½~±™V  îÄ w¸fgl׳EUñ”=ç‰) yè”í W£þk›/Q�f{åß*¢[®=GÄÑÂeqß`w.ÆS�ÆÆgàC1Š�,“èG¾­�'MÅåuþôµ[³h¸˜Ëb‚Êr¡·âÉÏjwùk�êaÑ`WS;èäOÁ—çƒúÿ%$“ «¢¤Ü‘h¾ž¼vQç€3A€*$QôT:Ø�ŹD�÷‰‚Ç=#¼™¿ÉƒÔžWÓÛºr6*ÄQꪯ"ù¡”¶/·;½¾�¡][¹Ù5à€õ[¸;§h-ÛoÐXª³ôˆ)L;r )ìtc¾�Û�³¨‡{< ÙäöB( xrˆÌŒy£®Š�šúêX²Á@‘æÐÞÑ«ÃL.âÖË#t„]7Ïlï?>0(Êðm×ó}\¡‡hmwÑ~ŒŒY�m—œmßhq`DÿþÅôvÂçžÚ=\¾ksäëa%øÄw,'°i»‡ê¢e—¿„ :bP ZëQ²´œgÆ;i@¼1[”÷Ä—R˜¬¯ª��Qã<¤ïJñÉ'Ç·`„èf›+øí=OjÀŽ ~´SrÁnüh\i_>¹aÐGF [!?ÿ”Õt qã€-ŽÍ|l°${ôJyc’‚}‰6¯ÞÍpäñŒÓ=‚/ÛÏy×6x:4«áú\n Äο“›Öï{ŽÙà×^¢q)}ü‡wù®åYÜ!»B®3)áðÄ{·N�”�ÓíRê®ë1ëøWä=,„ ƒ£Ö{ñäýçaµ7Šk§å—é´±ù)†ù b8³Rà$F$À:Ÿ*Å^¿�ïÏù. ˜aù9|ér!‘,ó×ð„ðÖŠÿnÛÿGà³[^é¨-ŠÓᆯùJ¼tEÚÜ‚ð>Èä·^å­†2·þ^ö¾ewÉÁšø’S•oäHáɯÂk8ëPXw1l] RYîu¹‹šP–W ­¬ë}¹cÁkÓDô9¼|ag;)�¤þ3�mbš3ÓD¿ .A‹Æš]ç‘»}¦‘„Š]Wàb9S?EstéÆZ þm_˜{Ýö\¡W©W·“©R6J~ÿ·[p}>î>5G>´l„Ü7<ô š¤~c-¡Džbg|É.N´–áÞÌ`,ʺ·{œCá&�–T”úûj~ŽÅßþ¤ÿv·7"ÎõO`ùFôe&½Vâ0¡…—;sº�Aä÷ò‹ö}šú#.ÊŒõ(�ß Ì8 d^ɯ†¾WS£yp"áÌ[b›ã/v·Ñ`?NrøD z+Wúì«`é¯`›Ÿ±&÷ØjGm^¡¨¡E‹À4hýä Ç+QžøÜ�T:L5® nÀ!¤94a0Ò4UõŸ4–X;`ìÛûÈ£ä>þ´IŠ+¥ó]Žfk}�ˆém±)f†¦P*äÝǯ Â!˜¼2Ä$q+_êŠ ˜ù4Ô™ørÑbLï»=ž¯Kê@/¼r«0e¦dCmå^Tv"÷«°qæŽÇBuHGi¦8Á&â€ûH÷&íÓžäñ=¸ýý|D[õ?÷EÉKèYX*ƒ¡«2ñâadm©í¬SÁÊE]ÎÕû,€DjxéŠMÀ^ó†� ïü65P<Œ®µÆ8‘þW^\¥ ®ˆÇT] ˜ë aù½gÆwpR¯¢E¸¤fEðÉ™Y7Æ¢{\JÎÙÿ0±xO×<‘pRaQeÉ’sKêO:Z–ïeÚ—Iž{,æ +tü¬¨OÃ}fÕoK1ŠãOÒI@f°«rà‡#Н…ï×/ï’ZÿĬµ®ÇÙá¤$œµ,¤îït*ÒI%¡Å,:p«Ç·I}8XÉìòžXñ×±e|ñ´fBܹ²ïòŠß€Ão¸–í\?gH5o…†ïøL¼M�dMÆ´xÒÿµ+Ç5›«¶Î£ta önr)ihÂSqž1éÞu—¦SG„Hœ:0 ˜Âº™sˆÅ >‚{â„»Í7d©´–“±zpú¨5¬ÉEI%Ðx–^Sù8A=qyÒW'RyJø°!:äòJuHÇ“ÕR�M‹Ò¬k ýè¦þ–¾ð�ÚÍmÒ \•mðü€7…r ‡>Cn#£÷×óž÷fÓ,1\b5Gðx}¶d ±ûIòjî»}¨=Q³ngD´PðK[cįТ Y0ˆpÄÚÅσ¾–=¼¨;œG#éVM¢‚Nûδ—l¯?Ã,?ÜÐüKƒÛ9�–tUv£±ÚãÔÓ.‰Ú i«ùÒó¥I¶ü†y@‰÷OfB²b>ÿ=5ÜG%\·ü Ì åì#ƒ)&oÅQAB‡W¹ ª<{@êLáë@ü¡µ4ãÑ]óÈ=¡³bÖ§!â®Dx•ZíÀbR¸S±)W,V¾zqëõõ#Î%¤ #1“hõ`©";È1róS°êè|ŒWn¥ôÓ×SÒ=!ÃÝ{Œh¡Ã ¥Æ¸mo�ÀRã•ýwkhŒNuår„\¡›‡xg^+"à7ƒ¨êfsU#Uò`pÜ?š½?dÌ£FŠx¶>º©f&,¶W·!ÁÆõ%¤±-ˆxnÑ 2‘¼_éD-¡q¬p5.¦d*°Äò:uHuÊ—vŒÍË*±_p,ÞYÒ»ÈBœÎ0…~9¦o_þb »;ÍÅ„ÔâÊóå]y¨å“¶ 1"‚)Î̦ÄfìÕNå–÷;8ÓaÚïŠ:,¦¸¤6̈Êiw)ãÅ`qßR®í[/AQ.h¥kýçýйoQÌpÊ,Û¤rèÕ§TóEcé"˜Ü4Æè¹t+äMaØy|.lÄOÇÜ#eÅ*£ÊAÕaƒE/[^=~«‘7²%TØ—ÀoYˆ�âéZ:²ƒqLw+qDC-:T%îxëndn®—Ù¸B=ã›Ö»5ìîÙ™ÅÜHœËQ© @p›+ýžä°?"—ìQøæ l:�Ž1Ö?�{ùînËÃ$Þ«Œ ÂNˆ s ãr¥˜¿é8'õ\” —rBëK·¾º°¹vϦBÓkZu6Ïu)‘N�”3NÌõ/åÃÕ·ß7اx¨fˆîç7Û³*Ø¢gÿ‡fåÐgìk'/χ§ì )u»b¿±\¥G¨~Jï8ä((¿«âÝÀàÛp ìtƨÀ4—­Í®cŽýwþ±–&ÂôÈ*ÓåÙÿ‹ÑQ"Ж“¾GÉý#<a䓯 ~ˆLØÄ@­QÖŒ%$Ñ€OžKº½�H°(;œjZ÷æaë×üè¥=áÚyäæ-Q…F†hAg»ÖF÷æ˜IϘ(R_#¿fƒ—V�¬öÕ((OÝbÒ ŒûˆäÖcB07ÑZ€ø-lyJxË›i¸RËX?â>ÐÐî W§òö†SIP\Û³šßÉÁv øƒ�".Œ¡…±úÿ-ü¶ã›s‘ 1m…p EöG8�Ð|·ì>¸›ÕsjW UÄ›¿Hãµ�f\“íR=æÄw𱕢‹ÄUÛ߬U–ÓV@EøÚìW¥:jH¤—0{Tl±‘¯H¥0ßXI]wᬖ>¼.7‚n¬8ù_Ü£÷è³ =Êg¹“É®ê.€¸¢w^X˜nI¥w‘rGO,¶Ú¼÷úSªº0½‡Su§­‚Å\ í½5‡H¸Uƒp¯é¡í¸‘»ï @!†5®ûÓˆ‰Ã;ÅÞúyþßÂ{D§H­šÓˆ&ئOøÅJ…ߢ'½"ü’ãµn¥“p• ì ÜZiopøUK"¯Ô½�“×�ã&”•b‚À]2yÝû+€®¸,Yï-†£Äp¼­–ZŽÆìž•ëîôÑ](ÓãF±7EÈrS½qŸ »ºžÒu^Õœ£mM,ß?"¿}…ÒÕÒok¸¿�s rh£ëª¥rçÁƒåÂÐÖ™ÔŒì5t1 èÁ“—5¿5 B<0m@íۉƣx¹¨PäiÅ72޶ÙbÅ•�+³Éî–)oU³—òÅß?¸ó¼jEŸmŸtº·Õé¢íŒÌcµþ|�.ï‚êjšî¤&4D­hz—º·*ic 8÷¶ª#²ÜòÂr([/E)ï¹é?É$ š3FóÜ{HVʸ (ç„pæ¢gmMIn*ç†Ü»4‡�Ü %†a-*^�aÛì�üÚ57I]aõǧ#+ñˆè§ÓƒÌ9ç5+”Ñ{<Õ²fs"Z'íêd7j•9µ?qq‰«E.¤rP㽇lý<1oÕuÅ=³%VžPRô@@$¤¯¹«ûú¶-±éOÆ,p„êj#ælº¢C6†ƒ/:bQÛC”'}m–òüÚø‹ŽT;¢9z[Í"~¦©bà“¿-ÿ•òY…3Pмë;êì,Æ^Ý휧<|‘+ß¿Ÿónw¬j§�l†ÚÌêTK1¡'Ò)+vZ´ø¤ªÞ– „TÑwž—hÃ`v#ËÛ¡µ–uT� õK bµ•—ņŸ,�~´¹ÁËLƒÎöX3>ïÅ4Ë¿¸ï¿É ê à=d0I»þ¾÷?—€Æ‡¦ö¢™ù>‰ÄBóÁ¢”Ò1P(|šùר }“kÖ- \pè˜uAû6¬–ip¿]Œå›ôÃ7ÕTÃúO©D¬÷²�°·Zð­¨tI/ô|/ÄD�ø˜^©„~2ý¼Èô¬¾²W³pVY¢8¸á Qj IñÐÅõGB{<ûð3¦�GHJë�üÁ©ôŠºÌž޶å@\` �íÌÝö $ÛÜ®¼`ͧsè¥õ¢ïÒÉèïÜq˜/¨VÔŒ#øíÕ®lÀ@²K¨ü7ž­�[<å<‡0,^†+Èõ“½âïàcqüh{‡+Ê‚)y# ÷þ¶%D²™ç¬SÛl‹vç±èŽß®‹ðÌ*Ò¦’!êÑ|ÛÞœFh¬O0MͺgMžã9̸ô… =Mµii¯t‹cFµEXœlϰ�«R‚…ok>¼õäþ„2ªÝu–x¦(™û1ebÃ8‹/ŸqG¹ª…˜…yôÝÆR”Å÷<�5•¢ñž_ã·[ÀòO®ÖÙÌâðÝR3#D?sÁ î¹û�-i÷ñ5°Fà74øWÆÐJõ"{)þÂQJWe;ÕÙQ–�H.>J¨�ºpZ2êí¢\�OW�pбj UVò鈚”üæ�HqÉô‹~�`”:ù�,©¶ÒA—Ý¡¨GVaÐU¥ ŸºÆ^s(a ùذlµ^<žþ}õö¶l¥á/Ø—¿Q°Ÿ#QI¸ç4’€¿‡ôë»àøôhf6ã~úÙjÍÚº%!Ö5ddž)KÓiƬçÞ^ Î+$©CúHd, ¿Rn†÷“ÿÁ»¤ðõ{zR‰ÍÒÉ?n¿DŠý­5N‹pÄ$à·@åÄÛ(d¢6Rð öj8‰?5Ž“à2>/8aç­r©çnÑ‚ˆ ¹–Š92è²'Øé…Cë*• ý[ŽzLÛ{¼ÆšÌÀ¡hwgïäηeŽÕÛ¸‘I¤öíçW£€ÂU ¾3ZóÔé yÇ�‘ _×VZSTCÁâݹAÝP(¥ é@–zru‡€@òƒŒ•A“¤é+㩸$üìV.ÕÞR¥�âZzݨ:a™‡7?ÅØsÔRÊ?àÛy£¼‚í�-´æ'$majJÇß gHˆYÍ�åñµ› qDðl„ño`£­Bué_âõfˆ[™‰ÄU¶Ümò&¦+”¯Çr8 „Év“>‡�F› ^¼ÓÏiÍíã¾y/kÅe@Ìþ0`_bÝî)W øzï#z7(q�Y•$ÉÄ8~<sÙ+£‰Û#膉ÿO�4¡pÅ�µ›-²6/g»XÍIÏM„ÿ 7ŒÃÓy2ååÇB2—ô[1iËÅ–º:œe~àù欘ä±ËZ@¿œïs,þÚ^™�?–A3ªÈüš#ˇTuh}÷ëj?]—â£]hÞ¯[G‰>•ŒÇNÝÒ'¼AüÉû¨—æ¹¼R)¼’W�=øS{y€I§PËXÌÑHž,aö”¦…Ý9Mõýê¸ÉeÓÌ˵¢¾[¬6?!n(fö,«>èþEÕRÆaV8x‡uIµSΞI2nÚdîç:äÎQ±†ØÐÀ.ÓG#Ëð¸£öj÷w ÇÍ Çg)5ê%ã?š�õÍiÉu/¶”Ý¡+MÄ‹Î(Tñ(ž)„£Bàøîd•x..h\7Ÿ÷Úwz\¡“O¾/'w¶5"èFr�NBºÛt³{¿"�Îl`4 Dqcxa †3²˜ÛÆ}¨ùÍSùåw¨˜ô1Lã8¢¼éöÕsn¿£'ðß$Öí™Çk§Ž(DU÷k7×°ÿP)Šï<¥jäuÞ šl2ag§¢pª¤þa+ƒbšYºï´•Ü«ÃÅ¥ùX�8¨Ž"Æù—Ûe+H¬Ä…D8nYŽvhç›K­!®w!NŸÃ6°!:z¥›íÆ 'J: MÇá]Ù<·æ×ší`ùšëŠŸqË𠟰|P�K‹onóØu¤"Ïœô#ã:‡ÓàY‘£Tw=j·NŠsBz†¾Ÿx¼¹§Üyt !I(G�Œ2ç¹&v8Â×mA ¯Ìƒc“Îo�ƺµ­>�p5½�-ôæó €ìê÷¢¡šCaÌc]#Æ�×ЩlÊÕ€-x§©:Õ&í¦x6ÛÚå£oNOàÖ�ss÷õ×È�Ø*FU¾ýîN¿1@(§¼6Ìü>@€#€bE ÿœFÃTïªO›ºAÝ€ö¡¶ ñ£ûœ :”¨htIW0w×�( ú#_AâÁÖ…½Ð&Ã>eÔªÌ�ru+øîþà;Ž+¢Uo#¨�XsçP°Byåš$ùü¡ž?üU^Ũy^ûØùùÖ^d'>c¼á=sÔP‘þÚm¤h�¼}�/JËà3jû‡$Ro¿œbhŠÄÖŠnu§Úu)S–µ%¤qôÌa‰ÿȤàgeOö^¯³(j ±>ÍIb»›EZ&f†oÚ÷ŽÒt}ƒƒ›o.Ïȃ‰7yªJ)޲’†¢eAÿøÊ ¨söIó§ʦ ÕL �&ëÚ§N•`;ë£*JfÄ °Ï�äõ=ðÅ_©ÜÛcyÔù›<Â@ެ9y “ž°'4DµØ$š@I|êQ[k[¢ÐòƒÞ$½*‹‡ü6w•¶eQAToD‹­¢Nñ¨ù*À²ZÑØg·f(QtpYŸ4I¨:¬`:(³°CÈï¿?䤯l3u}ÛäƒõOЀäÛñYA±»p0IK®y{�¥ë êÎêå¥}ûÌhÆwBÇã½´b¹Éz•Ü…îȆ\÷°ÒÚ¸ Fs) 5Y¦”­‡pðt¬½x íß-Ø&f¤Dˆ;P:‰ íÌ€Í�¥ ¤ØJö™GÅd"i2è—5é纚jÏ×&±ã^ÚÔÆ‰ˆÇ¬‚ŽaøhÒçX*Ø ¥Ÿ9¨oä ÚDƒlàÀüeè¢Èqå½0ºgZ©ùð²Hø*¾ên”(,ü�úT½e(U­d™‚¼u�‹syš™?ñûÿ&q'ŒpÃ[µw.ø—mä^Õ=BñaS¦RÆžví›"u�bf±Û¾‰†Èm0žøðÞ:÷!ZƒØ³Ê¡}ð©ì»£äË•}:ºl5÷Wc)s —áRGÇT©¾‹EŒâüÍ,È�œ=�³Si^�;ÂØ1|‡lTû"ÿÌܰI¿å [‡xuömî¨WˆÉÎÞÄ¥†¯Q�´tö¾¸iÖ'ÜþEHÅ©¦QÕ‚`¢åø¹H!$m¾Šv¹£9ØÀXéáöÙ0ñd_¹¨¶™#h9ø5<á|Xó4ÅësL«~ÐW’÷¥ÂÄé·>/0ì,s!d!‡)ø¯ Y2WÌWšaüµ �-þ%~ú¦Ü¤AßX6ßpM•lÊÕl�šx.5÷iæn3„D1hr:½~�—6å=I›ˆCæÈþÌ j¢ÅñÀâfXŒw Çâ6É"KìLóÁÁ¹KŒv�ø‡¶‡!ƒ(:~¬Ó%§8@·Â¿U.Zr—G¨ç4ŽË» R—]È› Mw`ŸC6Äæê³lw°±¯mÏØØGVf°Et£ :;è¶)G p3O6©3Œû¥(+ÓRx‰ågEÊm•»óåV¹P\÷Y91."Œÿ�±†L!‰—zpê]ŽÈy<à…ߺH8fRDa.Ï ÎNV¡z;=;@Ø|G£Q�—ñùÓýÙ�»)ÌžPw ˜™y(ÕýEm“à•¶=Z±x¢‹ž,3 ÓÖð1úTJvÇIñï ­+JÊ:µ»’LzU˜dØ­˜W²I!:Ú:æ/s8g¹|!-,4÷´Õ±Ì´N!Ú[Gñ¡9×é6\ô3EH7ç!ÿ,s.ny¾mú‹¼þ¢K3�þ x™¶ŸD1A¾•˜[Ì{`îœt†& /ú~ÚÌiÉ^WÙ8Ùö d9vÕx뽘dT¦}*@‚ÙZ3’*8»É‘¿óÒcHò>ƒ ‚°¡¥®ãº8ÓîÍJW!©£�Žï^ö7D­–ˆ•眑ÖÛºâ>àëÐøaP<,šßµØÖ�Ð`cÚ�ÍÝO‡\‰ê•. ý �Nõ½yË3±\b|OÅ ò´™k¤ÛÍ€øK[á¶´ˆ®­6\µgN;}0� m<¤þ^–Žx].ÙØÔK-�¯…”[ûä‡�–"p„›ØÛ`¦¤–ô“…0�ÁjS¹7ÏÝ „¼‹xªìðÖUmƒãD ŸE¡¥ÏqS¹Œf25®õ•õowA 8¤R¢Ûö“ëTtr ÌË0Xñ¤�ªú¿·.“8ûo®ãt >Ζ_jiÍU>Ÿ{èTŸoòÀÏšKÛ¦NýÆÑ²4ÒÿóJº&>÷�À4ê°5�•oá[>vSvðÕƒYöCã]VÝîV•ZùÈ[®¬à{OtëÙZ<‚®®XçR �\*V¿¯#†&Ì^Ø™6„€Ÿ´c&—Œ�®1Ê™púa"·ç%‰AÔI[CÓ�V@Sÿ…WƒZÏs€M¬Ò øÚ¹ß&”D4�@¹“ÓÎüîäf„&(L¡šÛǃ«c £�V›VÏÖþÅåy`—7%~É í_>QëámN ñô2Ããïµð‰#…䌖gSù~;�z¾÷†©~à8¢‚æBw½ÂZœs_¤D 謉–u§Iþ 3·UM~Ì”n}ò²Æƒ �ªÉòÉÕd<Ó¶ò€D®«lWužù'*’€]Ù¶BOù ÞéŽxÉʆçNÌJ¿d‡¯LTðÓ$�% ·«Åšt'Xå«ôFl ä …ž€r"u‘ie(J©ð«rßé³FgÚ`é»ÂÙû¢gêèÄîRlg°qBÌr5ÁÆ„¾_Hð¼HƒÅþœç­ZVSZÓY½é7”ëÛ´H©½S›þʈu<»fiÍIƒÄÏ„Å;+ ?æ™ÅR¬Ÿ%ÕFæÂK±¥YÏìîsÃýìõòìûï˜Ê_ P Û�ÓàÅs<› Û8¿Jk¢Wvå4 ’ŽÝ¸¸ª“í¬n¼‹–øJxŠ“:ùvÝ6¶¸þó|QX‰ð/¨Ú#ÿ…=<4\d} _¤E~-Üz $>[”2ÔÀ w³Hß"®V™ì ¸Õ1@ãmîÒ×UÄ”dîÆçÍÁÏÓÖJÛ¹ùÑ _F® ]‚|¡ýÖC9u’߉Å�¶rQâõ…�·óˆ%b…Äp϶�{+>Œ/‚¸Á_�¨Æ«—Lã¸0çSØ�´×Ðyi()©ðòktR Œ¢»%8Ä?élv…òGÄ~˜vŸ ì>Æ“¶©Œ±PÒæ™@Ú§ÿ²\è÷âgW_›FÕ ]`bÞ çôƒˆB‘83ìm�ŸtQÙS÷ÐM®ì÷BÉÑÆ{6Þ b“ï9 ™¾.BºCÚ’G�3àIÓáÐÌð¸¸.�zÔÖt˜Y�’Á/)¿ ŒkÏ*#SÜ¡§ô\‘¿}àQýðËÙŠâ–`[?êÚi/0WøqËê("{®-n”ÊÞô-4¢�¶l’ömZ%˜aR<Ü1æhm-!ñ˜æÛþ Å·Àû¢B/r˜±E¸hy™§¡ýùi{÷¾�²øsØ Pݨ�8Âõ¾èD/·7_@?'|ת.]ëû}›7PîƒèÜ\þ;\ Ú$mqxb™u²Nncé3-Š›õ» }B6zcuX˜ŽR¬à1 cå%k8c ¾c\W*ÕVjÌÂë3ó£×žÂ(~’v¬#U”ãFø’œDÝZ´Á\ožp )1é9ù‡Q­‡qe`‡eöCÑ:´«çy-£”j„o§iMóˇ«%±€]¬h¿‚�Bà ês‹XWýj <¦dl¡Ý߃�LÊ Þ˜ƒ½$®Â’Ñ=é„Sïeì Š‰{0˜ÀI¾.‘4äXzás̲—`n ⤳ÌlEN�Óý±_ìOœ÷\Úa“·pbÝAÛw�íÊ3ä?�ƒ™~W~ZÎVrõ`›¶h½É®ÿä Öq�r¦ž÷Ûr[^Ïþî—'¹»µ3ð÷¿ô®ÕÝä”s�Mï¹n!¹ ð ÒDOÊÈ¢Ø×g4e P®)–|~VW„%$.S[/t¨ÆÓ¹³6Yªû¹;†KZ<érDH”„ Û®ð&y Ó•º(è>žiÛ(×K,e và3”•8!°†î… à¿a‰¸ ˜R¦ e„¾�ÛO "Vn!O [›þáIî[ò±êŸp mËõ #c„–� )|p¼:ÔólŒ‰âÊS»gDH™–‹©ÿ!tÖÞàÕ”±”«sC°jQ·¸ŒJݳÈQ~C„½'/+z &æøM ¯'R¾l2ðüUV�-‰¿Î®ˆ oŒDn%e§rÝ …À¾)]u{B×ÐÌwý›$yKyOžÌyy*ÿ^T0ý¼T4q±»$ þ}¬ÿ±m�w9ü#·vÀŒÀf Îå Ñ†žó�% ËÔâàX¾Ÿ>Q‹€H|§ÊóF‚À¹Y<¢v•ÄJ8þæ-ªWåþ@iB™%Ë46W#*»›I:×t�òÄ�Üô�¢—7êÔ>î[Xë+ÞŽ7šÍÕÞ<ƒlgh­ŽÕHôЛ ãÍ™‚x§Ç¥ C“%Ïù§µbž;ÃÈï ŒV Ûhs9ê™ "®¬jàýh}qÙëù”Ø3åÅœÛ[»4\•P£üD0ÊÙ†ªz‡eOõìYOv÷\�<�Žhî×ÍDe¼¹6רt·rÓÞœšê]ü$é¹I½0ÓX—¥G±“Cl4†¿&qvË+Q4è~§ÆHÅŽ{}ÝïóËÔ§‘I;Œ‘�jp!ˆ–Ú„sËë€x*£‡ ÔÝfùØìêr4žyÝiðŠáŒØëvš®QÄ€;›xðPͧ÷·"ž�>�>‰ª÷Ö‡ZñÜÜhºÌô˜ j©²®Hö#ý¿¡êVGjn`´þ,½n‡Û\«€—ãÿòe6‹ºK Î@¢J¤¾G{˘?E0Ëþ¢ˆ.ZGJ÷éEGäñ§(Œ‹â{ŽO„ßß–™ö-ÐLøh„·MŽ=ª� Ö+÷ÿ(ÆaÛ®%jDñ±qd+” ÿEbå¸>7ÁËíz,Þƒ¤=Ã$ÍÍîÇÍýô'1mÚ’[tÅ©œ©Ç:ºgŠYÎÜ^²ÀA8à1?éÊ`ÙŠMxù¬P¥0ó߬ór‚³-µ´GqЊ)жtß–—\˜!Ö·›îÿ¿Þ¡× ö”…+Yç‚ß猵¿�±ÕÕÄfäìÇ‘ ?˜lÂÄÆÕàÛºùªZ`¡×઱iÇRÿÜ•Ìî¨ÓP½ãðO9…‘8W"Òæä�ͼ;ô…–ùˆ¨Å©€Ý–  ~cŠÃ©K„ÄsПH®4 ÕP—Ý ŠFR�¿ UV� Í6¶5Ý©È “¾ÅßzÛõ»é\+Oåü†™­ÐŠ^%]™M¦ß ›¢Ezøo]ó’Yþ îÐÎiÅaÃ…¼Ç—4¥mÃjL>",µÌõ4a{îÓj’­rÑ5„Bt@ïuYrÂpßw  R-òîÕ}�P0‡R¦oj‹_€+7F¨òØ•-Mdz¦Ì©ïúÙ�<®,%céªó 2YÒù<‡’¥õŠóÓ¡£ÅÎo�-‘I\ÂsÝÎFލ)G)5#í)#—Þ=4F§% $ÌYt¢#©ˆëïå3§Æt}èsÆ'ö[ Û­YÙ÷Ίñ•{êœRày‘Í„aÔù_DÏÇÀ2Þe€’‚Æ–öuHö^ÈX‚áxY'GÚèªb‡dY® ë2z%ÆØåºøô�àÈ�¢- >O/œo°ÖüÊ‘8íoÚbŠHûÕyóXŒwe††.ªi_¸írÌät¶ÿ¢8aÐc�²T-«�‘¨@æ[bë_ÒÝã>!j1ÈSí½F–Æ¸Ïø£<ùöoáâh ¼ÌÜ †pRÑK/IBH¹u@¨­žn¿ø¼�óNs<Ê?nIóæŸ-wùê¬:-á~´Ë‹ö3b†vSËú/ûò‰œ¦´ŒPyrÖ<‘Z}ç•Í“ � í¸¬Òˆ!m‡ß‚Dÿ7ä1ÆÀ@,Í�Â?' Ø¢Toø Zƒã7¼û°CОG”šÆos¡,´.²c2ñÐV<ëI´Î#c4œ>°Q'0™V6Àu-é¬ÌËæïæ- èÇ LNfR {g¦‡¯Ò,�©M% Y¾¢b� 8ŠÖÔAöÅòÈm¶<Çñƒ_Dïìxˆ�Ï4+ÈÈöÑ*|q —$§7C¾=wSìߣ²–1Ü Is8þ«}Î[x‰H£ëìX•X™J Î?5¬s±½,ݰ û¡à(�‰°$ÜZb44 ¦€§wç‡R2«_Š}@î¿a�W�é"•[¦®RE/‚ºçÞ,Ú3Bíó~…žT׋VàÌ\ ™µ²È,5æp+( p‹7� ÁrR7ëàêpå² î‹ÚóFú{òã ›j‹ú1É%l[ÿ¦XµUŒz7`_ÀGm§ØøÊ`¥ß­«¡Z¹cæ›4Ј]<·â¨7>ÍΆˬóõôe¦ Âmà®\±‚¬œæèi¿rÅÂãò�k Ðœ3G'3ëjËP ´#wf¢”Ïóv:dMoùqdmÎä¤ÜÆÜ,E~…G3 áëî&]MmSæÐ†¸¾b¾¬AÊHe8XÕšu¼*¬à”ïnêgEŽ"—³íˆf™œ�%înæ-Áúšo\r~Ø�ÇJþvð„1x�g)Œ¶9z7·”pœÌ*ót«„_“Ûƒ0pݲ½& Gºa¨òµ*»q»—ò—V@{··XL"‡PÄðQš«½ñèÙÌÙävÔ˜ n'�°_ø©iŸ)wv¿.6�|ÝŽÆ¥÷‹‡c쫛ˤë+y¸àýg·-­’Á!Ú.^ ޶eý˜•kº #ʱ.˜¿´+÷ýJúø~JÂ[^‰ˆíj +‚u˜»ï3ëë×4�uõß äôixZÞ÷̰‡(Ä,¼²&<�ª(O¥+ʾYÍ¢64„ÊÜå=ªŒž\iŒ°X¤<¶‰=› j3ö�3Ç,–$ÁCzv „¯ádÕžå€2Jójøp’!{ #ŽP¯� ð»xÉpeϹÆAûtY #¼KÁçê•ÓgÍ8Ìó1Q¸=ñ·Ÿ±ÓÃP›kÛ,['„ ªŸ¢¯6aù´ Ǧ†¿�`ÐeÞ—cv~f—)☎ä$èÜk9‘Ë2©0s¹å«eñŠ+it[·’ßËŸ6uEŸA™Ü'~Q7småMŠû Üu1Ë4ÇmJƒÊóØL..Žÿ÷IjÑô–}× úÓâuAt¢Ö>­d>W Wйƒåoº˜u3ü_¾ì> ڵϥZgȯ•e$¢Qc”²Âá\¬WãIwÆ¡ñë·¶øª­p%H;xÃcã%O·¸�&6Qÿ¢o ÙfµÔAçÇŸª��…½;ëžh܈#ø«UtA¥Æ+�ü=$q‡›�´¸r¾Mw@:„¼p‚%x“= æ§?vD¹Ëa è¦Ï±—J6š²Kp4¸xs„á¢ÐNÄâá×Àîi=[!2ë5Øçö©p5�=j2¼A‚+‡Ûà ‡–¼„ï+u'ÏPSGs´­“È—°Ôü•{µã3: ŸŽX|·M)5Ïê~«‚¾¥˜­;±^�üœ²âMú2íJ’Îû¥19öâ®c4«×ŸfS3O•*›ã¬š²ÿ(¬8ù—Pc å)øÇŒÒŒ«ž…¡C%Jµ�•bÚÔ+EØ\¡L¥‘ŒHtXã$WJâ¨7Šdkºxj9OË1ndKY¿y1 %k�TÈ,¤¡j=ÐÍùÈÆ9{óþ ÷ú•ë˜�‰Ä–<ðÃ0åЫ±Þ8<Œ½²ôý§øJƒ£k$�ˆ YØŠ cn­Ñ„>bYNm¹l€ÒòqåYƒùUØLOVIøQú�Ëß½1Œ�ïïgø]>`8Ž÷p\�°þ°½ìûx,‰ñU¬·Ç™È® ,ú¿P‰±€âÕçn÷R®J&Åñ¨šÏ³¨ 9± i;f}Â}96Áú‹‚Žùgˆ“VÊ(!úm>`stTó�,çg”¹"kЕˆ·ÚŽrÚБNßRGQ¼îx”Ÿ0ÚTòÂ�–+Í0õ*eg€›íæÐ›™Þ \�C‰„U‰³ûÓ¢-XNn™Þ5°ùäúkÿëØ_¶ñ‡ÞpE÷ÉÃÞšî*ü¢ª�KÇŠ¤‘;®_i8|õWÝ|?"[+�¬SGLt p}²Ê£H�££)Ö}ÿâ2û”CÉ\qçÞõ|Ü’äCJá€t%“7)ÖÅ4Ü;mí& vc¤·9$ÿïoqC˜tÔ;Ñ2*ú\XNÇüÓ®°Íy1½„ ¦›WŠ"ÛºÔÙ²ZuŸ@îæŸ¿ÝX‹£¥jꤰ8 P¥y�žÒÔxõ¶4[Érãé ô´½#€í’¹'ñ¡H�Ùß<qýˆAüµ¿žó¬1+€(iúaä‚î<=Iä!ãw¾õ]E©AŽ¥‘çˆ'ëî�í è-Ùy¤›#×Ò‹1&^·×Bá¾w!‘â…àØU.\Ø‚ÈIªJYR�ИaÏ‚’z_®(GòFŸ37Å2ŒµþœÀôè¤ ‘–czV&bymíaÞÛgøk$Õ,TŽŸ™öe0Ì(ÛùCU¡�‚~lÛX¿"" fö;a –AÓuLÍ$cd“§+-]š†­4 ·iÀn‚ƒ£]ù‘bnOÖœÑb4ʱﳡ´3¾ÛB¯áÎ` ö0 J³¨(G®!‚SaÑyhZ× «|~å” Ü�€ª@{ûj&QÛ×Ð3eñÜŽHE~å,]žD¹®Pã~D¥*ZWêO ˆ’µ9tœâÖXÄ +©•¦¥Œ·†g¤Iµ’ Uœ¦/ˆßG½ŽËóx:¹ÑþåÂ&hŒUA£½d´ïàämªK¯ßJ>-ÞÏ”ÅÆæR´pf,ûcFYÙ@›«eSËä»XݰfŒ·pdëX¹? ‹Üˆy¥µº\µVÍú]imÿAé·Òùè"&ã¯X²Ê�>µm—ëM»ÍD¢…9¤´G:mL\Hc·вeQÚSÛݳ³äÄš5ÎÓ£Y,Ôñô>_¸ñ‰1ã·våÉ53žDÑäu†°Ï�òÎø3Z·ÜŒ£[I$‹uºTWgv0’Ýîæ#¢G°ÀøB�XQ¯ü%F¸‡»æU8Za“'™b—DE±KDÝtÑmtË-²+Ï­³{@ÍhA˜D£¼#á"Nï°“Ýð°vMáå’ê»jKÒB§gsmS×Ê{áSš Mê©Pd–¾`ÃrÁ÷¿iÊ-�Ï;~£?áâ{óó6ÉÓ¾]’$½zó‡ÊAÓÞg/…k±9ëxQ|Ð ÿŒ£BÔ¬-Õ+ŒŒ$ÿÅ=(Õt07ÎÐ:aüqÝ4‘‘cVŽÒu²Ç½_qâ™8•�ß2�ü™Ê#i×]ù6öd™…4‡ {xäô•FëMá. g.uH6Ó–­åÖû èÉG U/^F²³Äu¿�.%¨ Ʋ\}K-^9¨€Òñ_VÂ`Šýò|UuZ3Ê T³€Š­è*9‹í%Ú«’ŒˆŸvÁ.Ö¦TÚÀÈ4ÓÏZX €?BoÌ Ú[Kÿ ž¿¥Û� ”BfèQôºv¼W"i£ü;Ñõ5W».Aû_8X+%Ô>¼‘µ°î.{ç„è{a€ò¶ZÉn—Á?Esø­¹%bü7*¬èêÖ‹ý\<ï\µeWF VRfò„lNWªûcu.‡âDå‡NzƒxÓœ¢o¬C©`×Åi/bÚ±uÀëÿ¦«ƒÕÓ•õë'ÔNxbty�D#MªÀøüEQ™à‡µ_]Èn1³fÎc´"w-7¯¸ À±ÜBù… c£fâ–ÑÛÖD{a·,!%Wàª^}¸Ç,=ñއŒ 0Ïq§˜4d#Cðªvá¤%WÅcÈÈç’u¿>ËÁøú³É •½�jÃfÔ3?9©k#ëYz™¥�Ù{ëñ{S»/ÍÏÔ‹ g3þVÑ382*˜K`M§]Õb÷Î%‡Lp¥ë T`×°åø/žä9XƒGùÛz!LƒµB+ÌÿGÏ Ôžâ_ÂÔÏ%l6¯¬Íâ°#µŽÄt­¿„a>–9I¼~ŒÝèûÕÊ»#ÐЉL„á ëÃÃP®=`ª€¸å~1}%E‰ýÝb雀–ܼ-æÊ>Øû€ž¬¼5(�7Ž êëPr“TQh+áu§ºHåöö­šçWÏ¢BKS¿÷Ý@ÑÓ¼ÚuD2ý´*´Œ+wóF%ÄTÅS¤“wŒkÄD÷Ã!oQíð¨3xÿÞ(6—eº¥@ž*-l³\ÐVa!Ö•¾Kæ@u¬hØ‘‰%¶êˆ}®G~Í„q-î‘h}s)»üíþ¾¦º�…kaë…ÓšuJyyJ ±*PXûˆ&XŽ]¾?òë’ {ÉÕñ5®&I6�®¹Ü¥’ªÐ’2¤ÒùLÜú‹6´Íß&•SÎ$b1x©;ømõø³SmX¡tZÍ¢*ðõt¾À«L§~/ç|ý»·ÅçI�ey¥<'#×…Ffí ¤HwUËýó|ÊÃwfɱ+7^pqhS¦~,Ê`�¯¬•%˜’ìzÍ‚Ú ‰1R„ÔÏ®ŽF¼ñÀ‚Þâä=©FÒiù¾±9�Ê`ÒkˆíGQÊ+`kN[úUL?=hö �¦§æ…¥i(k+4_¬ß3yëhÐ7m{²,ôÕñWtà,5ðq!Ÿ÷ªœ‰ í?EÓ}O{M;Q»Á[¥iô¥™u8;yœ¿x%®¤Á"B&×Ûœ" «ÉmváÀû#wÅc†uæÀ žÕžµB?ö ¥D~Æ !ÈU|˜f�º·�vv‚i¡˜}û­ô gû‚E¦ÅOú½õ—yŽ4í6ë¸îùlM·ÐÀN@gÁ|ºQùš'§'…~¾™æ�N²6àÁ˜˜Kc¬Îa§àáQÔ È{N#ëd¦ÁM*Çì+# W6tÂuG댩ºñ—«@6Û¬hݪ–ü�O»7DaÌ“$·ŒÁy4˜BS –Øï¤"Ë5®n4¶íPóZU<®ãÒ \$$êp{ì‹�à°¸Áõ)ÈBÚ&V> ~¼+æ´¼NYÁØñZ¦ºûÒ„Ò‹ÿ�©Åþ‚«—éI¤$ Í7Õ´ _RiTåìR�%¾¹½²*‚ÔFðˆú–ú�¾ðÿ¨…QŒÒÿ¥2íÓÝ@õųäï𨤬Ò?æz\~s—aÕ¤Ê.ŽÆáŽ3T÷‡X·r i6LBÏ:Àáãmñù+‡ôp*Âú«,uwfÏ{Ý»¹têd^|áÒ¿Íx�~ ˜ŸÉFæ"‰ñ�¸R-§qRŸl’ÎÆV­Ä(ØŒüžþx^+Ò•÷Ò8e6Ì�ç¶K2.½V‹Æ»÷ŠÓ-Z°�¬ÍƒÃ,Í)˜Í=Jÿ#"§S5 ë½…‹ uvÈÈã¡Éêy@¼†Z-zºGàvà­lG~FrSü÷«lR+µx7´bg—i¢¿8Hh+d“ü Ë^<ˆöçgqF"�� %І©ÄCd�>�z�úýÕ�¯"š 0WÁä…}:;Òe*\=ùøÍØû%·ïD{¢�Ä€l{ín‡³Ôz=†#t8Íw´Q+æZ¦EÛ$¯Á…A¿²eöÅ•âú.ð[àçûÉúÇ x…õ/f�ŸÕ�ÂêO0%:- MÃÚ—ŽË}�Ž2Ö‘Æûæ‰8�Ù RúñrOÁ½xÍ÷íç.ÕÙqûÚ]ÍøÕŸ6<}ÿJÓ)[ÁÜ/ų†¶Ì°ÌímóÉÛå‚U{ÏÚRÄ!ÉC­ÕÉ…•DV£,Є‡ëë´/—²ë/5‰~Ž˜S†Úï5KpøX-þà e ZÖ&5/ùfƒzÏ.OÚ³hëN?ŒV¡—3÷¼2PŸ…„bü0ww¼k´9�Š=g—5껦%Wµs›¦Ó„U}%$.Qƪ48É>“úÀ[vº}Ý bù4K"DÓe3 Z‡¦Y �x‚šyp†Pú€0«Ãõ÷â÷hçÆQØYHHÍ\Îêo€MF÷‘!BFÞþ}t×7禡ðCÚ·³XÕ…r;3ÐÙIEt‰+¬Öq+›�ÛøoÀÏòMÞC]®÷H£ô±ß÷•sù R(�æ'^o²vš”WÒ:?(EÜ&CqäW¯2gÊÉô«­þh5݃d L‹iW7pÐTÛ£�QáH¹²:X LÒÎ>/z¥©U5ôcªëN¸Œ/2õêǬ4)¹NcƒÒ±Î3�.='"!Œ·ùý+¢šL›ITÓnê÷³5bª«ûBéhwüûÇA¿Fj*}Å.zœ?2=Œvãgi.=ä�h½¶&·µõ°èܲÔkï¢ÃÕËHÖv!­�Õß�H¾Ú¤ƒ¼GO¹UÎù9ðlà²Â2o+ÙŸ)7·‡mn�>ÎôÅÖTÒhn8݃)šs[²TmØsî¬è‡ \Ï}×¾?)ùÜ_VO¥¸�~ÁHÁÙu%‚þ~køÌœ”z¥ÀµŠÕŽI¡¶)þs:" (ÂËlªé¤ÿd*;žŸ 7Ð{K:/Žêu—Ì8¸@|YNÏk>òu97k¸êPe� œ×Õ¢ºzMâöN1¦DŒ�d¥°ø§ŒPïÆIŽö7àî©7ÂÛ)XmB†åÖÔ71HÚÍÞ÷YÊa²he{ž²µb· ¼¹'Μ$Õ›ŠLHN¼WÌ›FRRî½Êì|ì Éx:4žâÁz–Ÿ²cæ2ˆR´›�Çi•WžVÙ·:ñaõu5)kÞÜ©yeþšž¨V`„bÔ?÷5˜¹Ú Ô© ðV3P¾ǬBɯ†Gö1�¿Ÿ O7É·ïÒ×_ÊžUSëò>ƒDвdÔߎo»ë Ç“Ö)m¨n¦L›7]8z5|¹iÕs<ëòúP¯C¸Pç²@Eü3Jüiã 7þ¯“€&ao‘¬ÁÓ ý2ÿN$ïEsÇOZ³ %.ï7Kµ‘¡õ× . — Û ìRXDEQÙ“Q¤[BPœõÞªSt‘�N7¿<2DW^°Õ¿þwÉ‹ #FÅ ªè·ÅÞ|âò¸mS2ä3È9V¥P šhÚ¬åYŸRRþŠV[üꊹ¢vØ%fÌ`ÑœêBlÝõ'gç@’%e·}Å‹‚€h¸`µŒ&Ö«r'i936F2Òõ�¼�,Xˆ k»žm„ ñ`|–#Ì÷}É�ȸvøYô#'mfg¶¥]o`n\’­•MÿQOkä‚{`]5»®N�žcV%8%8sÌ©À`µì÷ˆ2 dÝb®¾*&W:®¦g) ÷œÉÛúî O?ô¾»&3ì†Ì朡 é°¡9ós ¯4xð”Kî/Þ³îB!ðx}[¥B÷€)ÅŽûdcÐôs»ƒ²}SQO×9‹¯íõ/®b|7*žéyº]à Üc(Øäöƒs¤ZÞn_Œ¦ÓkW_FóÙ2¨‰e�ô BXSñÿøÊ Çõƒú@éF«ç \ÓbÎ¥»÷Þä׋N’9 ê”ÚB_Å3Fÿ†¸ya=òˆ6Jì Ò7Œ|5<œWí#TòJô5N êÔÌåDk’s‹ƒ¡öb+Ù:¦TÌ[}a«´:–%¢!¦•2øsÈÐvÁ €G€Ç¢g ­‹Ñ�ÊQÌd˜s8TñgóýÉ4WŸ|TÚਉlzE 2�þ6ÁØÕÒâe +YéÎJ€ 6<Ì:d¤ùzZMú \ãÇ/zוÖáX’I#Då×,•jVVØ@ ¢=PšCcAżºå�o€%�|j�0�n¹6¦rhÊåØÙ‡×Ý«_¹P“ ³™{œWNëñÑøy°�c”Ê]ŸƒýB7¤)Š+š“I|ðÛ"••i‘ÜýGÉU¾ë…T=JP̸µîØî%¶ëJ‚3ùÞã:墺Û0¾V8›?͆ähxÄe–TiÀ�Lê‘ܵ-ª=ÄÀ‘�·G”ܲ0l `ç¸'Tþ® MÈ2­â:µÅìª2ù¥3±clXíÖge@ñ¿u½†è[ÔI¤Úúë ÿ9£©óòÅ¥e- R@Än+¦‚<„Èï±/œ¯+Ѥúšù²Ÿ3¼>]ß“N'#®pï[׋W–@߃Wk�‹²?,ÇX‘pãµUŒ‚G*n¸€i™Å)Tì¯þ4†ÄÇü�÷FHÏlw !“@•F6 ¥%T{±#¥È¦å¢ „½ ‚šût Q¯§2œV@½/jøE]�·_>D›ÐM¡óÅÄRÃ1ÊŽcKbâçRæžœ7AxõBšv²¬Øy¾aÇ»?ç Ld­£àö*_7±|ôÝdð^°R3%lÓ%ŒÍ«úk`vÃÔÁ‡B\” ì-hI4Ê Yµ_‘��˜º`;Ôº²wâ:ieÆØÆü¼kížÚ}DÔÊÉobFã´µmqºI w£PÓÈC[À>IgM8’äß’ãË=wgþ‡+4ZÇz,SGN¶ú’¤^2}Ø—¨®ç>¹ £+ÌÑV x¯ yt%€£è“Ö»F^ù<ãL¶Y‹jÖ³ûå õ*l!«ëê¼ç‚±Uœ‘xð'ûÛ áçmÌú÷›™¶ÃpS ÁÍvs61ƒ5«õp=4±¥â “Ð[–߈‘&CÁ1c¿­)ø[9½ Px((ÛÉ{ï «=ñ,$žsªð±a&nBïš,Ê@Um ýªGÞ¿ò@°‘;Ð?š8]Eïœò¨Š2~–ÇB¸+Ši õ±¦DˆI(} tÕi�©ß;v)gp4 ÄÆ�å„ÞiGj(ñwÀ(ü¾šè~üŒ�&ܵ«ObNˆÎ~oß6Òå=è28‹âËlWœª»’€#ëê+™jiŒGARI„LIuÔRÓÇ´í�=&‚éEŽzzkÙžÃõóõ Ž&3‘æu¥îsÛ¿#öZ=Œy5Ù¬Ž2®Ž‚xÝe‹S% ìá Êë¾§ÌÉ ˆ¥²�é=¥ …UÖ ºS@P­š<þ¿ëšá;Œ}$¬apº@…U.VÁ›L͇°êõéÜÕë©^É&râ× çF\7”P\”�µ¥¯.æ$')¢P\g:4,$ Ñ4(Êž€´@ÖãgÖݰ¦¤"cÝÄГiҪʦ ­°5M Ä8ºå¦ßýœL”ØU“æìÈ;þ�Üü(B�éÅ3ÑÿlÔZ2ÿb1ÛÅ—q|*Â’ÐÜSíÀ :r½P÷Ì�ÿ?=\xT¥E™9t•Íç#8qþàôŸ§ÍkCLÁÂ0ÛÏ’YÛÆ·ŽPÂÏ9—ß}é¢î1.JNÍ™#§€D>©,Y .K-ë~ãÝ«ÆTlp(Ò¾±ß‹*(’6'?ñ¥í¤Y}j:—Ö€ØÑ›¯ïFHn,¶8(ÝîÚMaÉÇ=H»ÞÙµZâY£^QÏØ%Ö!UjQ~P‡’ ïHG$îßåeТ©ãgã S´Že®uœ+g%‘SÕ‚�j—¥AìÞ¦ý•LIïù.uÒ8úcÏü‘•%¾Wù “4ÒDajsÖoôŠ7¤=J^ʃQ—N]m2dŽ6MêÍ¿’lÜ5ü¡l愼(Öf©mÙÌ’_*ÇIN[z# Bä’³v{†‹YBƒ‹¨.J°~¥ü7aîP9ÒA-9`Ñ1^ÒBžà¯š®rÞyÁÆFÓŠ¹ídöÃu2»z:CE$çìDõA|àç .iqÃnyý ;öf/ YVñ©0 R¦Bóiø¿ì¾Ñ ÷Žok4�Ij–0ï8N˜JXJÎÿ»<ºt¤ =2€¹'á$‡7]„¹ðÄëç™+2²m‹!Lüƒ9æ ›”Ô ;:A¶¼â-‘kS*‰ý¶DÛ1©rsþÿÍAß‚\8?‚ˆÛ®ïÐôŠœ÷#cˆ"Þ(Ò>Þ+4¡ˆ‹<{_M&–�vì�âhÇ8cC9þŒæã,,­}[ÕY‰ʆئ °æ"+˜�ÉùŠÚ˜Ü ÊLô ¯“Ô8Ñ­‰Až¹"`³ B¬8ÚÛµÙ£þÈ ýhÖ¥6£ªäo½ÅLçlWdYCVyÿfå™"«{ÏaŸP¯|j–oM¨ˆŽX‰'‡ïÇ—]Âùá™7Õ ö.¬1|�R�:NJ\ÜüIëÐ]ƺ^­³ºú¦Ðý(¥-çjHÕÓºšBPvb$r'AÈô—� �ÅÃY!TAxÇãÎÁu#OæÛ·Mâ˜=i¦ª8OÖ&eÖf‡¬]¶p¬QÜׄ¼‘'ÀBW¶\d¡Ϫ£¬x᜼/6Yù�rÀîDÅOÓɨ”^ÑQÏëªF÷×›¼0Ÿ-áÚ agGW~»äðÀD»qÎS~L ôÁìr œ2¤KH¶ÝÐ,´›Oû¼¢úÛœº×ŽðñöTnsëS…y“ˆ{2:64‹€øþ¶AZT| M ;|aUê+BèÁ¦MÏ$3¦ý¤që¥öSð –\QJ�@ ׂJÈød7êsQ ¡­Lت �ƒ§# Ô2nÊ¢ˆ“§¿¦³Gk¯hÙ7 zÙÒ{1ÈëËþì_é7R�Á4ñ¦} 3Ã|B#³ƒHôül¿b�Ž$h Øso~çfâC?€‚WsêÑ;Fü•곯w;dW9²­{f<òjš/©çøp]–ébtœ¶ôÙaÉÍÏ-�PªK|l/~AEfÀ‚ºJBµ½yæ4A/‘CFAîJÀ…·,4-ôÔÒU¸ú •”[Ññg(ãéà#ûk*h´¸½5¿#ŒªvË­YÕi2«>Zuê@ˆ'Õ¿fæ=mÒV¹}>ê…¿i{ƒèúò®Î z/Á}'«)k ŒS‹ÒÅ[Ùê‘☠r#"n™d¼õž~oÜ�ŠR``¶iÛðÂݨpE=ö¸¦à´¼n/@qä5×í$=›Ð�Ô8+>nƒVÓx¤ `xDÖÁëEQmÚG¨;Mq-[ÆfÞÿö¾"þ-�ú§p“ïùŸ½þÄô%¯nõé®f·Ôú¥…ÃÞÊf0H‘fD ‚‚akãhP¡oö‡f‘1 ï}ÆÒÂsJ'€žº,N3¥GÞݘŒH÷€óÞŸIAË®z´Yòåúš‹äJ'¾”ûÊý¬ZEÕâl^•»½=À2yOÚÁ½‡wW¦°sñÒ¦­„I™ÿ•‘óîÄï’Åc¿{õ-Ÿ°Ì±¹^;ˆ[tB —$±ÅO³p›Dù0À;§MhЇ…ß’€"òa•cÀ�† ×à*Ľ„ê¡L-±¸42ñÅÕš_'’…ûA{�Ùe}Þä.~¯ÍƒÌ@'ö0änµ‘­î€l—€±w=ÓŒ5\¤aZV£Eóüœ!Z,¹(=]˜…(K7è -èÕ$g™ÃÜ…äS™ÙÞÿÎ|’ä]ÅyAî’ WW¬gçªnN#eÓ±úQ+Ç^·Ã¯í°-Ž(èN~Lå¼çFÊèDZ²�(NŽƒ^ð%‡ Ñ%o›,ÏÕ_íþÚ«ˆþFÃ`ÖG€ì-.­ö–Fî�@â½kñ]Í€f ”ܤØ;‡¨±Åt— 8¡/çáfɳ窜v¼@>k'ÿ”î«—É Ý‹iE­ˆ>ïÑ|�5T©ûUD&kn�u~ãÖ¥øy.„Gy&«nÌ™b\N¨íþm§�+®Ë‹£r¢}T£>-®×yÈ–› €ðdR3Ü“áÚ8j)îŸù` „ɰ´‡Aœ\Ñzž…ˆÃ�¯`mÁ²a�ÁR¶ç nÑ}]må)ÉÝXw­>Î+ÎÓvÒå¯Õ~€$Þ ðêÔY—µø í ¼�ÑíÇj“* àcÏG×´£ÊFÜ3‰ê ¹î´ M=DPç‹:©�/bRÑ‚½a*€ªªd LtÂ)Œ°]ºs°øõðD:®ôŽ¥[0P0[+¯b;[Ì ãåBŸ¸Ñ[wå.Û™ öÎ'¹¯Ðø¦ê5ÃDlOó[>+Õ<(æ�Xb_6Øî…‡°ä)Q¾«Õéë{¡G%¥„’¸,éž ´æom_Ì£3 ’\ù—&Ò3è_eÄ×¥ û¯ý.ð=m™ó×%3zš¥[Ð.¼ÐÁÍ[ø šR=åtÞæñ,Uò !ޥžÌLÍZºÙúí¢v€µ½�피ÑjSžjC§ùrõ˜v†>UƒP,¢øì)ÈK›/ÉŬßÓé» —w²Rl(V3Wµˆ+úYD2GvØ[UîÌÍ÷ñBv�¼ËIÏàªz1[y©èØ[%ûÈM´óH¤ˆLŠ õ9C€®ù9ðþ;r(©ˆ†I¼~i\á­È{Ý]ôÆæã²�¬e™`S¥¡ä�`,ÝJÝÖHð£„C¶{˜Š- pwºÒú‚G”¾ÍÖJW?>ì“#ç‰+€Æ\½x�.ðòCxÎø ›þVÏñ>Ù/˜ ‘*À*ˆ/À•ë;Ìç\Ís ŒÔÄïu]ÅÒ¡Üæl�æ …v.9N¿&N²î!'SeÍ‹¹‹zî´yxÕsI |úU¦Â`‚ä#9?×û9Cþ>ͭʼn‚^HÒº ’¥jŽ$(±›Œ62ëÁ¨Éôsj«6UÞ.µËWÇùx=Å£=?_S–rÍ—î¡UQRô±BÅ¡>Šc6ÿm" >¾r'‹›Î„";QVrÒS7ê?‹\Ïo�égæð÷ùìs¨ñø&Éy¤iøò0mw QRcË®u5ÎBœ«>qÓD=Èjù×¥Q‹³ e„çdÔRýÓV�@õhR"j?LGÐbƒ˜6Ðü–s�áb ˜O„Ój-.!¼ �Mü˜ÛPíÍ)Éý†îw sˆ®QzÅ_ÍMs-Ž!wÝGDömg–Ë1â�Õk”è½…Wq@¶£ ÞáG.~ Ð#�y4Ú Z™Æ‰ƒ õïçï-¸A_aCi±¦ô�§³ù¶¶pðçŠ2¿sÓ¨L‘W¶ðèZd;èt'.SÄÅ$É€ì˜T$&<9Â/(vDkƒ¥UÏxû‘8^\åi`�ÝV”]…êÀ ɽi9Úꢡ­†èaF™I˜` uåep¾øÆ_yžé#™Y/6&±»º%ßpœÕS±ß*òõ Þ£Ü[2_Tò@Rƒ"¨ðyV)ÑDîŠò0- ÅöD¡“ÍÏv `†KÆ…þ™Î¤ûâ³âãTzöãmŽ¼Ò›×ɰ¤ß }%Qä!�¬ãhO¾èp>¨ý߃óº}$Öˆœ»ÇŠ´Xíû�¾ <3Àò;Co‚Ñ: í#c¿ oñÔ•Þ`}ýcëÜ--Â�ž¼?/0³†Ojþiîœ!¹µ,fß² yXÁ]vÁ÷‹ˆLèCĸ¨ð&zi0£Çaª€±v:þ2bÍIqžèÌI“³àAÄå õëÖÑ@ïR!ÇHªè¸ÂÇ«d8Q“ªáíò+2^¯èÞ°ZWšñ %g‘‹aÓâ™+ç€- ÀíIš�ÿ}CO²Õ «ÂÐôÖ(×QLÚP/ÑQ}„ë`ëÆÑkrÍ»`¸}œ_>(Q` ëu4d²_¸âÒÉqõÁÒ>£ÁŸWû ÏV̇ZpI¯qÂ8}K®Yÿª€£œ×Ó¶VÅO…½Žºl̘ÈâÛæ<äyTu�tÇti¼£²†V\^Š‚ûî†$tÊ[m’ܺíœ#ÇBâ!Oœ7ì7£BÑm·²I­-ØW…}æßŠ� Ì�zlOjêl´•¸ôf(99v¢)òÚÆîüþ¯™Kjfîÿ˜}·µÂñnÁ|¹æ!'S¸¤Þûôžy@Ómw5fÜvFYKs¨Øÿ ×ÛBS™éѶt+‹W¦=b±úXY0ô^�=�,)%Ú¹ÁR `–sýûPŒÉ§“�ãÀûi˜y!bÊ€sâ1=Ý|¥3g+ÑW»Ä«èiÎå‡Zmåü Á2Ú^×þômP ú¬¬®å¦¾V¥çKMJ‡|~¬*h†¼ªžžƒ,Ö”Vçï&…èìßldyM×su¶ËH¸ƒPÛ}Ô M–AxÆ V0±m&dëÜá¾Ý•°À‹}QÚ’ûAá€ÿ¾5"ÎиgèŸé¦”Gˆ¨‘u¥§Š>÷sy$ï¸0†Ó=3_ª‹Csgþlí©³2"Úuž–1PRM~•Ë0{–4�Ö%º:^.Á„£iC‚»ÚšºŽ#œ+zy whrï;0ƒÑ¦\îs; ó­ºï‰u„=ȇŒ™Xúv¼—ˆ@Ý­À¶›?Z¸œàD$‡š(à‘þ��©O®”±]x çei)˜f:\� PÌ|ýIÐÔ¼Gö¼?ì—% S�+@×>ÓˆþArVÐ3—̽ʀüõ•ß!—Ãîé½ 0j÷s‹¢�(É ù�òê ï܈‡~cëu¦‚掙‹hµ€R˜hKÈtÏ-Óo¯8Æ”F0q©ŠÀiôÄ[󔜦¼¡©WkVìH:±ùBgӑ̵Ý™&鈕ã´¬‘Øàøºa¢-�‘]°äË~÷:y6�–f;Qnì™ÒȈ@)õ5 %¢° ê&U†ê3|Ç GûàÐî– KC5Á QTv‰¥�#’n1P 6Õìç æGˆš1Ù”ï€ÉI�ñMŸ qÎT€‡(p3x8<Õ'Š{{«77€b' »LcÑlSnë­ÞÝhàKU zwß_ÄO=BÌV}`¿ÞiÑx%\3–Œ0n*^çiGàŒ†­ÕûûR8“'•¬yò‘K�‚^ÌŠºš¾ e–st݃Kí$å#O %Ä3щ¯¬}‹'¶'\äáˆï;6æñ•öZÆ‹e°že”(z{\œ\Û(èWšt”=ó(ïZz¡J‚ЏçB/;3D OO&\�À­¾ Hˆá°#žÄ+ÍÒ�]Å ¾ãˆÛ±ä‹ãåyit©¾YØüÛ“(ÌäË±ÇØòÛY¡Ao�ß—/Ú3ÛAŒÑ‹r©Ò9Öè‰éFÒÆ^! dºA¸Ù”JŽìq¯ªDžœ#g›n¥=Þ;²ÿV–ÝZJàˆ.mÈ‘÷ ¡�׉Õð�Óæ‘?AU5Ý�,ýê �¤îNLQ†—4šŸ‡²Ë‡)aìþzK„tfóëUÏ —ðH Öˆ¦U¶šO*¬An½±»ß7$<3ŸþàaHoî'¦þÏs\{�b¹éÓvñ^¡ÓB­d¶r3« AAOCF ª›™ËÇw­­Í?¢°5ç\(‡=KÕf. ×ô¶�8³ÛuI7¿`©Óq^ÄæRàݶËQÞÆor.ÀpZåΜwĦçƒMÄÿw Ü¡· 'ß))=€R”~âNÎ/ 9é°‹4k�4åÔd£ø¸Üü™"…Ù�”ÈV{á ¿BàkaLöǵûô {juÚPEJ&æø/t»HÚÙ«¼ù"!ŸGýêjy¯6?t•µêR^‘³ºœóvxzr—ð¥í¼WN&s²· nøÛ¾õ |aÉÉJ$ò`áôR\àra­Ê{®uÖåàaÐÏ]�ÊšŽ&åK—?‘átÕ$¡Zç#¹ëÏQTÍ.Ê‘ÞT`˜åQ] »êœ,»7ÅÊOËäx=@MÒ ÏTfs�ao(r܃ž lV�(¦°…w©w/┨_º²ñ.¹1v@  ´1‰w´mî§d—ãEkÝUBÛì�C ¥šþʼnèæ1–M*¤o$]ô×�¶¤Rpû@"¸A/±àþ÷/ IsH!Eî#¹§5v‚@µË?�$QY©•¾+ЃQ+A�߈â­qØ@qæû•¿~&ÝQì2Ñ(ë¹TóÖ£Íã°Ãèê ’•Ú/VåÖ.ògKƒCåº=�îDA0P_e3 o0²ªÓþm«2‘¸,%Ï“�‰3i䯦; Q á¾qŸµÒ^,¬yÏ¿/Ù1‰Ë…ëç„ý†OôWé#8öºpìbVÚ9šH¦î“9ÔŽ§ó Õ'¤vrìŒ�Ík1)ån”ÉRö‡±HšV_[•‘³£øìW±~ ¢„Ãâÿ¹+,;²˜69HTR\_\:ŒK“Øb|AáÔõåTUÌ'žÖuNzyì*•žDó| uÈ8è«üZ¹ýkôç„° µƒÙ¢�üV¾ RŠA.O»RKÛ€Æd™Æ4Â{èУÁ/ •à ԷáJ \µN+sÊÅ<þlWÝœ¹£•^ZeóˆHJ³uBs7 Dä¥C„+å�¶ÕsĦå ï ÌhힽιH°mæ“ :)îlÖ È%®e´5{Õ$c1bwÚE&½¨3Øý ío™´Øæ:î®SÝÂÕÐEÁ9f±ø¡ÆÃ�Þaßî­QÑøjn H1I©‚1’i\wjñDÚ2ÐC�7ŽÔœaeªO°2hïî$ë«vÌkdƒ[Ìi¤ÚQwÿdø)K² ��\æ{UZøt‹Äü8LÝV¹„J¨ÚÅ,êK6Kú¹i ¤È°!Òo>H÷bv·uFÄö"ÚÞ?’ªŸø€Xˆ…5]¹q"�ÊP&,kñ‘,ª|ç+œ¦´#”mU‘–è]ºK”? ¾� j*ÉaˆâÙÓ>Šž9ÐÑ>¸r/èj±PebÖ½“ e¯—¢f)$e#'A„Iqñ²½Û»PUöi߯ERëŠ,~B ØÉÆ^©îsG€öêÑAS’ª¨•™O4•¸rtV*�Ü‹ª/ˆCµ30}ïŒÓ„üŠudœ×Ö¦?‹£ãÅ Ãdn“Æ]†¤ÑMUS¡n…QËš�ÿŠ�~\±Ò Ì5T¶eÖ�³|XOÆS*…ï)J2ûÑ'#ÛÉ]·ÛB‡CW¡K"Âæá›õæ·‚úà¦Ã_Â=œÙÇû„o1üít ŠRYôRî(P…ˆÞúqiçÄ. œÜ_�±îb|ÒyòŸ£üz9ü'È¿î'…d£T5#Cqï-ãÉØARÛ‘ R³‹Žƒ`)„Uh%ñ.y“bd=,o°6*Ç�èO�µÄ$a rÎãQ(bLÙÏÄõÝn®RÅ;-Ðß³é,»"ª#4ƒ¸jO ž‹�M¬(ÍFêa÷NKrktãvt,Ýãa«D%­� Ã`5;�é„­k[Ö¤w<å‡þä¿ü¹ÌãH9«Ÿ¢ uvê ü¹±šðýfk˦=ÚwÅ6¢wlß`/VEÄ_ÍX�}gÑtŸ~ ŒÍáË}¦Î:éJfFºÕœ• 1jö½¬'É&Ó�ˆƒúäèHsm +Ÿ5ÖÈ)‚¢ \Ååõ.�Ô\?àž†áãÈ·bC˜!ˆ'" ÊìÂR`Ænû”£(é3?k:b©Ľ 8Ãd(Ü~—Ÿ¶fçäÌ:ŽÉ;«ýÏ;)Œrv†rCØ?xl€L&£§»£õ@ôKûe(ÃĹT;ãX�î;v×í‚€ù�ÐÏ0Ðp°^|êæ'·Êaé‹=¶†eâCþ£ÌFIQüµt¶º`"“yžì‚-ÁZb"¨à˜"¶ä/vZ–›»2? ð4ŸâùÒÜ-³õ:þÔ‚[ùË{$¤¼'IÚÀ`R?˪»ÏlÂúýqó…@ú°‹ÅцҰ22�ßkäÉÀKqÕá<úªÛ3 /E{· UeÇš´ë­îÄk…Z)ïÙoF¤®ŒÀè�÷–ÍZ¶•Œ.)Íî¡�O:WuuV»œF’¨«ä×"TJÁ‘‡e†Ÿíq틸o X Ûö'ÞXEëJžRêØ-¯HrG¼ü‘àÁ³v “ÝIø·U=N�ί£¨ž!ÎFòŽhj‘ó‡Ã±T5ñ††qžbÞT ´”_]Æ.½V2²Eß’lZ›àÏöÀý ·ÛDޝ'ókÁÐ0°bH`<ârxÓ‚œÕZÞäÓ=K‡«G¥–†& bu-ãø&\×e¥JØ„¿�ŽÐÞY÷ôy×÷¬¦5gâ:eh-/Ñ9|çeñ*ÆäìR�6Kvõc±Ìsƒwfg…z•;ÅÒ¿é°OÑ ôDZÛ(E$úx�~ǶaH\ t¢%†Øýâ7§°D�gÔ�rkÅÓÙØN­ËN²çBÚ•~:àñ—¯Ùg?L"Ì[Xÿs¼Рù§±GaIäóü¯Yá0G[&éÀ1p¬"ð*ϼQ�<Û"{à=‡¦£ëOò ¨ìíÛjÉB¢Ä›CÉGËÄÍý¨sx—÷Θ'x¤\¹¾‹°C«‚nÄ_25?�@7.ú1a�¸`ë%ô²½3²­Ç4¦›¢ƒ¢¯ý\•¤˜»ÏòìùJµ¦¦n =MÕ-“ Ð ‹#“ñ�ýtÏÒÑ/#iöT0@?,AÚ¢>ºø~C ]Lr«ÞFä�Fuuq‹Tù^!v“‡ï#ÿ9Pk°Š£Z¹pªß<¬ÜŒ‹?Rwùa5¦¶48¡6ùbïäÐêK]ÍfÒ§Ùô6ðúå¤à/tGù/ä5Íy!�Ž<©IàT�墡YeqŠ"8?•±•b¢Í`Â+º,ù‡ÕÕ¯¿ÆÕ4^uŽÍ@ŠÒD,�dnɉb׌³¶ÄÃgö­ÖPÒ�½6f ‹FÄ£»SBb|ó¦wˆ?®rŠ£Lî´Þ—�¨z¢up�[Ø©¯ê„¶Ã��*F¡@Á�=R= ÃUßýª[è%Ëptè„#òcE4þˆ\z‡�B6 �f³VaYÙ4û=¿*™ö<c‹QÝÄœbd�DÎeÔóE±Ÿ¼5(éÒÅLáÙOG™ÂÄÑã¼fË´>aºŠ �è ¼p¹V2Ò#îµ;JR{ë\GßW6 ¸2••˜HÈt UÙI:FiÍ�±_Ð@µB�ù…Skø\µÿ ÕfY. _x¥Fá±úó⎓M­Î°ŒC{0h P¨¨ªH _ËRàÔ¼4KãþM\$c©—œQ;�–XÖz.ÿ¶JœôvyŒr äÕê…e#â¾õ‹0ÕBÙçÂì»"f+¶¤OåÇm_0äß«>ŠS2] OÑ‹s,ßÈäæ|–93æÅ)‡Zc¶!B-mQþÉá÷©šªP‹O‡­AËFÈàÇ5̹I:_£:Ö$W¶t˜o Lc•°)ùW3`Íråè]yœªFåtZ·0e$†zŸ%”³2Ò¦Sny†xØH®I� Qt4¿Áeê gŠœ I™Q0 ²jZÁœ89¶¿lR­oràŒM�Äœ�_Œý¼{E!Û­fHÇhÆ_JBçéû�äã"ž»Hí«­•ЙÑYο5á_×j^"ÖÕc¯Ó;¡v÷§Elþú3ç6½]†¿&éÛŸ=Ý€o(êJêß~82þ\VO¦9´–¥ÌÑ»{™Ž—�š‰eoÍþl›wÇ5DжSœÿ:;3ÏÌ”,íÉaÚ»“?ˆ‚ì`k%plä9 i¿ª˜óç°]xfnúˈÍ&Œõ_e¹ƒ"3Qa‚”ÆäÇ›�vƒb×*m’¨ñK>£âþV}å4veõq3ЉÕ~4%Éÿï®{òb‘Rö—&mÇÉý“ùÄ_:Aa@™”>~·’ÿP±DQÏ—í`ñlˆ®HºH>óbó}jï±\ãÇñÿkh"Eê¶)½�øú'› \.#0û3oV ¿jR’ܺܙ†³5"ØWj`ôžv²í!ãœH=`r3§þÙÈsðéâÅ´Š[\’ªÄ«ê§ÐMùþ¤ÛÝ×!�Å{F'N¡Z%è(’s*©ÏFB1ÈÀ¾®éZÛej »ö×»‰RùÊÅ_ùŽ7ûJÏ ‰ñh¯÷Ò £ƒ®<�¹<ˆ ƒY´¥møtEêUv¸Ãç8½ë¼µãe$LF„¾@˜n)Dzë™W§#·T«ò"Ž(I2V¦ÚyS”/Æ$ î*åyé)«_ðìªi2Õ¢‘ÄÛ€$GÞêÇ‘-W$À©]ÂXxÕs@ÿéÈÐf,©#‡ÖŽ}g'“·-¦ÒƒH!È%JùJœ ª¹.¯BÅ{YœæÃ¼lň|ø¶îÑ.,×ÖD°Ò‰­CÄ™â�_vq-Î?ã*‚è"§s8àö��uœ‚Ì·Ù}P§Ån´DšÓ³(8a`I²+6`âì‰\FÉËíœ}FN=óuØWÅläù_¿ÈMöNWl¢xBÈr±e�6"ÃÙÙ�¹µ2­d‡<Ï�ÉÚê•W)y@èíUz5ȅן¼ ¹/ÿŒ1 ‘¯„�ç±M+ç lþ‚á#‡òs8ö·u=õ >&Æ4VOþ²’•\%h²OI¤²ôf¥7þ¨×ï*ÃŽ-÷4 Ö L›_Z•žæW€NÁjv(©ª©Ø_ô×¶k®XÄf¥ãÀR¾y£’î C†ÜCTU(l�¼¡ˆ¸âH°ØÍÁFO¸LùŠnðÓ'ŸB9¬m¯ôÍÖ¾Ò©{4/kG_5÷°Ú‘«žfI…ËdºÂl­Ø9ºˆ<Ê`4åÉz£¯Ù YbÊê!: g§_#Ö‰ Ü^üæûÂ{-AÞo¬æO?r±ÔÝ—ïj¤º·Õe\r 4ù^öÍb�¢Çùïmì5h={½ $*…X-?�75éBîmAÏÁFoL�þBP��ØÌ§fž 5eõÁfº´Y>'GìÖ$×>öb�ò•¼�,Zé[„ssТTp5óÙ@kcìôЗ@ ç¡gÐjJ`ÙÅ+*¹�·-ï…‰ôŽÏ¼¡.‡ °áw䴱Ⱥ@Iiî#óþÿ'<})M¥&ýÒ€¿Ý2©�ÁùëïFoG·Õ ½faîkìú¤dT±VC‹0~°lÕäIܘÂ&£(¸µ†±tíðú…OàÉwÝÐ êUÉB;$É¥ðà€<‘ðâC3 9â¬Ç6ãtÓ5’Ö+s<;§ï”Ûˆ ÀHÐ,À©Ï®5_}“É"%gDóµK6‰ÊbÚ"ë4Ú164UDŠc°$ù.⟒”¢¶XiæÏ%\X�Ý/Hر°MüŠ˜ø Ýõ0q WÑ„¨È®V\zá;ü¹ÉòDš á0óbHšÙÅ; úý@ŽW£›vÛY^é«|jÍ7÷Tø"­è�&Öa(¤Ü‚{c¤qôÎ*0+öK÷=ž½ù®O õ%&É,A.àÏq‹…£Êp³º#¾pWõôn>Ÿ¤·ÒóŠ?™}}pŠ�×Î@,\-dð>ùçž É)�VÙÏ©V)-½6CÞ_ë~ˆãòuß•ìyxâsäìÅgl™¢ÜŸèÂü*œ…ÈhÿEH4¹æ5í�¯\aµ8àoÆ„_�¾.ŽJ�~#:c ï™d)ò<š®sê"‹Ò2!BÌœÿøz ÿ¦uB’ ‰é‚æ;Wš«x,„$‹HnÈNÛ5�J«ne·ÓïX‰ƒZî<II ‚ª—™@ÞâbŠLÕ,p;Pbèd¢½Ä:0)`d7zlËB3<”²öõJµ!œ×A¡'ë5#Òäe|Á6H2fà¯(q<˜×/fñ@^0µvÔ}[ZË8´ºÓHê1ãPRƒxŒª@±ß”û~p”” ‹‘’…RbV[0&i;ÆbŒŠ¿I FìÉ ×ç{ð° ÁÙÑ5R¤Yf&4¸ÐÚiXê&IîÁcUóÏ5QW�NÆL­]-‡A¿ãšF?äH¼ZÏw*HÁìIS/±•# Žé„ŸhŒsÂ^¾ž³?Ú¤o”ÓÒŸézC�©ÑËLI}€yMqYCxkE«8ðY•þ†ò-ã¼#1³àUu·‚è_6…Ú¥Ú± I¥ÌŠoèw>IKwÝxI~jœnsÝkÈø*u3D9•�Ü3¢+ºáºÖI‘‹ÞœW!½�ÃÆ¹ÃÇøD*‡ÿІ€Xµ@Ûuqºp§Õ«W+þ$C Q„µÛ¾­½�[…ÇÙiC5â8Zã( ¢bå6x�­k­ÑÅh­Vé_­ŒïÈ.±ö”ëÓÙÇ8Úo¦SÀÒLYBs`XÙþcK«Më’8ßzÈ•.·Úeœ7E»oh—¹d‹Ø†®r4£ìQš[ŽUVx¼?w«pPÒ::�¡•ß|Èe=�€Öâx¬Žç¯ÎMózô)ÕneñŠ5À(rðÞàyԲѸˆ¬×p¿ÂqlÌ:7%) …¨iXJ4JY?b†È(|]:oÒmpÁEˆÝïì`ô:矿¡io�1JóVYyûI¡Ÿð�â¹Ì¥ÓQ òw´Ú©úr¼Á%Á>=¬*½�¨[ ÄŸRò�uKx4jš«Ö^Lì¹�¸ãŒM96Ò{5Ú=¨5̨Ù/Ír³©ýQ©wo/Êy7˜LrÙNVØÖÔ{ŠW!6Á”S”wÛ�q‘\ç«lËÆŸ3‘˜·F?ž–¹@Zï¼â}÷m4�!àÌ,z+ŠÊ€êža“|‚µ$ÞÍ\¡O�DAÊQEsB1i—÷J¬&=!uýªÍ'a 6² µ=1_¾û¶kÞ¨/TS·–Mã3TvÕ°�¤`ƽښïZp{¬8‹Ì3ÿÅ@ 2ÀÂkíŽÑ Ô¯J@÷79Rû¹<˜¥£Ã(×!VÏ[¾džes«?âÄFþY¹˜•z/Ìk”çP°ÒµË¦„ίŸFÍ*÷ëàs¢1—$”ò ¤5œa¿ÚæÏo|P?º™\ÀøÊÑ2v|j�ȵãe>,¼Ž¦‘ýf, êRB$•µ®�ögª±ZstÛ•;O ÓµßÔëk‚�ÛzÊþºWÞ !ê œ½ŽÏêÈ­õÚ¶ŸÈ ÿÖ]Âʈ]�ƒ(pÙNû87œaÑ äŸ•¬kçHÞ®àrE¯ïœ°l�E”^»ò�LFùùÁ¼1̲ý£)E%úVà{%¥¢èoµ6yùÆ£ñq÷ É5Gö©¯xJLíOq¦jþ‰gV¿¸?öE¬Å-ñÑêõR™‘Wؤ˜),fi�osßM_°L&/'zG‰ ¤…!ÝÒ˜7�þMµ4�¢Æš3¿÷"¸„ic£JÂì¹45—[#£¢-…‘ö,‚îêüe—€ï%Å©§,»fßr ßj%Q'äcé´ÕæKÃ+Á»’˜€Ÿ­-‹«§òô¾¡ÂU™†Ý]ÝpÊjçIüý b& ®É›®|•jyþm{7^Í(ã dëéó\öÅ�­ËâÚ’"x,”he‹§M¸˜¢¿e¬ÁK‰Ê[êÿOËΰtÿfïx:|âŠBéoÀ�s¯‡?™¾Wœ’Qf £qè§~hDažŽÌn’ó)§.C‰ü¥´¶’T÷Ʉ̼ØÞ»:š½QÍ\1  cö£†Z$uKŸC†I´rƒ¼,�:²´†NmkDƒù˜ûj;�ºÉŸt�Äxê>€ŸAÅ,jPsêñ2*Þ¡äù¼¯gØ›.‹0÷ö›92ó×kŠ3¼ÇŽ/¬5�`=‚+{x¼·×þ“¢Oòæ×©gdH� zÛD=„7ÿc$§u}¼s."°Î„Rw±©£¸iF%M=| ûôuà;9Þ ßÆ÷öê41—çÏ$a²ùößú{a¤ñrˆþv&,Ã\›oHmÙÝ|ÿ9i-s�p£z%Î4I3a5-ÈNV©JJV,®uÙ2x ÖÆÊƒ!Å6Φx̦÷7‹æJÞ‘yxr›‚Bw^Wwjß²¢$_’�>åØYó',…•Þd#²ý$,ÁJò~w8°yÈ0íQ†1¯ì((óà‚ Ÿ¸*ÂA¹N¬èÏü8¹S¹ wx@·ëKx³©£*åS7—‹z-ZôÑÑ8ðí©¼Lrz¨:³¨7Úåa0.s¥S = ÁžîÍËv´–95×�ü]*îHÙ?¸�°£¤?"|’ØL¯ÛÝÒ/XdØS¥š˜ÄŸ‡}ƒY'.Oí–³&õiÁ¦‘nä­~éHúwnÐT"ðØ”?o™6:évÑ´Æ8\MvôÏ5;|¾X ày_XæÖ¦«žÝÄ®db$a>úÂ.ÆûôË‘È-ñ¾r³È: L¢ˆ³°ØŒÎк$&÷ßÉN)’Í%ùEô…¢%/ÝE-l– àJ*=ž4’s\Qм� ¨kUÏ+U—$Tm½±¡ÉX¼(§YÛ×ÐôDû,!àêlc´I„ñ”¯0€÷yѸûrŠSXžñ?†þ¾œp‹ãFFHå½û€+Gõµ�lzÆÌjÞßk£`©uÎz‰í‘‹À{d™ ŒÎýƒó`Cz}­Yãð¯‹ÔnD Ä~ìᚺzt}'ã�H&Td[õE.´¨¢iôÌ!UQ˶˜# œIÍ9V -Ø�@÷@zî¾*ŠÄáC럽�a˜¿º%,»Ç›sÿ’<îàq–µÅƒ–[òé}Ãñ÷±a`\ : »T–HÄïÀ»u=w\r.ò/4»­ŽsדÞ9ÒdŽàªy[AÊâ´W!}tNç£sØÿ%®8!¶NÓï8ƒvƒ¡uKgKb(ªo #ÕÀ«Ûã4?Ån@r„, ¦û- ÷±«A®Ì*¢�…¦‰©Ã£¥ÞˆãÓŒ¼$ˆ[S`´¨™œ9iê0-I但euŒêŠ–!\®_˜w‰¡…ˆ3Ö¨Ò”æs·;ºq2›UuÙµšÑ…ÔyrsæÁÑc &Ë™Frßk�aUpFNmåcòœ°GN0[[/.„A¢\z1<ëôwrpÃptW2ý‰ØÌ¿lW Uô©©Wyl •¾ÞO$ó ÛÀIìíˆË—ú¬Bÿ«ÝOŒ¨É¯vàn ¼|Úì«ùÁ@^ÒÒôè"6UMŠñ¾Šê-UoPݲ'‡k}Ç7²VPV+ä¦,c¡BLß�Åk\_±Kk·¼¨úÝ ÊzåÒ‘f¦,ó›¾$=ÿ!•›sl¨pÝH#”—Ç 5ÁO¾ðÄ27Ž£ž�I^ É#Ή¾+¥_=�ùÅ¥Îõpu³†®Ðý0K¡ §K�(K¤o·­gÊ­„vLGs‹ŸjFo’‘„"„‘R»ÌmeZ…qW$�ÕCM`à#ìÝ]€·myn`Øš�lj˜׎E¡ó?ûNDdöÖÞ‚ ÕHÒ£ÏÎO°QŸ*ßyHD@Z–üšÂr¶án$€‰·øÇ'Pý3¡˜¢ÛCBD¿/Ò…ÿ޲B¨­ úúó'Cr›w4åxH²¢óý)ì��ms\‚\ݘ2 �Æÿ°LáߟT?p¸ß2™"4Ò>À}Ý·TÝñK+™ÛÞH@͹×ï¢Ø]faAÀÔvÝÎ)Þ'í„•Ç b'ÐK2§Ææb ¸‚`çûÇÿ½î±þ-Y`•fÒ6ê×9* .ñDrÛÿ¢}?Óº^V�¡‘²ÝÉ@µ”VK7û„BÒ¢|üŸÇ®_?÷ؾ4xÔ˃üÖ~PgZäõg�¯ó@ET o å <¼_OÙ&O»<‰Á®€¿W‰$LñT>ü7½�aËorƒ7œXÿ;Ø Œò· „œ\Ü–@” �¶&H ÈÏÜ5¶·ž "c5¾£å p¶ÈÎ’Zªd-1ð7骀Þ0ùáu*;ÀôºÖüSIYŲì~5‘6!»‰æoÏ=&ѵð¿‡ÅFvm´Ù«ÍeÆìë² S@GÜ:Hs½ŽF‚0Ô\HUSÕc»O_ž±µ“Ö3Ó6!Š�2eô#(‘#•©”Ùìfâ9$¦U4FÈÍÛ´õ`lðÒrþ˜)£ñ$Ö"ßÍ6׿�jlqŸã«=þ›Î\SRúÊ'>ÒÌ¡Q¿2ƒˆªó AÉeîEnÍó~{ æ|ºØ®TçÙ,Csu¹;þo+Ô€EàëløJÃ¥I)ºË"öGœ ’±¸wÃG$ö@uGxum–˜Ê!pŠ9Èr.5n£ÙL"ïoÇÒ2…+!G"ú—–�y¤µH�{1‚#®Hb*$ÐÒÊŽæðüZÕÚ¡é80)˜(íÐ�§Ð÷–jÆ *Å#ó‹Ý“í[˜šË'Éj&~6þjê + ¯ÓbÖ<×B‡ñáiR¨?N™1ý–nnØòû®Þf�Qè´óÙ�fÔ{ ØÉ¥£™Âì�Y"Üc\¨£Î�ç:ënfb7ôbbÍ�¢_ ¯ùãAˆê ´Œµ¼rè̿Ղ±÷ëÓYV–éšêà#Úì=_v¬+‘㱘ºˆ†¡³ì”=EvØA‰'�Uî¯ÒÐÝ´Ñò`�= ìGä+xÔ�(£úÒV¼àPú,¿_9˜�PÍ?<Ò3ª‘þ£vÙc£ë”îȄԳÐiÆÇ=kv¶,( ŸÛ9lÉËÏ‚«à)U¶›t†'hÊñ °J'�@Èc_<Ÿ¼[* ®b^Êe—GŽ5êÜ]£4‚�îY¨{ýÓPæè>q~ß‘õ_ÄüV`¯ÝÕY Ð¥¢›xQèÛét,Y á{Ó®è[M �¯54~¹}ÐnxºUèwC50Œ·Q?ÈÁ\S-sšC%ý¡ñCT‹*¹a#–ôµTÃQLÞ*ÄoÝy!èt=D;4k¦ÎO·ËÚY0Ì'%:à �äJ.ÜC%ÎX÷C€ö|G?³Àèènµ†JfHÏ1+ˆ1�k4¯V;“|j5%­T�«¶Ç擆›{ÀªôœŠ‹ÈѺ]E�B •)xõ_ŠV¤ña887áGú4ø¦ ÆÍúW̓]`Ó6Q}ª®‚!}%xmÉ–Ëg“}>@±æ¤›|à|"n¦7ƒ*‰%î’†êcޝêNp[-SeÇW9Š!‚ð‚ÇCË0@´îç×ÚS$Ùì?ñ�D¡=ü½kS¶�Ðyn£ ¼Ãtþð%†ß­Lí¯a�’èÕ1Ƶ²Ôbeetbox-beets-00724b7/test/rsrc/discc.ogg0000664000175000017500000002116215253035401017570 0ustar pieterpieterOggSþ–ç=݃[vorbisD¬€»€»€»¸OggSþ–ç=^¸µÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿ2vorbisXiph.Org libVorbis I 20050304ALBUM=the albumARTIST=the artistBPM=6COMMENT=the comments COMPILATION=1COMPOSER=the composer DATE=2001DISC=4DISCC=5GENRE=the genreGROUPING=the groupingLYRICS=the lyrics TITLE=full TRACKNUMBER=2 TRACKTOTAL=3 YEAR=2001vorbisBCVcT)F™RÒJ‰s”1F™b’J‰¥„BH�sS©9לk¬¹µ „SP)™RŽRic�)™RKI%t:'�c[IÁÖ˜k‹A¶„ šRL)Ä”RŠBSŒ)Å”RJB%t:æSŽJ(A¸œs«µ––c‹©t’Jç$dLBH)…’J¥SNBH5–ÖR)sRRjAè „B¶ „ ‚Ð�UÀ@² PСЄ†¬2 (Žâ(Ž#9’cI² ÀpI‘ɱ$KÒ,KÓDQU}Õ6UUöu]×u]×u 4d@H§™¥  d Y F(ÂBCVb(9ˆ&´æ|sŽƒf9h*Åætp"ÕæIn*ææœsÎ9'›sÆ8çœsŠrf1h&´æœsƒf)h&´æœsžÄæAkª´æœsÆ9§ƒqFçœsš´æAj6Öæœs´¦9j.Åæœs"åæIm.ÕæœsÎ9çœsÎ9çœsª§spN8çœs¢öæZnBçœs>§{sB8çœsÎ9çœsÎ9çœs‚Ð�UA6†q§ HŸ£�EˆiȤÝ£Ã$h r ©G££‘Rê ”TÆI)� 4d!„RH!…RH!…Rˆ!†bÈ)§œ‚ *©¤¢Š2Ê,³Ì2Ë,³Ì2ë°³Î:ì0ÄC ­´KMµÕXc­¹çœkÒZi­µÖJ)¥”RJ) Y€d�AF!…Rˆ!¦œrÊ)¨ BCV€<ÉsDGtDGtDGtDGtDÇsUõ}Sv…áteß×…ßYn]8–Ñu}a•máXeY9~áX–Ý÷•et]_XmÙVY†_ø�åö}ãxu]nÝç̺ï Çï¤ûÊÓÕmc™}ÝYf_wŽá:¿ð㩪¯›®+ §, ¿íëÆ³û¾²Œ®ëûª, ¿*Û±ë¾óü¾°,£ìúÂj˰ڶ1ܾn,¿pËkëÊ1ë¾Q¶u|_x Ãótu]yf]ÇöutãG8~Ê€€Ê@¡!+€8�$‰¢dY¢(Y–(Š¦èº¢hº®¤i¦©ižiZšgš¦iª²)š®,išiZžfšš§™¦hš®kš¦¬Š¦)˦jʲiš²ìº²m»®lÛ¢iʲiš²lš¦,»²«Û®ì꺤Y¦©yžijžgš¦jʲiš®«yžjzžhªž(ªªjªª­ªª,[žgššè©¦'Šªjª¦­šª*˦ªÚ²iª¶lªªm»ªìú²mëºiª²mª¦-›ªjÛ®ìê²,Ûº/išijžgššç™¦iš²lšª+[ž§šž(ªªæ‰¦jªª,›¦ªÊ–癪'Šªê‰žkšª*˦jÚªiš¶lªª-›¦*Ë®mû¾ëʲnªªl›ªjë¦jʲl˾ïʪ)˦ªÚ²iª²-Û²ï˲¬û¢iʲiª²mªª.˲m³lûºhš²mª¦-›ª*Û²-ûº,ÛºïÊ®o«ª¬ë²-ûºîú®pëº0¼²lûª¬úº+Ûºoë2Ûö}DÓ”eS5mÛTUYveÙöeÛö}Ñ4m[UU[6MÕ¶eYö}Y¶ma4MÙ6UUÖMÕ´mY–ma¶eáveÙ·e[öuוu_×}ã×eÝæº²í˲­ûª«ú¶îûÂpë®ð p0¡ ²ˆŒaŒ1�RÎ9¡QÊ9ç dÎA!•Ì9!”’9¡””2ç ”’R¡””Z !””Rk8Ø )±8@¡!+€TƒãX–癢jÚ²cIž'Šª©ª¶íH–牢iªªm[ž'Ц©ª®ëëšç‰¢iªªëêºhš¦©ª®ëºº.š¢©ªªëº²®›¦ªª®+»²ì릪ªªëÊ®,ûªº®+˲më°ª®ëʲlÛ¶oܺ®ë¾ïû‘­ëº.üÂ1 Gà @6¬ŽpR4XhÈJ €0!ƒB!„�RJ!¥”0à`B(4dE'C)¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RH)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ©¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)•RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”R �Šp�z0¡ ²HŒQJ)Æœƒ1æcÐI()bÌ9Æ”’Rå„Ri-·Ê9!¤ÔRm™sRZ‹1æ3礤[Í9‡RR‹±æškVk®5çZZ«5לs͹´k®9לsË1לsÎ9çsÎ9çœsÎà48€ذ:ÂIÑX`¡!+€T¥sÎ9èRŒ9ç„"…sÎ9!TŒ9çtB¨sÌ9!„�9ç„B!s:è „B„B¡”ÎA!„J(!„B!„:!„B!„B!„RJ!„B ¡”P`�@€ «#œ�²€– R΄AŽA� AÊQ3 BL9Ñ™bNj3S�9�tjAÙ^2 € À (øBˆ1AˆÌ …U°À  æÀD„D�˜ H»¸€.\ÐÅ]BB‚X@ 88á†'Þð„œ STê àà ""š«°¸ÀÈÐØàèðø8>€ˆˆæ*,.02468:<€€€@€€OggS@–þ–ç=ý‚å'02310276;:?CCBl…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹¬Ø%ô B8FkF#ëœzÊýýžåJI`Ÿ76BU5À: š†îK.Þ[/IÀ´˜˜€Ž€ ~ÊýýžåJ¼çÛJÙ@!TÕ€ €z wPˆ{@Û‚š_,ß5ðè@ 4>ªýÿüå žík¥°@!TUè40ÑMtô™àÉÆ+ÚÙÁ…WÇуàÐ>ªýÿüšäâvy¨…PU¡ô…|G×�OӱЂ††�ÊpBÀ&€>ªýÿüšäîô4ª…PU'Ð@$¸O}�Ç%åMÒ;†:€ žä>ªýÿüšäÒ´ð&”ªÊ* @t𨴯ùçaï¥)t (4 ƒ˜šýÿOre1éM0BU 1>ÞY(¥ÚsYÀ&-RJgè¡ÕMkòØÀ‚VšýÿOr¥2ØåIØUUÅ@EO5š‚nE~IôÆÓ´JÊqØ)d¢U)°$ @šýÿOr¥28åMèªÊj ÌY�¬"æeç…d×Ôdþ‘òcw¢ ±“¦‘€d :šýÿOr¥`°Û›¸TU:Ì]¹¤¿\Ïô³\ÏÒ{QFH4¬T05Þyýök”‹2¸ÛÛXaE…P + &EÒæ^ ô#©”¶&Ú!ir}Ï””Ωaku¨“)lY �‚&˜ HÞyýök”‹2˜íMP*jT¦Þ1{Ã�1^_Y•¢~vçt×ZŸ}¹.ó­¡£ª9“5\1á)èàÁ_#ÞyýÿþåR Ny“B1ê,˜r(¶Øò³4ptmp sR›¦£L/g9‚èÞ?®Í0—M)°”,ZýÎu¹ƒ‘Þ8 4´X‰ h©u À÷ßÒ‹ö~>S£Èü†ý$=cr¦Èß7²ü¼öŽ¥ÏÃŒóù0ƒÊ«®b¥*¯ß·þQ�ÿŠá¨Y4®#öO¤Å± Š«=¡ P{údX]ÎÔýÎ59 £¼ „f)6ðÖ”³A`fœ“€½^�Ä!ƒ<©¬˜i0/d¥·?/Ôh³=é«m¤ò¶Þ­™ž��wÛÕZ:Ý–ÿ‰�^®¦×Ö‘&uVwû’CÅ_Åjð-˜mŒýÎu9 %½ Ð"++IÀ@âÊAGÕ�rý5]óo”X€¯/sãÎ�\ú çHÇ‘ÙqoÅóÈÐ3ú.+¼ð¬qÖ\E�¬SF’¿1R-à"ç ÜI¦ÏlÂjÂɘÌìæˆýÎwÙ4-= Ĥ¼ÌdÀ¢ÐIà,1æ8‘qü]âj­_è÷⥧Թéô''ïsçõu|‰ìwûæ¹ÅÇë�³Îå‹�/ó¡<:�0ÑÛå$¡Í½'—3Œˆí®�ý ýÎu9q­< B¡¡ËÂÉg�Pà€~57kg§P¿d´]�ÙÛü¹œÎo¿’_Ú¹Js)êã5÷Òä¤Åp–ô•õÚc\^;Ç¥QåtFôbˆ[D®áì §­“ýÎ5¹ƒVÞh’ʦ¡°@vv¿´ÄN˜¾d ¦²²Ki*¯u67[˜`&· 'nV‡§¯‹“ËÈcºt“Ÿq’C>-VþFŸÄ¼VÙ ]êïtGNÊy49ªéaœÙMãýÎ5¹ƒä�¡Xd‰‘\%`8�'\àÁÁû5ô�7‰M?/'x‘,ׯ×}Y¿Ž½nmcfFU)¸¸ð“‡0ÙëÞ¾ÕÑøÚ��·•êP[©+T²ûë¼ý2š\ÍüÓSœ ÂG.W¹èX©;·åUFÀhkôo†FØ/÷àÂu cÊ:ýÎ7Ùƒ–Þ8€˜š• ›0Ød7•\´×vÎ}ií½E«MÝ M3‹Š"äðºÏ~µ½b³¶#Ah©'òR‚ÑÖ&y,]~�MG“-9¶#8…þùäë¼�#s/yýÎ7Ù8ƒQ¾1ˆ•Ö%ˆ8€iup;š¤_I5…ÀÖÿ?»ØÄ&òÒµädu¡n±{½ï…é!‰Ÿ»:•¬Ï…úzÅU.25žBÉ–+Êèq0ïîQ®*/CUë&^ܱé-ýÎ59q#} „&å68ZÀ€ôлt3ü´WÜ™ohm™äP»-¨Y?Ç{ž°êŽLXø8&MöØ f%ªO©›÷NÉ”‰Íͯ®b¢ì½›ìÎÈPw¡ëWI;–ýÎwÙ(ƒ–ž„*hRdÁPL�Kºá?7œ�I—»B��Á¦Ñ|_O&±arúäºvQà$¹k×°d­Áå²l­Lc/["°R#lcú,èVÀÝ�Š…«äàHïbz¬Û{8˜TýÎ7Ù8ƒQÞ1ˆÉJQ3=HÐi—� ‚©æÊì•ä¸óM6¿ÝRmöµ|fê «ö’ôÑZ*Ìü(NbÎÑÙ&ç²ýÎu¹ƒ–ž@-jIÁ…&&èh‹o\ˆœ‰[¢ÆüJx2ÝÏÚ ^Cí7^:«YGcF¦òO}žÝºž‡ƒž�™‰°±<É~¾¬2Pâü"SÔÞ‰íõªÀö™!Gæ&ÛóS’‰�ÎI…¨ýÎu¹8ƒQÞ(BÌR¬H¦Ð‡YB,ƒ’²-oÅx3CT§XÈèòßÑ| éÈÓùÆûѳ^^ª„^‰)5=‚%G½pïb€{fy](€>(Ö÷:;ubjÙ:kGG:OggSD¬þ–ç=‡¿²¬‹‹‹‹‹‹ýÎ59 %½ ‚”. :>�þè]µ¤?÷TãÌxL€çsÔ˜žM›PÏXšÁ„—+q!^#§ÃaâèÑ|S«ã.�„™ãµ•«Q®%(Îsnå¶©lõ]”N-{~ýÎwÙ8ƒ™ž0B“b…qÄñ–X9vñ)l}¬Å¼�b‘Id=!û…t,W¢7Åæÿ9±¸õñ­Ûÿâ® Rñˆçƒfƒ©ÄÀoé<ïËÓ—·§¾UÚe±”׫üpõ0Úé[(wÉÎ"…ýÎu¹8ƒ–Þ„2h–¢"hrðÈ)=|éP›Û"ýr:Iò"q�ö°Ì˜è¹¨š¯à޾Rß"à€"«•uÞ½‰ þ¹Ú‡¿š.øAsñ©Ïˆnµïn7…£'òèeŽ~ ýÎu¹ƒÞ0B Í c@2 °8èä>h»ï_6ƒzyu—YÆü|$Ô•»¹Žëö¬ÊÀÅ…÷ñSìÙ n'E²0!¸¶²ö>~v3üayè™zŸ›9óMÔk ¦1×5„éW7ñ#ÞežÈiýÎwÙ8ƒ‘ž1h–bÞFh‚¦zmœòp4<¯å²é*é´ ´ÚäœÉ"N¨„ªñ|oâSðjl’ÌôøœxŽMqIß–Š'S´Î—WøKw®²:&U0TÌn;�‘bbž ÆPÈeýί² 8P‹<Üà0P8�Ó¹­j xz}]�Übeetbox-beets-00724b7/test/rsrc/unparseable.aiff0000664000175000017500000025432015253035401021141 0ustar pieterpieterFORMXÈAIFFCOMM¬D@¬DSSNDX�ÿÿÿþÿþÿþÿÿÿþÿþÿýÿüÿþÿÿÿýÿþÿÿÿÿÿÿÿýÿûÿýÿþÿüÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿþÿþÿþÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿþÿþÿüÿýÿþÿþÿýÿýÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿûÿþÿÿÿýÿþÿÿÿüÿþÿþÿýÿüÿÿÿýÿýÿýÿÿÿþÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿúÿüÿÿÿÿÿýÿûÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿþÿÿÿÿÿÿÿýÿýÿþÿýÿþÿþÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿûÿúÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿþÿýÿþÿûÿýÿÿÿÿÿþÿþÿýÿÿÿýÿýÿýÿÿÿþÿýÿþÿÿÿþÿüÿýÿÿÿþÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿþÿûÿüÿÿÿÿÿþÿüÿûÿþÿÿÿÿÿýÿûÿþÿþÿþÿûÿûÿÿÿþÿüÿýÿþÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿþÿþÿþÿÿÿýÿûÿýÿýÿüÿýÿþÿþÿþÿÿÿÿÿþÿÿÿþÿþÿÿÿýÿüÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿþÿþÿýÿÿÿþÿÿÿýÿýÿþÿþÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿÿÿþÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿþÿýÿýÿýÿþÿÿÿþÿýÿüÿûÿûÿýÿþÿÿÿþÿýÿüÿýÿþÿýÿþÿýÿýÿûÿüÿþÿýÿûÿüÿüÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿüÿýÿÿÿÿÿüÿþÿÿÿÿÿÿÿýÿþÿþÿýÿÿÿýÿýÿüÿýÿþÿþÿÿÿþÿüÿüÿþÿþÿÿÿüÿûÿüÿûÿýÿÿÿÿÿþÿûÿüÿþÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿüÿÿÿÿÿÿÿþÿýÿþÿýÿüÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿüÿûÿýÿÿÿþÿÿÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿþÿþÿüÿûÿûÿüÿþÿÿÿþÿþÿÿÿÿÿýÿýÿþÿþÿûÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿûÿýÿýÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿýÿÿÿþÿþÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿÿÿþÿþÿýÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿþÿÿÿþÿýÿýÿýÿüÿÿÿýÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿÿÿÿÿÿÿþÿüÿþÿýÿûÿüÿþÿýÿþÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿüÿüÿüÿÿÿþÿüÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿüÿþÿþÿÿÿýÿþÿþÿÿÿþÿþÿüÿÿÿþÿÿÿþÿûÿúÿýÿÿÿþÿÿÿÿÿÿÿýÿþÿýÿýÿþÿþÿþÿþÿÿÿþÿþÿýÿüÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿþÿþÿÿÿþÿýÿýÿüÿýÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿþÿÿÿþÿýÿþÿýÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿþÿþÿýÿþÿýÿþÿþÿýÿüÿüÿþÿÿÿÿÿþÿýÿþÿþÿþÿþÿÿÿÿÿüÿüÿýÿþÿþÿþÿÿÿýÿùÿûÿýÿþÿþÿþÿÿÿÿÿüÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿþÿüÿþÿÿÿþÿûÿýÿýÿýÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿüÿüÿýÿýÿûÿÿÿýÿýÿþÿýÿÿÿÿÿûÿýÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿÿÿüÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿþÿýÿüÿüÿþÿþÿþÿþÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿþÿýÿþÿýÿýÿüÿþÿÿÿüÿüÿüÿýÿýÿüÿüÿþÿÿÿýÿûÿûÿüÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿþÿþÿÿÿþÿþÿþÿþÿúÿûÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿþÿÿÿþÿþÿÿÿýÿþÿüÿüÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿûÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿþÿüÿüÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿýÿýÿþÿüÿûÿýÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿþÿýÿüÿýÿþÿþÿÿÿþÿüÿûÿûÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿüÿÿÿýÿüÿþÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿþÿÿÿÿÿþÿÿÿþÿþÿÿÿüÿüÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿüÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿûÿþÿÿÿþÿýÿüÿýÿþÿþÿþÿÿÿýÿûÿûÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿüÿþÿþÿýÿþÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿüÿýÿýÿþÿûÿüÿýÿÿÿÿÿýÿÿÿÿÿýÿþÿþÿüÿýÿýÿýÿýÿþÿþÿÿÿþÿÿÿÿÿýÿûÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿûÿüÿþÿÿÿüÿüÿÿÿÿÿþÿþÿÿÿýÿýÿþÿþÿýÿýÿýÿþÿÿÿþÿýÿþÿüÿüÿþÿûÿþÿýÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿýÿýÿÿÿÿÿþÿþÿüÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿýÿüÿÿÿÿÿþÿþÿþÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿýÿûÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿÿÿþÿýÿÿÿþÿýÿýÿþÿûÿûÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿüÿüÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿÿÿÿÿýÿýÿüÿýÿþÿþÿýÿþÿÿÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿþÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿýÿþÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿüÿüÿüÿüÿýÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿþÿþÿÿÿýÿüÿþÿûÿüÿþÿþÿþÿÿÿÿÿÿÿüÿüÿýÿþÿþÿþÿÿÿþÿþÿýÿúÿýÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿýÿýÿþÿÿÿþÿþÿþÿÿÿýÿýÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿýÿþÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿþÿýÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿýÿþÿýÿþÿÿÿýÿþÿþÿüÿüÿþÿþÿüÿýÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿûÿûÿþÿþÿüÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿþÿÿÿýÿþÿýÿüÿüÿüÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿÿÿþÿþÿÿÿýÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿýÿþÿþÿÿÿþÿþÿÿÿûÿüÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿýÿûÿýÿþÿþÿýÿüÿþÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿýÿþÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿüÿýÿþÿüÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿüÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿþÿÿÿüÿüÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿþÿþÿýÿýÿÿÿüÿüÿþÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿüÿýÿþÿÿÿþÿüÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿýÿþÿþÿþÿýÿþÿÿÿýÿüÿþÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿüÿûÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿüÿþÿýÿûÿúÿüÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿýÿúÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿüÿýÿþÿüÿýÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿúÿýÿÿÿýÿþÿÿÿÿÿþÿûÿùÿýÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿýÿýÿûÿûÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿýÿüÿýÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿþÿýÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿÿÿýÿûÿûÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿüÿúÿÿÿþÿûÿûÿúÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿþÿÿÿþÿÿÿþÿþÿÿÿüÿýÿÿÿüÿüÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿÿÿýÿüÿýÿüÿÿÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿþÿþÿÿÿüÿÿÿÿÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿþÿüÿüÿýÿÿÿÿÿþÿýÿþÿþÿÿÿýÿûÿüÿÿÿýÿþÿýÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿüÿýÿþÿÿÿÿÿþÿÿÿþÿüÿýÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿþÿÿÿýÿüÿþÿÿÿýÿþÿÿÿÿÿýÿûÿþÿüÿýÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿýÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿýÿûÿÿÿÿÿÿÿÿÿÿÿþÿûÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿüÿýÿþÿýÿüÿþÿÿÿýÿûÿüÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿüÿüÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿþÿýÿüÿýÿýÿýÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿýÿÿÿþÿþÿüÿþÿþÿÿÿýÿýÿýÿýÿþÿüÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿþÿýÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿþÿþÿûÿüÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿüÿýÿÿÿÿÿÿÿÿÿÿÿüÿýÿýÿüÿþÿÿÿÿÿþÿþÿýÿþÿýÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿýÿÿÿþÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿýÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿüÿÿÿÿÿüÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿýÿûÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿýÿÿÿþÿÿÿûÿùÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿþÿüÿýÿüÿýÿþÿÿÿÿÿüÿÿÿÿÿüÿÿÿÿÿûÿúÿûÿÿÿÿÿþÿþÿÿÿþÿýÿüÿþÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿýÿþÿþÿýÿüÿýÿÿÿýÿþÿþÿüÿüÿþÿþÿýÿÿÿþÿüÿþÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿþÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿýÿýÿýÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿþÿÿÿþÿþÿþÿýÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿþÿýÿþÿÿÿýÿÿÿþÿÿÿýÿüÿÿÿÿÿûÿûÿýÿÿÿÿÿýÿýÿýÿÿÿýÿýÿüÿþÿýÿûÿýÿÿÿýÿùÿúÿüÿÿÿþÿþÿÿÿüÿþÿÿÿÿÿþÿþÿþÿýÿüÿÿÿþÿüÿýÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿýÿýÿÿÿþÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿýÿýÿÿÿþÿÿÿÿÿþÿýÿþÿýÿþÿûÿüÿþÿþÿþÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿýÿþÿýÿûÿûÿÿÿÿÿýÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿýÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿýÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿúÿûÿýÿÿÿÿÿþÿüÿýÿþÿþÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿýÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿüÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿÿÿþÿüÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿþÿþÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿýÿýÿþÿÿÿþÿüÿýÿýÿþÿþÿýÿûÿýÿÿÿþÿüÿûÿýÿýÿÿÿþÿýÿÿÿþÿÿÿüÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿþÿÿÿþÿýÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿÿÿýÿüÿýÿýÿþÿýÿýÿÿÿýÿýÿþÿÿÿÿÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿþÿÿÿþÿþÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿûÿþÿÿÿýÿýÿÿÿÿÿýÿþÿþÿûÿûÿýÿÿÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿûÿýÿûÿüÿþÿýÿþÿþÿûÿüÿÿÿýÿýÿýÿýÿÿÿüÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿþÿýÿþÿþÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿúÿýÿÿÿÿÿýÿüÿüÿþÿþÿÿÿüÿþÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿþÿþÿÿÿüÿýÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿþÿýÿýÿÿÿüÿýÿÿÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿþÿþÿûÿùÿûÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿÿÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿùÿúÿþÿÿÿþÿýÿýÿþÿþÿÿÿÿÿþÿýÿþÿýÿýÿþÿüÿüÿþÿþÿÿÿýÿüÿÿÿÿÿýÿüÿüÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿýÿüÿûÿþÿÿÿýÿþÿþÿÿÿÿÿýÿüÿþÿþÿýÿýÿþÿÿÿþÿÿÿÿÿþÿûÿýÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿüÿÿÿÿÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿüÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿûÿúÿýÿÿÿþÿýÿüÿüÿþÿýÿÿÿÿÿýÿþÿÿÿþÿýÿüÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿýÿþÿÿÿþÿÿÿÿÿüÿûÿýÿÿÿþÿþÿþÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿúÿüÿÿÿÿÿÿÿþÿýÿÿÿýÿûÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿýÿþÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿüÿúÿûÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿüÿÿÿÿÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿýÿûÿýÿþÿþÿÿÿþÿþÿÿÿÿÿüÿüÿýÿþÿÿÿýÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿþÿüÿÿÿþÿÿÿþÿýÿýÿÿÿþÿüÿúÿúÿûÿÿÿþÿÿÿþÿüÿûÿûÿýÿþÿýÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿýÿÿÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿþÿýÿüÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿúÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿüÿýÿýÿüÿüÿüÿþÿÿÿÿÿÿÿýÿüÿÿÿþÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿüÿüÿûÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿýÿÿÿÿÿþÿþÿúÿþÿÿÿúÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿýÿþÿþÿýÿÿÿþÿþÿþÿþÿÿÿÿÿþÿüÿüÿýÿþÿüÿüÿÿÿÿÿûÿûÿüÿþÿüÿüÿþÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿýÿþÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿýÿýÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿýÿüÿýÿÿÿþÿþÿüÿýÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿþÿþÿþÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿüÿüÿüÿþÿÿÿýÿüÿþÿýÿþÿþÿýÿýÿþÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿúÿþÿÿÿüÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿÿÿýÿýÿÿÿþÿþÿüÿýÿýÿûÿüÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿþÿþÿüÿýÿÿÿþÿþÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿýÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿüÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿüÿüÿûÿýÿþÿýÿýÿýÿûÿýÿýÿýÿýÿþÿûÿþÿÿÿþÿÿÿÿÿþÿÿÿüÿûÿýÿÿÿþÿüÿýÿÿÿýÿýÿýÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿýÿýÿýÿýÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿýÿûÿýÿÿÿÿÿÿÿýÿýÿÿÿÿÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿþÿûÿùÿúÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿýÿýÿþÿÿÿþÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿÿÿþÿüÿûÿþÿýÿÿÿþÿþÿýÿýÿýÿýÿûÿüÿþÿÿÿþÿþÿýÿúÿúÿúÿûÿÿÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿüÿþÿýÿüÿýÿþÿÿÿÿÿüÿûÿþÿüÿýÿýÿþÿýÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿþÿþÿÿÿýÿþÿÿÿýÿþÿþÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿÿÿüÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿýÿýÿüÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿüÿüÿüÿýÿþÿýÿýÿÿÿÿÿþÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿÿÿûÿûÿûÿûÿýÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿüÿþÿþÿþÿýÿÿÿþÿýÿýÿþÿýÿþÿþÿüÿþÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿüÿüÿüÿüÿüÿüÿýÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿüÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿþÿþÿþÿÿÿüÿûÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿûÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿûÿüÿÿÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿüÿþÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿþÿþÿþÿüÿÿÿÿÿÿÿýÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿþÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿþÿþÿÿÿþÿÿÿÿÿüÿüÿÿÿþÿþÿþÿýÿþÿÿÿÿÿýÿÿÿþÿýÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿúÿùÿüÿþÿýÿýÿÿÿþÿýÿÿÿþÿüÿýÿÿÿýÿúÿýÿýÿûÿûÿÿÿþÿýÿûÿüÿþÿþÿÿÿýÿüÿþÿÿÿþÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿýÿÿÿþÿýÿüÿÿÿÿÿþÿþÿþÿþÿþÿýÿüÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿüÿûÿýÿþÿþÿþÿþÿþÿþÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿýÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿþÿýÿýÿþÿþÿûÿùÿúÿýÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿûÿúÿüÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿüÿýÿÿÿþÿúÿùÿþÿÿÿÿÿÿÿþÿýÿþÿýÿþÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿýÿÿÿÿÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿüÿùÿüÿÿÿýÿÿÿÿÿþÿýÿÿÿüÿýÿþÿþÿýÿýÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿüÿþÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿúÿûÿÿÿÿÿüÿýÿþÿýÿþÿüÿýÿÿÿþÿüÿûÿýÿýÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿýÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿýÿýÿþÿÿÿýÿÿÿýÿþÿÿÿÿÿþÿüÿýÿÿÿþÿýÿüÿþÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿüÿýÿþÿýÿÿÿÿÿþÿýÿþÿýÿþÿÿÿþÿüÿþÿýÿÿÿÿÿþÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿþÿýÿþÿÿÿþÿÿÿþÿþÿûÿýÿÿÿÿÿþÿýÿýÿüÿûÿþÿÿÿþÿþÿÿÿÿÿüÿûÿÿÿþÿþÿþÿÿÿþÿúÿþÿþÿÿÿÿÿþÿþÿýÿþÿþÿýÿÿÿÿÿþÿûÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿûÿýÿÿÿüÿþÿþÿÿÿüÿÿÿÿÿþÿüÿûÿúÿüÿÿÿüÿúÿþÿþÿÿÿÿÿþÿýÿýÿþÿüÿûÿýÿÿÿþÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿúÿùÿýÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿüÿüÿüÿýÿÿÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿüÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿüÿþÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿüÿÿÿþÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿÿÿþÿýÿþÿþÿüÿüÿýÿþÿüÿûÿþÿÿÿÿÿýÿüÿýÿýÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿþÿþÿýÿýÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿýÿþÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿþÿþÿþÿþÿüÿüÿýÿýÿþÿþÿÿÿþÿüÿüÿýÿÿÿýÿûÿûÿÿÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿýÿüÿüÿüÿÿÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿþÿüÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿýÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿûÿýÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿüÿýÿýÿýÿÿÿþÿþÿÿÿÿÿýÿüÿýÿüÿýÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿüÿþÿÿÿþÿüÿþÿÿÿÿÿüÿýÿÿÿþÿýÿýÿþÿýÿûÿüÿýÿýÿþÿÿÿÿÿÿÿüÿúÿýÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿüÿýÿþÿýÿÿÿÿÿÿÿýÿüÿþÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿþÿþÿþÿüÿüÿþÿüÿÿÿþÿþÿýÿÿÿÿÿþÿýÿþÿýÿþÿüÿýÿýÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿûÿüÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿþÿþÿþÿþÿýÿþÿÿÿýÿýÿÿÿýÿýÿüÿþÿûÿýÿþÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿþÿûÿùÿúÿýÿþÿþÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿüÿýÿþÿþÿýÿýÿýÿýÿýÿýÿþÿýÿþÿüÿþÿþÿþÿÿÿÿÿÿÿýÿüÿüÿýÿÿÿþÿüÿüÿÿÿþÿúÿúÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿýÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿûÿþÿÿÿÿÿýÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿýÿüÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿþÿÿÿþÿþÿüÿùÿùÿýÿþÿÿÿþÿÿÿÿÿÿÿüÿûÿüÿÿÿÿÿþÿýÿÿÿþÿýÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿýÿýÿÿÿýÿüÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿýÿüÿýÿÿÿÿÿÿÿüÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿýÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿýÿüÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿýÿþÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿýÿþÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿþÿûÿûÿþÿÿÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿÿÿþÿýÿþÿüÿüÿþÿÿÿÿÿÿÿüÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿüÿýÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿþÿþÿÿÿþÿýÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿþÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿÿÿþÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿýÿþÿþÿþÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿýÿþÿûÿüÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿýÿýÿýÿýÿþÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿþÿýÿüÿýÿþÿÿÿýÿÿÿþÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿýÿýÿüÿþÿüÿúÿüÿþÿýÿþÿüÿüÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿýÿþÿýÿýÿýÿûÿüÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿýÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿýÿÿÿþÿûÿýÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿÿÿÿÿÿÿÿÿþÿýÿüÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿýÿýÿþÿþÿüÿûÿýÿýÿýÿýÿþÿÿÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿýÿþÿûÿþÿÿÿÿÿÿÿþÿýÿÿÿýÿúÿþÿÿÿüÿþÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿýÿüÿÿÿÿÿüÿÿÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿüÿýÿþÿþÿýÿýÿûÿÿÿÿÿüÿÿÿÿÿþÿÿÿýÿÿÿþÿûÿüÿýÿÿÿþÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿþÿýÿüÿýÿÿÿýÿüÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿÿÿÿÿýÿûÿýÿþÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿüÿýÿÿÿþÿþÿýÿþÿÿÿþÿÿÿþÿþÿûÿýÿÿÿÿÿýÿþÿýÿýÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿÿÿþÿüÿÿÿÿÿüÿýÿûÿýÿýÿüÿýÿüÿüÿÿÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿýÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿþÿüÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿýÿþÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿýÿýÿýÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿüÿûÿüÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿüÿþÿþÿýÿýÿþÿÿÿÿÿüÿýÿþÿÿÿþÿÿÿûÿûÿþÿüÿûÿÿÿÿÿÿÿþÿþÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿüÿÿÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿüÿýÿþÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿÿÿÿÿýÿüÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿþÿþÿýÿþÿýÿþÿþÿþÿþÿýÿüÿÿÿþÿüÿûÿûÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿþÿúÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿÿÿÿÿÿÿýÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿüÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿýÿþÿÿÿýÿÿÿÿÿÿÿÿÿüÿûÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿýÿþÿþÿþÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿýÿýÿýÿûÿûÿüÿþÿýÿýÿþÿþÿþÿýÿþÿýÿþÿÿÿþÿýÿüÿþÿýÿüÿþÿÿÿÿÿþÿþÿþÿþÿþÿüÿüÿþÿýÿýÿÿÿÿÿÿÿüÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿüÿþÿÿÿÿÿüÿýÿýÿþÿýÿþÿÿÿÿÿÿÿþÿýÿýÿüÿÿÿÿÿÿÿýÿþÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿúÿüÿýÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿýÿÿÿÿÿþÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿýÿüÿûÿþÿÿÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿûÿþÿþÿüÿþÿýÿüÿþÿþÿþÿþÿüÿýÿÿÿÿÿþÿþÿÿÿþÿþÿýÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿþÿÿÿÿÿýÿüÿûÿúÿúÿýÿÿÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿÿÿýÿÿÿþÿüÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿÿÿþÿþÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿÿÿýÿüÿüÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿþÿýÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿýÿÿÿüÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿûÿûÿúÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿûÿþÿÿÿÿÿÿÿþÿýÿüÿýÿþÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿýÿüÿÿÿþÿýÿÿÿýÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿýÿûÿûÿþÿÿÿÿÿÿÿûÿûÿþÿýÿþÿýÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿüÿþÿÿÿþÿýÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿüÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿÿÿüÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿýÿýÿÿÿÿÿýÿüÿþÿÿÿþÿûÿýÿþÿþÿÿÿþÿþÿþÿýÿÿÿýÿÿÿÿÿþÿýÿÿÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿûÿûÿþÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿÿÿþÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿýÿûÿýÿÿÿþÿþÿÿÿÿÿþÿþÿüÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿüÿûÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿþÿûÿûÿþÿÿÿÿÿþÿýÿûÿÿÿÿÿÿÿÿÿþÿýÿýÿüÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿýÿþÿýÿÿÿÿÿüÿüÿýÿÿÿþÿÿÿÿÿýÿÿÿþÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿüÿúÿûÿýÿÿÿþÿýÿÿÿýÿýÿÿÿÿÿýÿþÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿüÿýÿÿÿýÿýÿûÿúÿüÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿüÿùÿûÿþÿÿÿÿÿÿÿÿÿþÿýÿüÿþÿÿÿÿÿþÿÿÿþÿþÿýÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿýÿýÿýÿýÿýÿýÿþÿÿÿÿÿýÿþÿýÿûÿþÿÿÿýÿþÿüÿýÿÿÿÿÿþÿþÿÿÿýÿúÿüÿÿÿþÿþÿýÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿþÿüÿýÿüÿúÿûÿýÿÿÿþÿýÿÿÿþÿþÿüÿýÿÿÿþÿýÿþÿýÿÿÿþÿþÿÿÿþÿþÿþÿþÿûÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿþÿýÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿüÿýÿýÿþÿÿÿýÿýÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿþÿþÿþÿþÿüÿûÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿþÿþÿþÿÿÿþÿýÿýÿÿÿüÿüÿþÿÿÿüÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿûÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿþÿýÿþÿþÿýÿþÿÿÿÿÿþÿýÿÿÿþÿüÿýÿýÿýÿþÿûÿûÿûÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿýÿþÿýÿýÿýÿþÿÿÿýÿüÿÿÿÿÿÿÿÿÿýÿüÿüÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿþÿýÿþÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿþÿýÿþÿýÿýÿÿÿýÿþÿþÿýÿÿÿþÿÿÿþÿûÿûÿþÿýÿýÿÿÿÿÿýÿþÿÿÿýÿüÿýÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿþÿüÿüÿúÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿüÿÿÿþÿþÿþÿþÿûÿýÿÿÿÿÿþÿûÿüÿýÿþÿþÿÿÿþÿþÿþÿýÿýÿþÿýÿÿÿÿÿÿÿþÿþÿýÿýÿþÿýÿýÿýÿÿÿþÿþÿýÿÿÿýÿþÿýÿÿÿÿÿþÿüÿýÿüÿýÿÿÿüÿùÿúÿþÿÿÿþÿüÿüÿÿÿÿÿþÿÿÿÿÿÿÿÿÿüÿüÿüÿýÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿúÿûÿþÿÿÿÿÿüÿýÿÿÿþÿüÿýÿÿÿþÿþÿÿÿþÿþÿþÿýÿÿÿþÿþÿþÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿýÿýÿþÿýÿûÿýÿþÿÿÿþÿþÿÿÿýÿýÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿýÿúÿýÿþÿþÿÿÿÿÿÿÿÿÿûÿúÿýÿýÿûÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿýÿÿÿþÿûÿûÿýÿüÿýÿÿÿÿÿÿÿÿÿýÿýÿûÿýÿûÿþÿÿÿüÿþÿÿÿýÿûÿûÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿýÿüÿýÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿûÿûÿüÿþÿÿÿüÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿÿÿýÿÿÿýÿþÿþÿýÿþÿýÿüÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿüÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿüÿþÿÿÿýÿüÿþÿÿÿþÿÿÿþÿÿÿüÿüÿýÿþÿþÿýÿýÿýÿÿÿþÿÿÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿÿÿüÿýÿýÿûÿûÿûÿûÿýÿþÿþÿýÿÿÿþÿüÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿüÿýÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿüÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿüÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿþÿþÿüÿþÿÿÿþÿþÿüÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿþÿýÿýÿþÿýÿüÿÿÿþÿÿÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿýÿûÿúÿþÿþÿÿÿþÿÿÿýÿüÿþÿþÿÿÿüÿþÿþÿÿÿýÿýÿþÿÿÿþÿüÿüÿûÿýÿÿÿÿÿÿÿýÿÿÿþÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿþÿýÿýÿüÿüÿýÿÿÿþÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿþÿýÿûÿùÿûÿýÿÿÿþÿþÿÿÿþÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿüÿüÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿýÿýÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿýÿÿÿÿÿþÿþÿýÿüÿþÿÿÿýÿÿÿýÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿþÿþÿþÿþÿÿÿÿÿüÿüÿÿÿÿÿýÿüÿþÿÿÿþÿÿÿÿÿýÿüÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿýÿþÿýÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿüÿüÿýÿÿÿþÿÿÿÿÿÿÿýÿüÿýÿþÿüÿÿÿÿÿÿÿýÿýÿþÿþÿþÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿýÿýÿüÿûÿûÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿûÿþÿÿÿÿÿýÿýÿþÿÿÿþÿýÿÿÿýÿüÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿüÿþÿüÿýÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿýÿÿÿþÿýÿþÿüÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿýÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿýÿúÿûÿüÿÿÿþÿþÿþÿÿÿÿÿýÿüÿüÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿþÿþÿþÿýÿþÿýÿþÿýÿÿÿþÿþÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿÿÿýÿþÿýÿüÿÿÿÿÿüÿþÿÿÿþÿþÿþÿûÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿüÿüÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿúÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿýÿýÿýÿýÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿýÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿýÿüÿýÿÿÿÿÿÿÿþÿýÿþÿýÿýÿýÿþÿÿÿþÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿüÿúÿüÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿûÿûÿüÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿüÿþÿÿÿÿÿþÿÿÿýÿÿÿþÿþÿüÿüÿÿÿÿÿýÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿûÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿüÿûÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿýÿþÿþÿþÿþÿþÿþÿÿÿýÿýÿÿÿÿÿüÿÿÿÿÿþÿýÿüÿþÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿþÿþÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿÿÿýÿýÿüÿûÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿþÿýÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿýÿýÿþÿûÿýÿÿÿÿÿÿÿþÿûÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿüÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿýÿýÿýÿûÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿüÿýÿûÿýÿÿÿÿÿþÿþÿÿÿþÿýÿþÿþÿýÿÿÿÿÿüÿúÿûÿÿÿþÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿûÿúÿÿÿÿÿýÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿüÿûÿÿÿÿÿÿÿýÿýÿþÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿýÿüÿþÿþÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿþÿýÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿþÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿÿÿþÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿýÿüÿýÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿþÿÿÿýÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿþÿþÿýÿüÿýÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿýÿýÿþÿÿÿÿÿýÿûÿýÿþÿÿÿþÿýÿÿÿþÿþÿþÿÿÿýÿüÿþÿýÿüÿýÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿýÿýÿýÿûÿýÿþÿþÿýÿüÿýÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÿüÿþÿýÿúÿúÿûÿýÿÿÿþÿüÿûÿýÿýÿÿÿýÿþÿýÿýÿþÿþÿûÿüÿýÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿûÿþÿþÿÿÿÿÿýÿþÿüÿýÿýÿþÿÿÿÿÿÿÿÿÿûÿýÿýÿüÿýÿþÿýÿþÿÿÿýÿþÿÿÿýÿüÿþÿýÿüÿÿÿþÿÿÿÿÿÿÿûÿüÿÿÿÿÿþÿþÿÿÿýÿüÿþÿÿÿþÿþÿþÿýÿýÿþÿÿÿýÿüÿþÿÿÿýÿüÿýÿýÿýÿýÿÿÿÿÿüÿüÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿÿÿýÿúÿúÿýÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿýÿþÿþÿþÿýÿþÿþÿýÿüÿýÿþÿþÿÿÿþÿýÿÿÿþÿüÿüÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿýÿýÿûÿýÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿýÿûÿûÿüÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿýÿÿÿýÿýÿþÿüÿûÿýÿÿÿþÿþÿÿÿÿÿþÿþÿýÿüÿþÿþÿþÿÿÿþÿýÿÿÿþÿÿÿûÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿúÿúÿþÿÿÿýÿÿÿÿÿÿÿýÿüÿýÿýÿþÿþÿþÿÿÿÿÿþÿÿÿþÿüÿÿÿþÿþÿþÿÿÿýÿúÿûÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿûÿüÿþÿþÿüÿüÿþÿþÿÿÿÿÿýÿüÿüÿþÿþÿþÿþÿýÿüÿüÿþÿýÿüÿýÿþÿþÿÿÿÿÿýÿýÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿüÿüÿüÿüÿÿÿýÿþÿÿÿÿÿÿÿþÿûÿûÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿýÿÿÿÿÿþÿýÿüÿýÿþÿÿÿþÿûÿûÿÿÿÿÿÿÿþÿýÿýÿþÿþÿþÿÿÿýÿýÿþÿÿÿþÿýÿþÿþÿýÿýÿþÿþÿÿÿÿÿüÿÿÿÿÿþÿýÿþÿüÿüÿþÿÿÿþÿþÿþÿþÿþÿüÿúÿüÿÿÿüÿýÿÿÿþÿýÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿþÿýÿûÿýÿÿÿþÿýÿþÿþÿýÿýÿýÿýÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿþÿýÿýÿÿÿÿÿýÿûÿýÿûÿûÿýÿýÿýÿýÿýÿÿÿþÿþÿýÿüÿýÿþÿÿÿþÿüÿýÿÿÿþÿÿÿþÿüÿþÿÿÿûÿýÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿüÿÿÿÿÿÿÿþÿÿÿüÿûÿþÿþÿýÿÿÿþÿýÿÿÿýÿýÿþÿýÿýÿýÿÿÿÿÿþÿüÿüÿÿÿýÿûÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿûÿüÿþÿþÿþÿÿÿþÿþÿþÿüÿýÿþÿýÿûÿüÿþÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿûÿýÿÿÿÿÿþÿýÿþÿþÿÿÿýÿüÿýÿýÿüÿÿÿþÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿýÿüÿüÿþÿýÿþÿþÿýÿüÿþÿÿÿýÿýÿûÿþÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿüÿþÿÿÿüÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿýÿüÿÿÿÿÿýÿüÿþÿÿÿýÿüÿÿÿýÿÿÿüÿûÿþÿÿÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿüÿûÿýÿþÿþÿþÿþÿþÿþÿýÿüÿÿÿþÿûÿþÿþÿþÿýÿÿÿÿÿüÿÿÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿýÿüÿûÿûÿýÿÿÿÿÿþÿýÿýÿüÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿýÿýÿþÿýÿüÿþÿÿÿÿÿýÿýÿþÿÿÿüÿýÿÿÿýÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿüÿüÿÿÿÿÿûÿüÿýÿþÿþÿýÿÿÿþÿÿÿýÿþÿÿÿÿÿýÿýÿýÿüÿýÿþÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿýÿÿÿüÿýÿþÿýÿýÿýÿýÿÿÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿûÿùÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿþÿÿÿÿÿÿÿþÿýÿþÿüÿýÿþÿþÿÿÿþÿþÿüÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿþÿþÿüÿþÿþÿüÿüÿþÿþÿþÿýÿÿÿÿÿýÿÿÿÿÿüÿýÿþÿÿÿþÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿþÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿûÿûÿþÿÿÿýÿþÿþÿþÿþÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿüÿúÿûÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿýÿýÿþÿÿÿÿÿÿÿþÿýÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿûÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿüÿÿÿþÿÿÿÿÿþÿþÿýÿüÿüÿþÿýÿüÿþÿýÿþÿûÿþÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿúÿýÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿüÿýÿþÿýÿþÿýÿÿÿþÿüÿýÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿüÿýÿûÿüÿýÿÿÿÿÿþÿÿÿÿÿüÿþÿÿÿüÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿÿÿþÿýÿÿÿþÿþÿýÿþÿþÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿýÿýÿüÿþÿÿÿþÿýÿüÿþÿþÿýÿüÿüÿÿÿÿÿÿÿýÿþÿûÿûÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿûÿþÿþÿþÿþÿýÿüÿüÿÿÿþÿþÿÿÿþÿÿÿþÿüÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿþÿþÿþÿûÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿÿÿþÿþÿþÿûÿúÿüÿþÿýÿûÿûÿýÿþÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿýÿþÿÿÿþÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿûÿýÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿüÿýÿþÿýÿþÿÿÿÿÿÿÿþÿþÿüÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿþÿýÿþÿüÿþÿþÿþÿÿÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿþÿýÿüÿþÿýÿýÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÿÿÿþÿþÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿüÿüÿÿÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿýÿýÿýÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿýÿýÿýÿÿÿýÿüÿýÿþÿþÿþÿýÿüÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿÿÿýÿýÿþÿÿÿÿÿþÿýÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿýÿüÿüÿüÿÿÿÿÿüÿþÿýÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿûÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿýÿýÿýÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿþÿýÿþÿÿÿýÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿþÿþÿÿÿþÿþÿüÿüÿÿÿþÿþÿÿÿÿÿÿÿþÿüÿþÿþÿþÿýÿýÿþÿýÿþÿþÿÿÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿûÿüÿþÿÿÿþÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿýÿüÿþÿüÿüÿûÿýÿýÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿüÿüÿÿÿÿÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿûÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿýÿýÿþÿÿÿÿÿþÿûÿýÿÿÿþÿþÿÿÿÿÿþÿüÿþÿÿÿýÿþÿþÿþÿÿÿÿÿüÿúÿüÿýÿüÿþÿÿÿþÿüÿùÿûÿþÿÿÿþÿÿÿÿÿýÿýÿÿÿþÿûÿþÿÿÿþÿþÿÿÿþÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿþÿþÿýÿüÿüÿþÿÿÿÿÿüÿýÿþÿÿÿûÿþÿÿÿýÿýÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿüÿùÿüÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿýÿüÿýÿÿÿþÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿýÿüÿÿÿÿÿÿÿþÿÿÿÿÿüÿûÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿýÿýÿÿÿþÿüÿþÿþÿýÿýÿþÿÿÿÿÿþÿûÿýÿþÿþÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿüÿüÿþÿþÿýÿûÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿüÿûÿþÿüÿüÿÿÿÿÿþÿýÿÿÿÿÿýÿþÿþÿÿÿþÿÿÿÿÿýÿþÿþÿýÿþÿÿÿüÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿüÿýÿüÿüÿþÿþÿüÿüÿûÿüÿÿÿÿÿýÿûÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿúÿûÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿþÿýÿüÿÿÿÿÿüÿýÿÿÿÿÿÿÿýÿýÿýÿþÿýÿÿÿýÿýÿþÿÿÿÿÿýÿÿÿýÿÿÿÿÿþÿýÿýÿýÿþÿþÿýÿþÿÿÿýÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿþÿþÿþÿüÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿýÿýÿýÿþÿþÿÿÿüÿýÿþÿýÿþÿÿÿÿÿþÿýÿþÿüÿÿÿÿÿýÿüÿûÿýÿþÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿûÿþÿüÿýÿýÿþÿþÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿýÿÿÿþÿýÿüÿýÿÿÿüÿýÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿüÿýÿýÿþÿÿÿÿÿÿÿýÿþÿýÿýÿþÿÿÿþÿýÿüÿüÿÿÿÿÿüÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿýÿýÿýÿþÿúÿüÿþÿþÿÿÿþÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿþÿþÿüÿýÿÿÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿýÿÿÿÿÿüÿþÿþÿýÿüÿþÿþÿÿÿüÿþÿþÿýÿüÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿþÿÿÿÿÿúÿüÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿüÿþÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿüÿÿÿýÿûÿþÿûÿýÿÿÿÿÿþÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿþÿþÿýÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿýÿüÿÿÿþÿþÿþÿÿÿýÿýÿþÿÿÿýÿûÿþÿÿÿüÿüÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿÿÿÿÿüÿüÿþÿÿÿþÿüÿýÿÿÿþÿýÿýÿþÿÿÿþÿÿÿÿÿýÿýÿþÿýÿûÿüÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿýÿþÿÿÿýÿþÿüÿþÿýÿûÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿüÿýÿýÿÿÿüÿýÿýÿûÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿýÿþÿÿÿþÿþÿýÿúÿûÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿüÿþÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿýÿþÿþÿýÿüÿÿÿÿÿþÿýÿýÿÿÿþÿþÿþÿþÿþÿýÿýÿþÿþÿüÿýÿÿÿþÿüÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿýÿüÿýÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿýÿýÿýÿþÿÿÿýÿÿÿþÿþÿþÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿûÿúÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿÿÿýÿùÿúÿüÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿüÿÿÿÿÿüÿþÿüÿüÿÿÿþÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿÿÿþÿÿÿþÿýÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿûÿûÿûÿúÿüÿþÿýÿüÿþÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿýÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿýÿûÿûÿüÿýÿþÿþÿûÿúÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿýÿýÿýÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿýÿüÿþÿÿÿýÿüÿÿÿÿÿýÿþÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿüÿüÿüÿÿÿÿÿýÿÿÿÿÿþÿþÿþÿýÿûÿþÿÿÿþÿÿÿþÿýÿþÿýÿÿÿþÿÿÿÿÿýÿüÿüÿþÿÿÿýÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿýÿüÿþÿÿÿÿÿýÿüÿûÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿþÿþÿüÿüÿÿÿÿÿþÿþÿþÿÿÿþÿýÿüÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿüÿûÿúÿûÿýÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿýÿýÿþÿþÿÿÿþÿþÿþÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿûÿùÿúÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿýÿüÿÿÿÿÿýÿÿÿþÿþÿþÿÿÿþÿüÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿýÿþÿýÿÿÿÿÿþÿÿÿþÿüÿûÿýÿþÿþÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿþÿÿÿýÿþÿýÿûÿüÿÿÿþÿýÿþÿÿÿþÿýÿþÿþÿüÿþÿýÿÿÿÿÿþÿÿÿþÿÿÿýÿüÿýÿþÿþÿüÿþÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿûÿùÿûÿÿÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿüÿüÿüÿüÿüÿýÿýÿûÿüÿþÿýÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿýÿüÿýÿüÿûÿþÿýÿÿÿþÿþÿþÿýÿüÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿþÿÿÿþÿÿÿüÿýÿýÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿüÿüÿÿÿþÿÿÿÿÿþÿþÿþÿýÿýÿþÿþÿÿÿþÿýÿüÿüÿûÿýÿþÿþÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿüÿüÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿþÿýÿþÿÿÿþÿþÿüÿþÿþÿÿÿÿÿýÿÿÿÿÿüÿýÿÿÿþÿþÿýÿýÿüÿýÿÿÿþÿýÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿüÿûÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿûÿüÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿüÿÿÿþÿÿÿýÿÿÿÿÿÿÿþÿüÿüÿüÿþÿýÿþÿýÿüÿüÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿþÿûÿüÿÿÿÿÿýÿÿÿýÿþÿÿÿÿÿýÿþÿýÿþÿÿÿþÿþÿþÿýÿûÿýÿÿÿþÿÿÿÿÿýÿýÿþÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿÿÿÿÿÿÿýÿüÿþÿþÿþÿþÿþÿýÿúÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿþÿýÿýÿÿÿÿÿýÿÿÿþÿþÿþÿþÿþÿýÿûÿúÿüÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿüÿýÿþÿüÿýÿþÿþÿþÿþÿþÿÿÿüÿüÿÿÿýÿýÿÿÿÿÿþÿüÿûÿûÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿÿÿþÿüÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿýÿþÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿüÿþÿÿÿþÿþÿþÿþÿýÿþÿþÿþÿüÿýÿÿÿþÿÿÿþÿþÿþÿþÿýÿýÿþÿÿÿþÿþÿþÿþÿÿÿýÿýÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿýÿüÿÿÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿþÿþÿÿÿýÿüÿþÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿÿÿýÿýÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿþÿÿÿýÿþÿÿÿýÿýÿüÿûÿþÿÿÿýÿýÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿüÿúÿýÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿþÿþÿþÿýÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿÿÿÿÿýÿÿÿÿÿÿÿýÿýÿýÿÿÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿüÿúÿýÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿüÿûÿþÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿÿÿþÿþÿýÿþÿÿÿýÿüÿÿÿþÿúÿûÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿþÿýÿþÿþÿüÿýÿýÿüÿþÿÿÿÿÿûÿýÿþÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿüÿûÿþÿÿÿÿÿþÿýÿÿÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿûÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿúÿüÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿþÿýÿÿÿÿÿüÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿþÿÿÿÿÿýÿÿÿþÿýÿþÿþÿþÿüÿþÿþÿýÿýÿýÿÿÿýÿýÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿýÿüÿüÿüÿýÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿýÿýÿýÿþÿÿÿÿÿýÿþÿýÿÿÿýÿýÿþÿÿÿýÿþÿÿÿÿÿþÿþÿýÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿþÿþÿýÿüÿýÿÿÿþÿýÿüÿüÿýÿüÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿþÿþÿýÿþÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿÿÿüÿüÿüÿûÿûÿþÿÿÿÿÿÿÿüÿûÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿýÿþÿþÿÿÿýÿüÿþÿþÿÿÿþÿýÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿüÿüÿþÿÿÿþÿüÿûÿýÿÿÿýÿýÿýÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿþÿþÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿÿÿÿÿûÿýÿÿÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿýÿÿÿÿÿþÿýÿüÿûÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿýÿüÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿüÿüÿýÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿüÿüÿüÿÿÿþÿüÿýÿþÿüÿùÿøÿûÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿûÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿûÿþÿýÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿþÿýÿÿÿþÿýÿýÿþÿûÿüÿÿÿýÿþÿÿÿÿÿÿÿüÿüÿÿÿÿÿÿÿýÿûÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿýÿüÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿþÿüÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿþÿûÿüÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿüÿûÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿúÿûÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿþÿÿÿþÿÿÿÿÿþÿýÿüÿýÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿýÿÿÿþÿüÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿüÿüÿüÿþÿüÿþÿþÿýÿúÿüÿÿÿüÿûÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿüÿüÿÿÿýÿûÿûÿüÿýÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿÿÿþÿÿÿþÿüÿþÿþÿüÿüÿüÿýÿýÿþÿþÿþÿþÿþÿýÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿýÿþÿýÿÿÿþÿþÿþÿüÿþÿþÿþÿýÿüÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿýÿþÿýÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿúÿûÿþÿÿÿþÿüÿÿÿÿÿýÿüÿýÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿüÿüÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿýÿÿÿýÿþÿþÿÿÿþÿýÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿýÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿþÿÿÿýÿýÿüÿþÿÿÿÿÿüÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿÿID3 ID3beetbox-beets-00724b7/test/rsrc/soundcheck-nonascii.m4a0000664000175000017500000001334615253035401022344 0ustar pieterpieter ftypM4A M4A mp42isom ŠmoovlmvhdÄLé_ÄLï¬D¸@�trak\tkhdÄLé_ÄLï¸@mdia mdhdÄLé_ÄLï¬D¸UÄ"hdlrsounÓminfsmhd$dinfdref url —stblgstsdWmp4a¬D3esds€€€"€€€@xú€€€€€€stts.(stscÌstsz.22""'-+1/+&0''&%)(-,*).)(*%)-4&6.*,$,3/'& stcoÆé •udta �meta"hdlrmdirappl°‡ilst©namdatafull"©ARTdatathe artist$©wrtdatathe composer!©albdatathe album!©gendatathe genre trkndatadiskdata©daydata2001cpildatapgapdatatmpodata6©too.dataiTunes v7.6.2, QuickTime 7.4.5N----meancom.apple.iTunesnameLabeldatathe labelR----meancom.apple.iTunesnamepublisherdatathe labely----meancom.apple.iTunes!nameMusicBrainz Artist Id4data7cf0ea9d-86b9-4dad-ba9e-2355a64899eax----meancom.apple.iTunes nameMusicBrainz Track Id4data8b882575-08a5-4452-a7a7-cbb8a1531f9ex----meancom.apple.iTunes nameMusicBrainz Album Id4data9e873859-8aa4-4790-b985-5a953e8ef628¨----meancom.apple.iTunesnameiTunNORMpdata 000009DD 00000ACD 00004337 0000460C 00029224 000220C3 00007FFF 00007FFF 0001FC7B 0001E5E5�¼----meancom.apple.iTunesnameiTunSMPB„data 00000000 00000840 0000037C 000000000000AC44 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"©lyrdatathe lyrics$©cmtdatathe comments$©grpdatathe grouping(aART datathe album artistØfreefree(mdatЃì\«11;Ä<Àøƒ¤4„ `I�fàe—^àï�P0#Ü·›�Áb˜Ä»VOØÙ(*¾J€q8òƒ„q©-@>Ťè[-3þ!‹rtg¼¼(ι¶q]b¥¸úƒÄPEÙ€€ ª°DãÙ‘>JUl3ËA$Ö)i)ƒÀúƒÄA#�€+:3ï`Xa¶™˜ÉùQ;«À±˜ˆèàöƒ¢" „Î Ž× óf{q wZ“Ä 3z¿f#)NÙq'øƒ¢" „kËr½ÙÖ£ g�§ý'”ê )y*¦˜Úö»,°Îµx¡úƒ¢" „r †BXVFìì7nhϦNž|z%ôe0Ue®«Œ œöƒ‚B„_`9åo¢ðJ­Dz0¯)òøáÛ1F8‘ú·åÉ>7t·#‹Uàøƒ¤4#ŒXÛõÞ™¾áàÒ`¸Ž‚Þ×xT†aGˆ~fäHv<ý¶ÁÀúƒÄ`? &ˆ×63Дl:äGàë’ 莵š„ÇÓëåN‚àúƒ¢R#Aש9Ï<³ÔiÇ%Öøê¦—µŠÍÎê®yfžÎôƒ‚T„ `®!�I}uhnV$?‹+ä¡(Z«„Á�¡Üta¥Vi±+±l‰8úƒÄ3#P�0¼ñ•T`’3¹èžÓ#?}¥ÕõÚ»ìÔ‹€úƒ¤Q#Hl`µˆÁ½¥ËK§)Q)E‚ñõ>O²Âô¯SÔ¦úƒÆ"#P ÛdpËŸ¿Û2é­~sÛÈÓï�'Pîì=Í&ü!úƒÄPG<Ž0NÝÍ�Eø™_ƒõ'1…:õ˜‹å\øƒ¢ ˆ,l ƒq¼Ôº<�¬>èðÍ&ïÞ¦J3}•]dQ€€8úƒ¢`F  8I+–¶:aá–;0¥Ç>m>;ßM¾íÛ�Ÿ× ¥/gøƒ¤p>€ÞbSci›”¤L z:~H�5ƒM3©'°A+è&„f ‡Ö(pöƒ‚0!dÀ¢’¯:%¢C°9B³î+]þ3Z†¹ècJr†Â¶�öƒ¤`E€�a,]µ)\BiwÈ,yç@úD¸ù�ü'ħ¥¨Üøƒ¢ ˆÐÀ€0qóà=bžmBÅAwùH°×! šDSª� 8öƒ‚5 !`Â4†§å^ñíª^:$9µÏ…gs`M%…ÊZZtª^U£Y(o€úƒ¢"ˆ¤09œ’#NÑ·#̬zÚW›;t A-1dyß”3¤^ àúƒ¢" "ìFâwì¼ú„,µ¸rŠþ¬js%”ŸÒísÙfžep=¼øƒ¤`G €@ÀãÒ5?à¼`•Ø�ÉÍM²ÈöÆýYB^×;C€øƒ¢`BÈ ÆãiRø—‡iéŽ6ˆ0 9ü¾åÓvë…(ÜÿÿGYJ´…=˜¢oçlÇWøƒ¤3 BÐ3ÜQhLÖÆ$/ê‡b<÷~³µ8ëûÛΚS�­n*jõXeÅ×7’#àôƒ‚"(„@Ø Ad¨*Â`óÙ'ሬÁ®co·>Vûça &µ% øƒ¤`F‚ ¢±äßxã}¸<ëÊüfP[2ÚqXä.Š'Iµpúƒ¢" „¤*ÓØšÖ'êŠÇÉR™z[oÝÓ¬ía‚„¾”XÇS2p'ÀøƒÆ2! éZðÞx²µ¾ùìú$©¿Vn´%j(óVÀöƒ¤`F‚�€öŽ�F†@›c}}ðCÂ2>Û<ÆçO5£!¹QÞ/grD�ðúƒ¤aBàô‡2‰´S(^®Z�dð{¦P�¤Ÿ~‰ÙÛ˜¦‘6 Sºœöƒ¢ „,`¼-1wNÞAÀÍ”XPKh¡wKÛ#0R¬Y±X�-Àøƒ¢`E� "ÅImq¤>w¢È1s5{!ÁXº[¯/æÛ?ÓG�¥xøƒ¢2"%€Xä  aÔž®ŽæÏû©ÆÏç¿÷º�r¯˜LaÀƒì\ªRi"?pƒì\¬ „ô@À\beetbox-beets-00724b7/test/rsrc/image-jpeg.mp30000664000175000017500000002432415253035401020436 0ustar pieterpieterID3STRCK0/0TPOS0/0TDRC0000APICimage/jpegÿØÿàJFIFHHÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÄ ÿĵ}!1AQa"q2�‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2�B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?’€?ÿÙTBPM0TCMP0TDOR0000UFIDhttp://musicbrainz.orgUSLTXXXÿûPÄInfo(!w  &&,,,33999@@FFFLLSSSYY```fflllssyyy€€†††ŒŒ“““™™   ¦¦¬¬¬³³¹¹¹ÀÀÆÆÆÌÌÓÓÓÙÙàààææìììóóùùùÿÿ9LAME3.97 ¥-þ@$|B@!w_»õ^ÿûPÄ1ªü@TØ5"L‹‰€TÇÿÿÿÿÿBhNs‡y�„}@3žÇ;çBú2¿úŸï!?úþ}C¡„'B�‰¨ÀbÊ€,=°² 7›âýcE`M.¦2 :ºJw� f}w§[?ÿÿÿÿ®�‘Ò�W:®ª…F Œø·BÒ5¥Ê纡Ö^³­*+R:kB·ß¿Û®Ÿÿßÿå™ü¾[�&8—Ub0'QX`€h¡eÿÿŸÿÙ2yÕYäÿûRÄ!ƒ)± @} 86`€³¡µ�àv"6‡¬ƒF” ³äÄÓ”š£ŸÃ=ØŠÿÃÿíçÞvó?Va˜VÓ¯S˜ä¤ËŒIùóläe÷M[#@~¸¨H'ŠÝz£U0¤fÿÿÿúZc{²™Î¤d îî‰tÖÇiƒ1ާ+Ó>b—Wn¯›¾·ÿÿÿüÿújÝkv}I*shìCÚ #9§™„Ä! ×u»kÑ{µjk¦¨™É+Q@·ãÚ·]šÙ+¶ŽºmÿöéFÿ¿nïâçÃWõÈó¯ÿûRÄ;ƒ­µ @×À÷¶aˆ N#œ4ìœHšW®JU?¦^gÍç=¿¥v„y*g^M)\ŒèÑZ¿½W$4>ÚdLN[Íûåú>¥S3õê*Ööß G_ÊxV#³B)ë´eT¶H Œ–šN@Ñk%©§GI,™eU]¦zQ.û«,¶-¯¬ª£"Ùõó·ÿõ¤~ù}ßJWò�}ÞÖT˜E¤>é ÈMŠB#–�¤D™?Èÿï–\dáO=!›Ÿbtph½'r†PŒ·¨ˆX.vlÈKÿûRÄWƒ ­µ =¶!'¡½…Ö.™|Ÿÿ÷ºùãnµXNkíÝbß aWIvȇ¢'HT'@if³³"rÙ•µz:ö²í£<êàŠZZVˆl¥VC¦žÌ´dO¯÷G+>F{)M¨¦³k-«¡‘§!M.hñqõ•Ò'ÆfŒz0@úÿÿúï�ºYïmV¶ígÔÖwµT†‘ x…!G!'GtÕ ÌgùÖ�2éK.ªüÖµ«mÞ“ºŠkœR1U¦cë’ë&ÈÊ ÄhÓF…ÿûRÄnƒ‰Y± = ¶ Ä'¡’�#¤´UdVißr˜Œ —N^’1·|ÓÜQêåZ=ÞÎëO7Z¶ÆÒ�}ùã�û³«×ÆwáñC¼[fB¢¯> ’†R*ˆŠ(£ ?ÎŒŽÿk;L¨�f*nS¡SyÌsfiÝT…*2ÙŠ&®ã;+È•ïÿ¦�µ ¿î‚YSõcY4FÚ™s­Î(M 4�q°È¬4EXuà�(ÐfJ8 vhã dznE"p z³3¬Ó¢zÿþr|í…ÿûRÄ„ Áµ@ 7Á#¶`È' ÷oò°×«¬Übß—w.Lû7eŠ’@K”¥)um.W§[MF¢‹vR6"î‘mÚvbÖf±QY˜ªGuJd³ý¾º~ü2[q޵öŸ�šŠÜfÊBýI�Œ“Ù+q Ñ áY¤û¾èàl;4·pÌ2!˜�äê£fŒKËCŽ˜…I¤«»Y%>®#Þ¾Ûøþ?Þ¯‰�y—³,¸b¡AY‡ž �,‘+�…” %*Œ?ÿÿÿËÿÿÿÿéíçX‘©ÿûRÄ–ƒ ³ =ý¶aH› Ò+Œ§º…-zÎv»c±¸F”ø1Þ�V”Ôß?Bøü'‘ßÈ‹ûßþoë$–R[ Ådt�¯# 4± KY$íq:4s²#M’ÀÊÀÕ= „gìdLt2•f;^«é�cµ]Lô[;£ÕS–ÕßÿúßD÷¾½ú~"‚i]1N^ w/jɃO)ª MFW+MÈ�6_+i¼oÌŠ¬ó%Èìéô™Á® )Ë $'¬ž\W'5³’ŸŸ6?'ÿþpüÏ&Ý™ÞãqÿûR݃ɯ =9¶ È£Xô¡Ùì”<ö =}aÔw¥“ꫜL»©ä¤NýÝgf¡V X‚�Š÷uQNkØJ$&¨gÈ©s©ÐªèÈ„\ôôµ?M?Ýÿ’ÛXßéCe+0Ylö¦Ñi4�,b`ø=@DˆWÿÿÿ-oU¦—ƒIT;f�Ê·j‘ ÇÕ’:ìtÑ… ¹ès5KÝ[$Ú?Ó#D ˆ§�øþ?þxç“ëˆÌ�ô¬-5ñ d_e°ÙSä9Ç$, ÿûRÄÄJͳ �= 6!'¡Øaþÿ?éö”`ÂI‰‚”]ÏKi»eóf;éi#R ¶/;:FSœ}LÄ×s ÓÔÏW¶ó£–=h¸c ¤4\jŒ" Eî A 8. `&¡ r ðäà‡å�¥?ôõÿñò‡¬¿-ŽB¼}åøåVAT÷QÞ>™Z­v_ÿWS›QW3µPÍÇ ›;ÙóÙN~U~íÿëåxJ§nÑ,¹!h,è–Ôš Òdj�-i² ¿DH\”ÿûRÄÕ ¡¯ �5ᡌ˜ËA€ J ŠÆ@ßÿÿÿEV"£¸ÌkÌeR‘÷w)ЬÇtz¯.æE!êK©nèÆvz¹W[ºûþúµu—ö¶ëÆ7”…N�J(ô˜"5±›Öó@ÁaL=#ŽÅ @ÿü¿ü R‡ÿÿÿ䉕àt½wiÒ«UGQl�wE²‰ì¬#GðPà‘ƒ°ºâNÜ#›±Î_ùSÌžž‘œ¬?Wý¢�“c‚ÃNB¥%©ëÎn_XèƒaåÑ0²Áej±ÿûRÄèƒ 5µ`‡¶à!¸I¶ÇïÿÿÿÿiòÌ—31˜[šÏ-¾y?ï œ””󤊮nK6‘â–ªÔÕ{±†yÕN~;sùU/µ¾ö¼½Í¯Š¸»k¡œÐMl0>Pø`ùÑP 8XLÆT,aLq€ÿÿÿþ¥Yÿÿu­>yñ²ïr‡•vá†Ïù¸JK×u|â•1ÚEf®´0’ rl즽þÕ¥éö6\on-dfY”š·®ßi ÕìÑ*¢'m9Å!D##à98ùÿûRÄèƒ e³ �-ÉA¶¡ &øÿÿÿ¯ÿÿÿÞü�"1µ“Y˜2 ÊiR+E½‹'Ç  NàÍOJä(aØ™dÚ%‡y©µþû3;%fr®g,«ŸXP˜¹üKÔ1¬´¼Õ�îS&!§“I…ó—–—ª°Ðÿÿÿüçÿÿÿb]ˆÍaI¤ÝÑÂàšW„=Ë»¨K=\ˆi“ÅñlÁIus?W;ŸñÉeûåß8g—UYñCcÂIêË®)M–VX`‰L3b3EØ„$TVÿûRÄìƒLeµ@�žÁw¶ ¦¨Œ<Â/ÿÿÿÿÿÿþwËMr:jdZ‘—uƒÊ@œÍåW‚ÉÉWŠ�ÉG’=A ‚Á.�yXžÎ<²,·ÎçîWQ`®f[:º+gdr´�’—2vÕ02+#`˜PH"(ø•ÐÿîM©4D6±Ï‹2•ÕJùݲn¬0^ŒgZ"‘ClV�¤±ÔªÒîEy~Ÿóï±¾²ü ‰ú…Èa5TŠ…W¦djj¨a#ÉÉTDL@Ðl”\Ò¶Ä€ÿÿÿëðÿÿûRÄêKq³@�= ‚¶ ³Ùó‘v¾Y™©¶q‰'þj»%#»+Ñž„l2ƒŘ$hœ^´ Ñ‘PIÄå/é^S4à?Ì›Ë3ѱ1WO\+uîŒý”† —¤:�!H¸€N /Š„sµ?@ù>ÿÿÿÿÿÿŸ;Ô)*_�ª¹jdJŒå$Ç™Ya´ LŒê ʃˆ „Ï8Ù«c¾ï¹ç}» Q©ûÝðm™¡Q†çXËïTQÙØ7(ÏB¢£Ääm�2• ÿùKÿÿÿûRÄéƒ ™±@�= q6 H¦ùúÿÿÿçlA¯û÷l|õ¿Têmš(þ™ýˆê-r ðm±Ôe¶ïȧ9Y™å¦â›þþcwßo¬÷OÏ̆awV­“¨)“dK‹ž°àðÆå“&Θxÿÿÿù”޲ÿÿëáÚ¾Ë �œ�ú]¹²ñ¾ê­\)„›�q„]»LBåÂU—RÐó†eNÞ~þ~W™Ïßž¾R»±;'––ZÆ×À\µx©,�·ÙKÂßM·ŽÿÿûRÄë }µ@ ;A”6à³Øÿÿþ¦/—ÿÿǘ�9sIBé¡ EËu;#XŠÊV¢�‚…¹Î—D8�TuGtF[Š‘.Ôïò+»0–õÍêl²ÑÇQêAŽj$¦?~ê•(@MNV'ž -Œ–©6pÿÿÿïúúÿÿ‘œ™P\Т/?ôéB%¯ZÖ*Jt¢a.fæýÁšÖÔ’p‰µ-sÿ.ßÿý9¿ô¿î?K=�¶ÓK^gϬÁ•Ö3‹ :--€Üý:ö„› Û`@ÿûRÄìƒ %µ` 7Á’6 3ØÑ Ë×ÿúµ6Úò²ä4�"ª(‡)�芢êCÕ°¹$3ÝXî-,t9XÆ»4çeSUÿú©Õf¨š?Y“jM¸ñ ðß%\ȸm ‰`dºND ˆÈVÅꀽWÿÿõÝï5’©î›k3·SH ~œëÍX);“ZÔŸQ‘ˆ{ù­- JIxeÞçù·Wýüùó+Ö{¿°òõLäo&�³I1ŠŸÔÄI¢ÈìD`5ÃÀh6 �•A1@�•²ÿûRÄëƒK™µÀ��…6 H³ØÊ$D�ëª~Çÿÿ‹<÷cb4Ås\\ÏB·ÐérZå^ï™n†åMÄÚS¼™Rg̺ìÏÎßzÿü÷×z¬uW¾ØÂ¥µJB‰VsŠÁjá`j¥ ¡‰ÈFŠœ½.ábD °òà0»/ÿõ)�_ Í ¼hÞecöÔ»éäcE3³ÔÑdÙïhÃ(·h÷ÚÎòƒî>¯ÿù‰^?ÿÿ¿ûþ»ˆíüuEŒe�Æ ©ÔQ …””Â:   ÐáÿûRÄêƒ yµÀ�žÁj6`Œ&ùÿÿþ_š@;v¿ÿ©­D üC0ðu"�,g¼C„¦ #6†þœ|¯“Å5„ùnÍÒ7�ˆ�¹ÏΟÞgržnßù¼´4ö7õÛ]å¬+Þ‚æaCÔÈO]:HOˆX×0>heÕ,�­úìÝÕ(½Tšn‰5ªâ4uƒ½é–ýŸ¾Z<�˜öÕë³ûã°gZ£¤ãñsŸ¹.îMózffvŸó�ütïbí³[Õ6TzäjY:ÿ Dâ*qÕ8†ÿûRÄí =µ@ 5Ak6a(¢at$;^‚Z,–HÚº­ �ÿÿÿ÷H(©¸Dzœ†3EЮe§3¦;&QÂä9ou%Ån C”‚d=+_ÿÿþÝèT»X™%8á< bHÃG‹ ‚01C‚ Qÿÿþ�53{ÿú¢°ÚsÉ–¥~ß|…™AÑ4Í�˱Sá:Ì#rm%di?2³Èïô½´ü¿çc_ût×™¶Ne [|óLL,�%é8&Y7™lõ:1¹£±ìÿûRÄì‚ ±µ @A}¶ ¨³ ‚?ÿÿþͨVÝÁ¿ÿøŸln4 �‘ò8õTÅû,EY¯ «ÉN57C“5TlÉ‚n{ Ó€¬¥=guÿŸéÈêYò¼eP–•‚~ÙU (i–q &®pH@)H„�©ŠpBÿÿÿý×%—7ÿµü)ýM>©-;c®k9r/©Ä…ä‡ áb]C‚†AˆÉëŠ$0äLYpÛõÿÿœ§oª½dV’{8ªtú‘Q 1#moHt´YerRDL(ÿûRÄì ‘±À “�=¶¡Œ–  ÅÓ˜]ÿ° 4zb£ÈfËþ|¤0 ¥  ˆ‚ªC•¤>ÁH›IV¾{¦×°å2l“)M1 R3ÿÿÿT·e£±ŽèŠŠ ÊU,1ÑŽ–$Á� Õ`Ò µ¬Õ\u"˜ÿô¿™æ¡…?«m8ëT),ùK_û¾^UQó3õ­H†©ò”>‰ò2%~#¯�øùþ~:ŽÛt(s8×¢¤¨†« ñ2F �ݱ`ôÐwk�¹ÆÉ(ˆ€ÿûRÄìKõ³@��w6`Œ§iÿÿþi3�m EMÿÿ¼È_nLDWcIÅ3“Ú ¨G!)\ÊyûE:ŽÇpÖÃ&CmMZÙ7‡¤ÿ–þ|º™ÿ¨ Èì&ÚÙžL™‰*(¡"bLÕ$"�]!*©•Qÿÿÿ S¬eÿùFg/’³4&g§õÑ Ì蔿J1¬ TÃ1ëK;„nå\Äšc(0£N´,òÛsüçsŸ)%�“‰ S*DsŸü‡óüóu�ûb¤ÅF䉜¤àüÆ\Â(ćVZa”BŠ ,`v�²JŠ• ´@�Ò·ÿîÙgs{ÿù•©<Æ&Nr=îyÎÆ¾¼vì8¿™æ’ö«XÛ;G们ªçÿÓ·íëÊ®£QJìŠÊ ÎìcÄ1ÅPˆ&4ÿûRÄïƒ }±@ ‰}¶ Œ§i85a«d?ÿÿòm?À2ÓZŸýÊfyÝÃá•QŸÏ)%[+lg®V£#‘¡^¬à��*�ݺ©�×êìÞ÷ûÛ¿/!rÈT®}÷'.�¢U惒¦Òç¢mÀ›Q\V`}f€QÿÿþN×�Lù¿ÿºñ–¤^CžêÞÎwÓ `ÖVq%Kà yÝ¢C=Zó$Ô‹:Êt¢Òòú^\ÙçŪ*鋃 É,m' œ2F �¤š¤ÿûRÄë‚ u³@�>É‚¶ ¨§hL›À�R)\ÚúášÿÿýSÙÎÇ&‹7ÿMœ"ŒÞ‡–kŠ: ”a!Á%-ÐÿûRÄé‚ I¯ ¡ ;IX6a´�è› ÿÿÿ±ÌÅp†@£¡,Ìßÿœ%èw*LS³3ÁËìÝ209TÄžs)ʦEtº¹T΋S©èVf{nÏFûÿÿÿµ:ŽÞBÛ¶'¨bZÔ(–HË €™í“Ì”¨ ‹j¾u[kiþî—ÿŽŒ£e aö¿ùezà’<Zõ2UÎE3-P¢p¢²;™�Ó1•Tò¡*­IÊÃv:5ÕÕ¦–WbÿÿÿÿKF½mK^áÆØ#.•ÿÿýÿûRÄëJñ±¡ UÑ?µâtŠ»�<Èæ(²äb+‘=í5˜‰—Ù¡jÿý�jB5Œ�t{·ˆ�J¼b"ìðÒÅ $/7“Û­Ê_ÿ‘fÜëæìË��‰•›{¾{9ï|Ú8>0 ë `…eKkI?‹²žrØÃ³çmŒ«Üó±)’Ò2þÎÔÆ<¥ØÏ•s9‰º!YÔyÌbM™† **:Ì×mÑU[ÿÿÿÿÝ™¨ö»:µdaö•�C (¹Š9»î ?ÿÕÿûRÄõNµà™�ƒ¶ ô!&ø£':¸—8µc…3¶ôéïsAЫõª'ßû¯4÷{2ÓKcÕ>È…X™‹eÄ43B3Ýn…ùŸ—åÿoJ§¹Sœ™Œc$‰4šFÌWU®¡"M3¥Ãž*j(Cp ¢rÝ« ÿÿØd<ͱ¦ŒD8L».ÿ Y“€¬=�{¹?]T.sž]…u¦m©9Ú�ÊÝ *»æ°›ß_ü¿ïçñõ^_Ýõ:­Vá[4®a÷’» Ð/*B„Ô ÿûRÄê m§  ­Ù”¶ ´!³¡£ËcD�œ§Çó�‘”¡Ð@ß*´¿â²ŸKÿ4#õp”[¡kUI„G$7)¡gÖÚ$ÍlÖˡγ?ÿÿûw§g»3vA„©Âܪ@3¡�îF$Êrï³@ÿÿÙ²ODd9ƒJ7"5Ïü¥þטWBMsé[Ae[íCPÐ� )ÓËË´ÏrSR6*O3z›1ùÄËŽ^ÇYÿÿó¿;Ÿg<„÷!MÕ]Ïfžá¦QCêi$zR²Ó`ÿûRÄë‚ é³  ±Ñ“6 ¨!§ÙJá€6µ�ÿÿÿ½Њ1�~„¦ÿù&GIÐäæZ Î+×·ÒzZ®U$·s…)iw*•·78YäQÖ‘U«ñ!žóÿþþrGÜsn[Ò„çßä‚^eÚiœÌU‚¯É�Ð.K*߬Eÿúô*å“3Yħÿì’"§íöš)œ³ÈŒó¶  ªAj¥hÜP £ ê�*9`¢ jÿŸŸçÿò¿ý·{³ç­2eÎ@ÎÇNh¢ÿûRÄë‚ ± �>ÉN6aèŠz´†Õ³‚‰‘$ ·mcŒttäÕ3ÞÞ^ó?¿þw§G/>}Š«ŸÃ6õÚWMH(€ˆçB1#ª‹F‰Æ#ÖÎŽ£¢À6ÿû?L‚V@˜‚ïóH€ä¾nˆR…•2»d‹·g�š÷‹[z¾àšÝˆ=Æ)ú,Ľ>el×î�‹h›ê©š¯Ÿùë¾úÿþ8žõi¿AšI̳¹Æ F<É$ñ �p†â„(¿r4IÿþÿûRÄï -¯¡ 7Ƀ¶`ô!§h( L ”�ã·t?ÓþûèºV¶áÈs5B¶U)8�&°õH?pÄ  ÚÛ«Â uÒ/5amë>åùÿÿÿÿþß;3¶únôY#šKC²þ-R�z¥ºÌÀ±i½¾HÑ$ e¹îÖ8fBÞ-vtïÿyÑfœ…Dµ³… óë=B“ÐszI›ba’ª\‰T’“]–_??ïÿÿÿ·÷;™{~uÚ²cÓIUP%€ŒC+‡0ç8W-Œ€ÿÿÊ-ÿûRÄç‚ ]± ¡ Ý ¡ã´�Ò{™ Ó¤rìF‡,ÈÒÏ'=A¼C—'émåP™ ª›ÊÃ[T¶³Û�‡&”�cÛòn•5-~Égù_ÿ‡3úiZ¼­÷ŒbŠàÖ4ÉÅ g¬tÉH,Œ2†¦!ipM4 ‘ 4ÌŒÀ×—ÿäÖË™ÉHÈÕ–¡‘“Y�ZËPÉ•”'#Y&²Ë!”¹¬œ²öJGü¿ÿö‘¬¿#“,²Ô5k,ŽF³Ï²æ_ù�Ë–( NŽF¡�¬˜‚šŠf\ÿûRÄñ Y³  Á‡¶!hšúrnªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªLAME3.97ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄì‚ õ± @oÙ�¶`h¦øªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄìƒË]°Ú €t4€ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªbeetbox-beets-00724b7/test/rsrc/full.m4a0000664000175000017500000001334615253035401017357 0ustar pieterpieter ftypM4A M4A mp42isom ŠmoovlmvhdÄLé_ÄLï¬D¸@�trak\tkhdÄLé_ÄLï¸@mdia mdhdÄLé_ÄLï¬D¸UÄ"hdlrsounÓminfsmhd$dinfdref url —stblgstsdWmp4a¬D3esds€€€"€€€@xú€€€€€€stts.(stscÌstsz.22""'-+1/+&0''&%)(-,*).)(*%)-4&6.*,$,3/'& stcoÆé •udta �meta"hdlrmdirappl°ilst©namdatafull"©ARTdatathe artist$©wrtdatathe composer!©albdatathe album!©gendatathe genre trkndatadiskdata©daydata2001cpildatapgapdatatmpodata6©too.dataiTunes v7.6.2, QuickTime 7.4.5N----meancom.apple.iTunesnameLabeldatathe labelR----meancom.apple.iTunesnamepublisherdatathe label€----meancom.apple.iTunes(nameMusicBrainz Release Track Id4datac29f3a57-b439-46fd-a2e2-93776b1371e0y----meancom.apple.iTunes!nameMusicBrainz Artist Id4data7cf0ea9d-86b9-4dad-ba9e-2355a64899eax----meancom.apple.iTunes nameMusicBrainz Track Id4data8b882575-08a5-4452-a7a7-cbb8a1531f9ex----meancom.apple.iTunes nameMusicBrainz Album Id4data9e873859-8aa4-4790-b985-5a953e8ef628¢----meancom.apple.iTunesnameiTunNORMjdata 00000000 00000000 00000000 00000000 00000228 00000000 00000008 00000000 00000187 00000000¼----meancom.apple.iTunesnameiTunSMPB„data 00000000 00000840 0000037C 000000000000AC44 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"©lyrdatathe lyrics$©cmtdatathe comments$©grpdatathe grouping(aART datathe album artist^freefree(mdatЃì\«11;Ä<Àøƒ¤4„ `I�fàe—^àï�P0#Ü·›�Áb˜Ä»VOØÙ(*¾J€q8òƒ„q©-@>Ťè[-3þ!‹rtg¼¼(ι¶q]b¥¸úƒÄPEÙ€€ ª°DãÙ‘>JUl3ËA$Ö)i)ƒÀúƒÄA#�€+:3ï`Xa¶™˜ÉùQ;«À±˜ˆèàöƒ¢" „Î Ž× óf{q wZ“Ä 3z¿f#)NÙq'øƒ¢" „kËr½ÙÖ£ g�§ý'”ê )y*¦˜Úö»,°Îµx¡úƒ¢" „r †BXVFìì7nhϦNž|z%ôe0Ue®«Œ œöƒ‚B„_`9åo¢ðJ­Dz0¯)òøáÛ1F8‘ú·åÉ>7t·#‹Uàøƒ¤4#ŒXÛõÞ™¾áàÒ`¸Ž‚Þ×xT†aGˆ~fäHv<ý¶ÁÀúƒÄ`? &ˆ×63Дl:äGàë’ 莵š„ÇÓëåN‚àúƒ¢R#Aש9Ï<³ÔiÇ%Öøê¦—µŠÍÎê®yfžÎôƒ‚T„ `®!�I}uhnV$?‹+ä¡(Z«„Á�¡Üta¥Vi±+±l‰8úƒÄ3#P�0¼ñ•T`’3¹èžÓ#?}¥ÕõÚ»ìÔ‹€úƒ¤Q#Hl`µˆÁ½¥ËK§)Q)E‚ñõ>O²Âô¯SÔ¦úƒÆ"#P ÛdpËŸ¿Û2é­~sÛÈÓï�'Pîì=Í&ü!úƒÄPG<Ž0NÝÍ�Eø™_ƒõ'1…:õ˜‹å\øƒ¢ ˆ,l ƒq¼Ôº<�¬>èðÍ&ïÞ¦J3}•]dQ€€8úƒ¢`F  8I+–¶:aá–;0¥Ç>m>;ßM¾íÛ�Ÿ× ¥/gøƒ¤p>€ÞbSci›”¤L z:~H�5ƒM3©'°A+è&„f ‡Ö(pöƒ‚0!dÀ¢’¯:%¢C°9B³î+]þ3Z†¹ècJr†Â¶�öƒ¤`E€�a,]µ)\BiwÈ,yç@úD¸ù�ü'ħ¥¨Üøƒ¢ ˆÐÀ€0qóà=bžmBÅAwùH°×! šDSª� 8öƒ‚5 !`Â4†§å^ñíª^:$9µÏ…gs`M%…ÊZZtª^U£Y(o€úƒ¢"ˆ¤09œ’#NÑ·#̬zÚW›;t A-1dyß”3¤^ àúƒ¢" "ìFâwì¼ú„,µ¸rŠþ¬js%”ŸÒísÙfžep=¼øƒ¤`G €@ÀãÒ5?à¼`•Ø�ÉÍM²ÈöÆýYB^×;C€øƒ¢`BÈ ÆãiRø—‡iéŽ6ˆ0 9ü¾åÓvë…(ÜÿÿGYJ´…=˜¢oçlÇWøƒ¤3 BÐ3ÜQhLÖÆ$/ê‡b<÷~³µ8ëûÛΚS�­n*jõXeÅ×7’#àôƒ‚"(„@Ø Ad¨*Â`óÙ'ሬÁ®co·>Vûça &µ% øƒ¤`F‚ ¢±äßxã}¸<ëÊüfP[2ÚqXä.Š'Iµpúƒ¢" „¤*ÓØšÖ'êŠÇÉR™z[oÝÓ¬ía‚„¾”XÇS2p'ÀøƒÆ2! éZðÞx²µ¾ùìú$©¿Vn´%j(óVÀöƒ¤`F‚�€öŽ�F†@›c}}ðCÂ2>Û<ÆçO5£!¹QÞ/grD�ðúƒ¤aBàô‡2‰´S(^®Z�dð{¦P�¤Ÿ~‰ÙÛ˜¦‘6 Sºœöƒ¢ „,`¼-1wNÞAÀÍ”XPKh¡wKÛ#0R¬Y±X�-Àøƒ¢`E� "ÅImq¤>w¢È1s5{!ÁXº[¯/æÛ?ÓG�¥xøƒ¢2"%€Xä  aÔž®ŽæÏû©ÆÏç¿÷º�r¯˜LaÀƒì\ªRi"?pƒì\¬ „ô@À\beetbox-beets-00724b7/test/rsrc/image.ape0000664000175000017500000003370715253035401017566 0ustar pieterpieterMAC –4Ü3Ù0' 0éoÅ|ÍþqôèîˆD¬D¬P('¸è+6¹D€»…›gz¿ãÿnè±`Èé¯CÔC-]áXUÚ½ÛΈý–̹€ËRôa‹% –ýÒñ0ó©'lOéØ[&ï(ïïHõ)œ"i%6aMJO1FÅ@…D8Ùqlpù¤ŒE ]“¹$ê åýwëvy0äÏ\þv7®Œ±I˜®Æ ̇m7¥.uMÒÉè$Åý #­×x|‰SŸúgb;<·|:}|{H?k¬ò"ÁÓ{�äìæwß áÝéÝ¡"v˜útŽ`OM".ÿÄ+.Ë÷"q=f“; åF&8e*’<û´íH4ŠÈiçÞ-w»´7rý:¤Û˜œJ� \ó!¶Ü$W'8[4“ì«„ËAvìMXFÊUÄÍ�HU®qta!;{;ªë¹ ÊÁ­àG^ôad¶Gê™gŒ¾P¥­)«Œ·È úîØ™ÜzИšSŽøg_êˆQ¤Ü=ÏS ªù¶¸âèM¿‡næ”– ­u%ã÷ú¢ÓÁ8½ Ì úx«=j]m6“aú@�“I›L]ö~çên0.*§ãÏæcžânQjŠ0‚ôêí‰6j®ñ1ÚC%g§�4ß\-GhÙ3Ý•[èàH"’—ó@ù>¯3°+©ÙÎÿäÜG½ù§W3r˜ÚKn>œÒÚ+{ç²òô·Š¬´ &…ñ6u¿_zêmeS)K+2òkò± éØ8ôÝ‘c¼3L®ÝÚí�Žªv²WܸÚßèÑ‘�¶Yຓ@§1"kâr}õqIÆþu ¸ ¡©[#ØÈôð¦‘w“f•—C?s·”b Œ[XAÅÊ Ã=‰‹\ ú„yäü�vJe¹•ÙׂfÁ$0²¤y£ž}:ŽÎ Ø­ô[èr‰zØ>Q†Áx �„“(® ~ 9Å5QþK�¸ÓÓÈÓ&)±¶‘9jÜa¥«`¾ê‹A8¤Ì×– ”©¿ƒÕ"“à†;bR3¸ “D©�W væÇ)ãϳS›Î£Ž�ÚÊ̲A}ÏÐꂇTÖ‹¾DcXHwüWE>Èà‘'•:Ð�•ÈœÄqqoie4>#�÷ -&}ì#}F�í5pÅã�±ã³*"•(taà¡ÂàÅ“"Ñ)®BÜ -·,AEexj¥ŸòÚ†›ûu®R�H×n_¶n¶(ö¶Îâg'v9HÃ^%Ü!?¾"XÎ@µÛÚ6×›R÷…­‰¯ÌÎyÔÆá=ÀÏ‚ö¯–8/Ö3VõMæÂ»8¿±ÿu!ð™rP@ÄÔ¯ ›“øqSzá~åjwñ¤xTèv¨TÚ.'ÿî†>ÐäÒš?Î`XºùÊT÷:™—ýÌ Aã?”1²\@ðd±Fâ|ɶÆD½‹°6õ Xõœ“4„,ˆðÁMÝR¿#÷°Œ¥&ìeõ¾­E„›ŸväÊýS²š+vWÈãsJÿËžýxñ¢Ìœã{ö[·>¦pQ… tÿ³òŽ)®Ì ¤Ç`ãmnX±^xõÚ-Ç®“©=®æ�´|�t¢Àr…βþ‰¹!ɰvÈ ^T¿ ßN‘k1½9¥#œÞiÔ[@ÝöSÉ‘’è&ÀÏvš¶¦_Ö.¯oþUœ�æ÷ÙÕt÷xLÚ½êø‰H/ ‚Ïm…Òfè¿ÃÉ‹.y Æ8Ô÷KüQE¶p:•7'§Nn¾„ì 8lh˯îo=›}¯¾•9P}Ví{sÔèÿŽ�ïnsÀXiVÓ”íEI€íH=ÒƒõsºK—Î{ÍÁ»ØÒcyO€g›¡P˜û‘–õ‰¿ÉÅþµ\3yy8#;çtº2‡ÿê[mš ©í‡ÿ‰y0˜ÚäQv{DŸ×®ú3@ä ã­h½lXÂqKž!®!õÐÖ¹ú§çÚ‡ŸîÀø–�%5Pú]×|¹õ´††#i2‰öíÍý Eäùì›êLÿî­ 7X¥¢)E»[Ýá[Z$ѾƺÅ–½¿îKšW¤¥ÒÜíešY#ñÙ,‰í�Þ„ì.eÀÒ<Š[èÍ؆,�I#ŒôÒ·5´BÚ ¢6Ìå)¥ÙùMP™12]ž Bäã'‘i"’-,¹XQ3Á™€Ø_@øå©ÆY5ÎŒDd�m P Uëe*zï =ý…,òc‡-¿gCó½6a‘¢1ucô°,a$õÖ×zܤ æV‚òÀRå “”$}ôÇÅ~ï¸9EZç1°H.1.–j¸¢î¿Ÿ{—N]aL·.7 ¦¯€DQ‰l¨°Ùñ‘±89Ågg˜­vDm˜ê^żäžïðDUV‰.’‹ „OX“EV½ñúůſ>qáz¯™Q}(¯#¸MoNªþ‚,–-ç~bûc–97þƒÛ W_ýÚ 'sžNYO j]feÈu´Ê6ó݃3¬¥Nâ‘+1g¸`äjÄ;Vn6ý²pf_OBdkàžpìuÕqž\HM…k�ûÇbµY2}¶PÏe'¼ÒqCG¡[J�ì7‰P~Oëê ’k¬™‘Õ3“/—A ]%†°h@ ozWÇlýÒ0—u¹rî[ÿ˜KŸ}–ún²gþÌ@)E¢ …/ï׿•A ãì�š¦›ŸÝéFz ‹ìӓ͸B‰@[Ë %Û×á!Ê~nÂ8o¦®H#7±=ªðG Ÿö¿qÍÐóв`Kaÿ„íHÃPXÙóú{ Œ¯Þz“ð|\+Èç|+Nn{W´*ã›Òý2†usá1\$«J÷‰µ®E3Õÿ°Û (ÓÁò‰¥Ql µÓâû¦ˆ\õ€V 6°ì¶†RÐ-]ú–SÑM¬´«}.ÒZ+í)BÏw{”û]ò�×¼BôŽ £[Ú~š–’‹©–uÖêk‹§*ë[“Réù½¼ÈƒKñ^ÿWñ.ý�yx^èS¥`¹ÇXñ T�9 Á‰}­ ,f%cò¶z¤Cdð°‰/oûXfÍÁgî/òŽæÖLb ãz¹IÑ9z,çik߸m2ÃHßè:ÚÈ™U3±6ê›ÐÔVà-­!S)­Tµþòt —Ãߊq‚üãÎ4zM’î=03mcí(f4E×Ù9¨˜Ji�#çØ$Ö€²‡.¼¶½î—f¹OÛša—¿ÇFaöæoËFV¹68qc•ò:u[P¯_«eÒžfàëf›ÛÖ»�$;R¾íŸÄ=§Œ‘!M�Æ—íS±(ÙbéLI�çoWÙ>òŸ“î铳ÒÓ¶—S{Iî=C.…ŠÛÍ'ÃÎ?^“Hut†q§¹›Yn—¦´ˆ®1o2²�òz.½ :L�?ÑÁmt‘¦×x) Lìå\èíöó¬�©K•a¿´¬p\!)ó §÷¯P#û…?#™ðÆÎêX58æ»ù޵¸*l¦&#àp(müL‡3–B±AóéV$®ò÷\Ö^›G�4–Øï”y³Þ°"Q’©s¬¯aò—R%VªwPRõ±ûo�ÆuÒÍ‘?ºËèðÔø| ÑjÅÆ ˆßFZ© Uíçíw¦³ÊåÝLeòt—Þ¡£±ß\®]�nfÈ yø*e6úŒ.ü¦”P��èZ Öâ‚ º!ýi…ï«{ï¤Ý†S¶hÚëêØgeyäÎy&úñ —Ê6#ˆýF(;`;S÷íþX·à‡«¶~Nþ>^„Æjß½#䬭VÏ%Þ†„Ød8tLí¥ƒÚF:änœ_ îõÈxrr«åô± „àŽV¡ÿ—;œ!ÑÆüHÙ¥©½IÄA�º_\d™êÞYšštˆI˾§ãzÒ!¦%,¼"{–( –ƒÆiðÅůÓïI«»ö�e²¢mnøq¥ŒÉ…w³ËX!qõüm­~"œ.Ã5Ì08¡8’ëA&›k÷y»pÌÝg¸þä¡!O úÆ5Ò/#Fv²Ñ¾»AßaI$¶öùIM$éV]ÆŽÎtõº˜ ¹ˆ\€�^ö*­B§X/e�`{Æh ÎLóê¥5ÎV4híE@òEÁhŒ�2²H1C|ggÍʳÏß® :O­ —B¿ ¸9’Œ0²ïXwTl}Š$4¨é�]¸ô‘“l“ÎôFÝÞ¬½0ÆeSbŽ+¿’í‰<ÑL¸J‘õ^‹!h�òï¡SiûA �fa‚B$?é×ZAt¸# – =š ü¿ÎGú—çTûÔûõU¾‘‘+FèX §L7ÿ»-áãx»µ¿˜Nƒ`¯Á�„6$cöÓ ÁÂBÚõ:—þN’mkCØ=ŽãF/}8âÖã^ÚDðAs¹´®#x_™•C«KT]˜ÖƲÔ¾½møa×á}üo† Vú´âä‚€ +Z*³N÷·G�°.™ IÊ›êáS \†Ä?ΤRý}-Jzã¡ÖbÍ­wêµØµ„ �…È�™_’ä7¥Æó¥sRáÁÅtÍ­n—’ëT;×ñŒl CŽS÷Q’ë¥Õ>T¡ã‹#A陡¯:^¯hõQ”ŠåÚÆÐÌU fB\ÿœm˜\ÕMrYó^ù`—A‡ô–œEëQˆïZ‹’�ÿ̪™¾Ð8#”Ú:V:ÞgJo’C‚ß0~×}”ætž4$¥ºóÔò°Ái“@b8epÚµÁµíÆE+˜b÷y–ßb´è³ò„«.ÓÐî˜v0ù›™H9û('�%™ÎqÓÁ‰‡N«)†{œ‰b²§?›,-nþ x½k Î?UT…áʰ4vl”¥P{%ªÝ‹vÄuݦBnðC¿jI÷4CLJ§�ì³Xk?fC¯åjpõß¿h×q”«ì�50RHU*‡ÒØÌ-m‹:Á|ã5´;Q•›µß&¼ùì¶PérçÕnŽŒ�L‘Uçò×5ƒ÷©yéšI,OY¡*„áùŽ“)XLÐN5 8ð‡L¨Vá6«³W 9Q R#+ކ K¢ìýäXÜg.náá2Šá»í2KÒØ—ïTõÂÞËÇÝ„¥F0XC‡,S_ç-ÏÔ,ÞÇñäÄÜà–¸‚ ö3"¤m²wr•‰kBÇR‰žÎrêK¦Éå.yú°V:±Ü;â *� 0èk½—V¼!¾“ŽBçýê ÔŠ¬±ˆì¿´Šú祽ò´D…¶ïbhtÄ·+ǵ!dƯ¢t'UNa¤…‘øÃÈÆ³RV»3J†™¢ñqôòï(Öô�<xm%cw†8Òž gVlz/˜ZÀφ“é{ꇕõGï@îv�•“pذU×ML-wmÕ<õ[ü ‰ŽêiAå8\0"k87Êž??—…� Zî"¶B'ì�ry/ Œ¬G’ñ)Ê•Hœj¾d/¦EÞLÑÆÿ4×8éG©Vä^LÁÊr1ÿ›¤äP =£¿g�Œ˜(F݇VÅÙY´ü4Åd•SÐL×ZÄÈÿ@,Ú†qñ­Û÷sUwOéB©Ø�‹ðáiñŽ$B¿ü(Ü»/ÞœSÀÑùdñëŽ3{Y¨¸¶ÛAò¥ ÙS'¦êçX*=eB3;näŒ1 îr§ír™‚ÊGÛ¶šãÍ®TóÄÍ <¼Ìžá—‰šy³sWûCáÜ=ªÝÃIjÐyg!=°Š¤�m¯\2£ö}bD!bë¯}ÂWœš�¢åÐÓÝ=XØj´:×…*hýøA81 #$ÄcØWfš'çF]iJo·âY…ÿ�d çmdÃß B~!=9- •ÔµþÞ yMMfª¿l�p‹ÙÞuÁßá°æ•¹6¹•]«Ùøk²¨6´%{둞: µ·Å³ë₍ï�û`眺!T̺p=�ygxæ(q–˜®ÈZn¼@Š�E¾ûö½aœe¯c6ho†Uè�Å[óuø"Ðï¤}†aÌä�“ÐÉ>:óˆŽ)ß»^]Q¬˜#õy«‰Câ«9åÜÅÎÞÑÅ…ÿG¹DZjœ³í&⥎Aà=ä²½um©q>©jJF¨’!ÙÍÀZ »{Ê^Š©óf!— o:Kç\tÚJ8™X@ —úÎj Ü4«º;07:MóÑ!©çñ3Vï‚€dܱ MÝppËTýµ]÷?l��órˆÔÔV/b „Ö†68¨º.'“[±$ƒ<בiﮂ¶æŽˆ¿4 Í®§ðú€1Ü�ñ.†úôÂ~pç”d>?ØÕ¾æw‰8­±P¹Lçbð\8Q·Ì²mï�f\ ƒe+‰õ½Í® ù?Êìªd)dœ“ÉóŽ�¥µ„�…®W™®´ÑIr$YB8v�@Ø 06�Šf%¸.ý·�Ê+1_Ê£€Ìî^Ѥà <•ºîp[GépÏŒwÌ ‚ìÙ´EâÔq6ÛªƒñË´×›ý�_ƒ-/¼‰kç qNúãKŽñLDu÷ïá’ c_DM!ÌâçwsV·¨¹ -ðUÓ÷ãØŸA¯�Š´¼q®g@Ukwíìp~SE9½tݲduÍ�tÿ}*Á&ïYe�zÂîÛSÙñEóÝâ=|çÁ Ʀ ;ïÐ<_�oâLÜ�òÔ|’'Y÷ûÈá=‡2¶y¢nï²Ì}VœúRìtOæ¼ þ•A0gÎ:KÉ{‡ìµÂ]è­I‰}/àÀjóÒ�ah•_t ®I$5‘uÌ&.µÒq¤2ÍÎ^¿w…dMMOè1-)zàuñÃX<Û]ÖIâ ŽÈ" Ý,ˆ/g® €ã|õ¯˜>éŸu¦¶ËÀ9ÃVÿ�ûžÉÒ/ò5k€ì-!“[Äø&þñŒ FÖ Ö{ëñq±ØõwhŽ¥ æéyõ3²]—æäéˆÛÛP\5NDùìÙžožcAÈSéâVm>[þâ}kE:Ž"üºÍTÆ ?WŸ î'aï3QíjŠuØxgÇúnrj–èMQyµäçŸÏ�høV´W†–&ÞÿÛEÙ)ó–È«<ªýLÓmÿѵJEöíÄDâ|ødæCj¹žßA§+äˆ׉Ôwˆ,Ý rcÆýMÜ­«M“Ïפ�kFKg˜ÓÇ ü¡ÇZcxé ìÊ)lQYŽ*Ru¹tO’2¢¼^½òµW@ýäÞ‚½ƒÄÐ`þÜÂT�¯šÜ† fCpK:©Þl)Ü9Øc––Mž¸¦ß®&)n,•ì‹Nñ%ù»ß4�ç{Ä?3�Ð^@>èÈJ„.òE|ƒ 0¡×\�ì§=e÷7üØsÉZ$ 5Þ«w? \."<$Ó)´�ßpäRwèƒÌß6Î;nì\+@°ÃiÍõ”ë–Rxã7Öî.V€~傦Bmk4ñ@áé‚%?-f$1¿²ÍFbñçšã•²ßPïeCS r:ýJ(üqÀf‹µ9âç˜äˆ¶L iáØÕÁNS(†î)»%w–yûyðS(Ô$("­�¤-­£H2Á‹²f>šËÙVïà$xbƒ‹žsÆhÃ%uÎIíòm+'ðNÝç�d럈?¿põË—8}ÖÖÊàpÝb�è�î§‘™ßè¬�à̈ŠPÄ«¯(KL.Íg ¼kH¼a+Œxé‚3ü1˜›+éOéçÌ…ar±7& ëÁvõdVóùOÉËê6!ï3ÞB4ÿø,F|sÄ·¡ž¦ë¿õw@*B`Ð_]æq>ù/ �èÃñ�½ø�×Ô"êÎÇNiK&”…=.ÿh¾À-JÓìæÎ;RvÓõ¨„À;YD¯ŸðÂpâšôT>JmÑØ„§3a¿ÕS ¬J+`Õ=*ãŒ1o05ÖY¼ò1¨k¯2eîÉÒÚÃ:ÅŽò5IrÝ �å¬WÚ1Ë1(£ X=~É`ä5ø;B,ƒd—´5ŠB KZOù>üS.�TÝ Š é%*¸ŒźþíoOú4yJ˜Ô8"B‘¶`G YSôâ#Ÿ‰ U¨I• 1ú÷nùäîy)~Nj7��÷•ZÜg¹\|¢¢EÐ «ÿ«0‚ŽínSîÅ�À¼“UúP Rf=²ÎÒòUE¹!¿_’šïÛ?~ åŽ+æΰÔ[£!W;þ#�„µ‘ú%‚tqšeŠ*ÚÅö»˜ÊŽLð û‹òY9WTd Ê+¿vsÓ~Vò!@œº’š�Ý ;éWÉïl�ÑÚUéf€æ6€ÒG¾�´y ²ü–¥%rŽŠLb@çå-���,ßÚy Á¥Ý MxR ä¼�o^‹ÉüdçN¬Ÿôf¤ÏóÄåmà% Û1÷[òKÇ;‹.žúBºÅ,ý�¢á:þ£þ^§ÁÌ&µ> ê/!†3|Ö«SÞ—yTßF?øË0E22¢>¤jQu?ìžx€©’ûî~$[Ó«™8ô¯ù{Üw!?I‰’a ×)!ö@à°½È@¶ jTz\žù+þU¼•øÐêêÆüß¼–T½Œ‘£ºBŒ+.ú€Ý%Û'±Zú oMO™œ8b(ºÔßg.ÙØE·�ácGZÒËêŸB—æ¾Wx‚»5õÔ0¤'œç##9]!@&˜Ìó�Ý¢FýL†FŠÐ*ß•Âa¤6˜ï`­£ 1\j¶Œ©ûܦ#ÂôÊÁ«ÌÀ5~µZ œ¬;s–í¹ØŸ¯o9­5 :!Ï$½—¡`môŽJºÒ¨ÑC+œþH;q !LO‚ñ�ªá’b�5­O~ 6D„o§õÉòÑkCZå¹@ȶD›©t†xÅø Ûõ˜¿4‡ï¬Ž<œŒU§9ë—žægù²Ÿ•ë–zÛ"rU¯ BœŒ‡,¿|¼?;Éùñî¾²ñ0sê�@aŠ€Ë³�éYòó:‰’@5¦1ñq±0ÆYDãc:âPoBê.Õ­²WZ²ÍDL÷·ÞÜ ÅìZ­°ezž> \_¼7tm–îÓë9&¢DütÉð—Ü•hI >kæ…F€‡þÒLöÑqWPBX`á#¦´«ÚæAßùþƒ#ÎÓXn³$u1�Y ÀuÃ|þE)èx†H¿õ.®-¿\t¿<7¶dÆ®(ìTü¾%ž(Í‚%Çê–¨«¸™Ç¨-’7ï±=ªaß’Ö±ü@†?À‘ÈT¡}ý‰öó·p ÷§àp(¶�RW‚»\ŸT@² �ž½îâ²;)BhôR9ïþ÷ïß®�ã«´ßì?}_™‰l¿ &°Y–ˆèê½odŠ‘ô*ƒïðÊ¿d�D«´âí€�Ì ³ûª]›õëha >ôyTMp´2‹¸e q¬±�8/ߟjÈ ÚǫɿÀÏ k³ Y® ¾ m’èº].Ê}ûß`æ4Ê�1Sy˜;€à,ɯt r!Mƒõ1Á�:°/i)¸X£ŽŸçÌa‘Xö–ø 4ðˆRš(Œ”ŽÕÕxºäIfQ3så/ŒÀ†Ñöž5ÒÕÃ',ö÷,½Ç²ªu[rwÝþ ÖÏn i á‰Tç†Ó9�XÏs§³Šè \·Ø =ºœôî˜1 "¸coäÅ/ê¡ã……¶“ ƒéžk?'-ÍHWªk …ukÈ1 0f›-Ý�Д˜¬5²gñéãªøÖc˜» q�;ˆZÀî5\ÂÓY5*÷[àØx–Àñ¯ß R»Y b¢úÄ_(%�…×L™ëa h²§5(·yÓn>�‘›éDŠ-¤Á»ˆ/HòÒ{uäef�/TCIÇ·R+FlÁ±øÄ» ÷UãÚ8ïúfBûa¦Þ<š’9 ¡ŒUvnɆŒ`g K³1–ŠN�Dß·¬ ÇL§? :ÚYS3oÜ 2b~ôg ó(š/¨y'æ”´¸ç@I%�JšZÐö3 lülŠY±=± ^!ua¯¼eAöè(†Ÿ34þܵÿÏSºaþ^ÀrŠÑrmgG`+n]8Ôī¿‹ù¨ˆ_Ã`ñ øHpn]á¼.2Dìò{µ¨ðDáÁí¶|’�>– ÇÓö~­mW�ÌÚxI�#¯g—zžÈ;‡*Õ~¶ïÅ ¦ëÞzi�9§6@û<û²ÂÔÆºI&o /Þ…t¯Ô,ˆ=?«v•s»Ü¥ÒÎ @™R)e~3ÛÑë�ûcêhiI�—·Ë�¸¥9«¾9Ü|F{ÿC2V1��°÷ÞSYêôše�@µ 9_,˜ í ñ9%¶ó£ùÂúÃbŸ…#æ2ä`O\úÈf+e^ìϦ�ê«_~úÆaÕgÛÖ;¸i † ï‘:§3mmØÁÚþ„ Ÿ{w©!dP-ÆæSêg£0ºÂÁ[Ü{efOŠ ˆ–s@¶ôÏÑ_!”um²hñM}õ!�å‹ë+Ò&�‚6YH C‹DµÕ{_ÅÅЧ0T7m`)C/4 Õ/a‡ •uâ©}XÛãcF ‰›Çš“SéºÄGÔÀbý�zðó¹EísÚ‚X¥çs ÚÿÙ‘žÿ:°÷dþ%ÎN—fÉóá ôVÍó ç掶¤CXÏIýóê +{A:3�Î×\4ñ&0]-k•ÈM$8£Äúâþ…éã§�jë]at ¸ÿ±/æ‰h& Ì(ÞŒj MΜûÊ+˜«ó½ãϹ¡ÇÉ8,'ÂC²Y0‚ùnù­eCÄ«®"¡Å«B¨û1øêåŒù�N>R.pñ1ü§)L­©Ó…WRW‡ÛZû°Ålÿç„£ª–ÝŒµé¤ &Ì‘ÔÜ+UáÌ&Ú«u´ýÝÖ~XªÏ"cÁ"l@u¸Ñ0¾ùòÈý×Ó'Ø ‚S¢XŠÀãZ¨\%téÔrŠ‹n¤¥5Ìç*¨\QzáÆ=@%â|¿øÑû.TÂO"µØ¸dGúE"sXYà!¾äx�­}M§ÖÎAdL¹Öï�„\•«üóͽlö·¦²ñeQMY¼’ãÆÓÑêìÎâ�Ðò^§ŸºŠÚð­)è›òê)—*ñæö} q ç‡ 0‹ãe¨ÇpwvšÓ æ¥I¯¼ØW‡ô,2_FüZl�à:Ô%,,�Ü!º9¾…yÓ”)[�~CZD,ÚëM“ß|NÀù_¨ÃJ[‘1hëäÔn¥Å-ª^÷rsÌ«§ymLBÁ÷Py‡…ÿk#”ÑQ{óxÅôgü[ ØH¬­a¼ ù¯¤w¢wGÕŸù^;Œ<ó?ó¨<¡Ý!ÆbNmÖð<^Ë´™É ýPÖË�Ò6»y^‹ù¡Ð†¤¿•;Ñ„@Š¢¤vf+]û²2{æ¡ÜVFªÚó¨e¦&™k1ÕVîj6¼_£™f½×L2bJ¯SÌÙmý�«3QIÜ]¹»ÜÖæ_Ÿ£‡ð8øŸb—Wn¯›¾·ÿÿÿüÿújÝkv}I*shìCÚ #9§™„Ä! ×u»kÑ{µjk¦¨™É+Q@·ãÚ·]šÙ+¶ŽºmÿöéFÿ¿nïâçÃWõÈó¯ÿûRÄ;ƒ­µ @×À÷¶aˆ N#œ4ìœHšW®JU?¦^gÍç=¿¥v„y*g^M)\ŒèÑZ¿½W$4>ÚdLN[Íûåú>¥S3õê*Ööß G_ÊxV#³B)ë´eT¶H Œ–šN@Ñk%©§GI,™eU]¦zQ.û«,¶-¯¬ª£"Ùõó·ÿõ¤~ù}ßJWò�}ÞÖT˜E¤>é ÈMŠB#–�¤D™?Èÿï–\dáO=!›Ÿbtph½'r†PŒ·¨ˆX.vlÈKÿûRÄWƒ ­µ =¶!'¡½…Ö.™|Ÿÿ÷ºùãnµXNkíÝbß aWIvȇ¢'HT'@if³³"rÙ•µz:ö²í£<êàŠZZVˆl¥VC¦žÌ´dO¯÷G+>F{)M¨¦³k-«¡‘§!M.hñqõ•Ò'ÆfŒz0@úÿÿúï�ºYïmV¶ígÔÖwµT†‘ x…!G!'GtÕ ÌgùÖ�2éK.ªüÖµ«mÞ“ºŠkœR1U¦cë’ë&ÈÊ ÄhÓF…ÿûRÄnƒ‰Y± = ¶ Ä'¡’�#¤´UdVißr˜Œ —N^’1·|ÓÜQêåZ=ÞÎëO7Z¶ÆÒ�}ùã�û³«×ÆwáñC¼[fB¢¯> ’†R*ˆŠ(£ ?ÎŒŽÿk;L¨�f*nS¡SyÌsfiÝT…*2ÙŠ&®ã;+È•ïÿ¦�µ ¿î‚YSõcY4FÚ™s­Î(M 4�q°È¬4EXuà�(ÐfJ8 vhã dznE"p z³3¬Ó¢zÿþr|í…ÿûRÄ„ Áµ@ 7Á#¶`È' ÷oò°×«¬Übß—w.Lû7eŠ’@K”¥)um.W§[MF¢‹vR6"î‘mÚvbÖf±QY˜ªGuJd³ý¾º~ü2[q޵öŸ�šŠÜfÊBýI�Œ“Ù+q Ñ áY¤û¾èàl;4·pÌ2!˜�äê£fŒKËCŽ˜…I¤«»Y%>®#Þ¾Ûøþ?Þ¯‰�y—³,¸b¡AY‡ž �,‘+�…” %*Œ?ÿÿÿËÿÿÿÿéíçX‘©ÿûRÄ–ƒ ³ =ý¶aH› Ò+Œ§º…-zÎv»c±¸F”ø1Þ�V”Ôß?Bøü'‘ßÈ‹ûßþoë$–R[ Ådt�¯# 4± KY$íq:4s²#M’ÀÊÀÕ= „gìdLt2•f;^«é�cµ]Lô[;£ÕS–ÕßÿúßD÷¾½ú~"‚i]1N^ w/jɃO)ª MFW+MÈ�6_+i¼oÌŠ¬ó%Èìéô™Á® )Ë $'¬ž\W'5³’ŸŸ6?'ÿþpüÏ&Ý™ÞãqÿûR݃ɯ =9¶ È£Xô¡Ùì”<ö =}aÔw¥“ꫜL»©ä¤NýÝgf¡V X‚�Š÷uQNkØJ$&¨gÈ©s©ÐªèÈ„\ôôµ?M?Ýÿ’ÛXßéCe+0Ylö¦Ñi4�,b`ø=@DˆWÿÿÿ-oU¦—ƒIT;f�Ê·j‘ ÇÕ’:ìtÑ… ¹ès5KÝ[$Ú?Ó#D ˆ§�øþ?þxç“ëˆÌ�ô¬-5ñ d_e°ÙSä9Ç$, ÿûRÄÄJͳ �= 6!'¡Øaþÿ?éö”`ÂI‰‚”]ÏKi»eóf;éi#R ¶/;:FSœ}LÄ×s ÓÔÏW¶ó£–=h¸c ¤4\jŒ" Eî A 8. `&¡ r ðäà‡å�¥?ôõÿñò‡¬¿-ŽB¼}åøåVAT÷QÞ>™Z­v_ÿWS›QW3µPÍÇ ›;ÙóÙN~U~íÿëåxJ§nÑ,¹!h,è–Ôš Òdj�-i² ¿DH\”ÿûRÄÕ ¡¯ �5ᡌ˜ËA€ J ŠÆ@ßÿÿÿEV"£¸ÌkÌeR‘÷w)ЬÇtz¯.æE!êK©nèÆvz¹W[ºûþúµu—ö¶ëÆ7”…N�J(ô˜"5±›Öó@ÁaL=#ŽÅ @ÿü¿ü R‡ÿÿÿ䉕àt½wiÒ«UGQl�wE²‰ì¬#GðPà‘ƒ°ºâNÜ#›±Î_ùSÌžž‘œ¬?Wý¢�“c‚ÃNB¥%©ëÎn_XèƒaåÑ0²Áej±ÿûRÄèƒ 5µ`‡¶à!¸I¶ÇïÿÿÿÿiòÌ—31˜[šÏ-¾y?ï œ””󤊮nK6‘â–ªÔÕ{±†yÕN~;sùU/µ¾ö¼½Í¯Š¸»k¡œÐMl0>Pø`ùÑP 8XLÆT,aLq€ÿÿÿþ¥Yÿÿu­>yñ²ïr‡•vá†Ïù¸JK×u|â•1ÚEf®´0’ rl즽þÕ¥éö6\on-dfY”š·®ßi ÕìÑ*¢'m9Å!D##à98ùÿûRÄèƒ e³ �-ÉA¶¡ &øÿÿÿ¯ÿÿÿÞü�"1µ“Y˜2 ÊiR+E½‹'Ç  NàÍOJä(aØ™dÚ%‡y©µþû3;%fr®g,«ŸXP˜¹üKÔ1¬´¼Õ�îS&!§“I…ó—–—ª°Ðÿÿÿüçÿÿÿb]ˆÍaI¤ÝÑÂàšW„=Ë»¨K=\ˆi“ÅñlÁIus?W;ŸñÉeûåß8g—UYñCcÂIêË®)M–VX`‰L3b3EØ„$TVÿûRÄìƒLeµ@�žÁw¶ ¦¨Œ<Â/ÿÿÿÿÿÿþwËMr:jdZ‘—uƒÊ@œÍåW‚ÉÉWŠ�ÉG’=A ‚Á.�yXžÎ<²,·ÎçîWQ`®f[:º+gdr´�’—2vÕ02+#`˜PH"(ø•ÐÿîM©4D6±Ï‹2•ÕJùݲn¬0^ŒgZ"‘ClV�¤±ÔªÒîEy~Ÿóï±¾²ü ‰ú…Èa5TŠ…W¦djj¨a#ÉÉTDL@Ðl”\Ò¶Ä€ÿÿÿëðÿÿûRÄêKq³@�= ‚¶ ³Ùó‘v¾Y™©¶q‰'þj»%#»+Ñž„l2ƒŘ$hœ^´ Ñ‘PIÄå/é^S4à?Ì›Ë3ѱ1WO\+uîŒý”† —¤:�!H¸€N /Š„sµ?@ù>ÿÿÿÿÿÿŸ;Ô)*_�ª¹jdJŒå$Ç™Ya´ LŒê ʃˆ „Ï8Ù«c¾ï¹ç}» Q©ûÝðm™¡Q†çXËïTQÙØ7(ÏB¢£Ääm�2• ÿùKÿÿÿûRÄéƒ ™±@�= q6 H¦ùúÿÿÿçlA¯û÷l|õ¿Têmš(þ™ýˆê-r ðm±Ôe¶ïȧ9Y™å¦â›þþcwßo¬÷OÏ̆awV­“¨)“dK‹ž°àðÆå“&Θxÿÿÿù”޲ÿÿëáÚ¾Ë �œ�ú]¹²ñ¾ê­\)„›�q„]»LBåÂU—RÐó†eNÞ~þ~W™Ïßž¾R»±;'––ZÆ×À\µx©,�·ÙKÂßM·ŽÿÿûRÄë }µ@ ;A”6à³Øÿÿþ¦/—ÿÿǘ�9sIBé¡ EËu;#XŠÊV¢�‚…¹Î—D8�TuGtF[Š‘.Ôïò+»0–õÍêl²ÑÇQêAŽj$¦?~ê•(@MNV'ž -Œ–©6pÿÿÿïúúÿÿ‘œ™P\Т/?ôéB%¯ZÖ*Jt¢a.fæýÁšÖÔ’p‰µ-sÿ.ßÿý9¿ô¿î?K=�¶ÓK^gϬÁ•Ö3‹ :--€Üý:ö„› Û`@ÿûRÄìƒ %µ` 7Á’6 3ØÑ Ë×ÿúµ6Úò²ä4�"ª(‡)�芢êCÕ°¹$3ÝXî-,t9XÆ»4çeSUÿú©Õf¨š?Y“jM¸ñ ðß%\ȸm ‰`dºND ˆÈVÅꀽWÿÿõÝï5’©î›k3·SH ~œëÍX);“ZÔŸQ‘ˆ{ù­- JIxeÞçù·Wýüùó+Ö{¿°òõLäo&�³I1ŠŸÔÄI¢ÈìD`5ÃÀh6 �•A1@�•²ÿûRÄëƒK™µÀ��…6 H³ØÊ$D�ëª~Çÿÿ‹<÷cb4Ås\\ÏB·ÐérZå^ï™n†åMÄÚS¼™Rg̺ìÏÎßzÿü÷×z¬uW¾ØÂ¥µJB‰VsŠÁjá`j¥ ¡‰ÈFŠœ½.ábD °òà0»/ÿõ)�_ Í ¼hÞecöÔ»éäcE3³ÔÑdÙïhÃ(·h÷ÚÎòƒî>¯ÿù‰^?ÿÿ¿ûþ»ˆíüuEŒe�Æ ©ÔQ …””Â:   ÐáÿûRÄêƒ yµÀ�žÁj6`Œ&ùÿÿþ_š@;v¿ÿ©­D üC0ðu"�,g¼C„¦ #6†þœ|¯“Å5„ùnÍÒ7�ˆ�¹ÏΟÞgržnßù¼´4ö7õÛ]å¬+Þ‚æaCÔÈO]:HOˆX×0>heÕ,�­úìÝÕ(½Tšn‰5ªâ4uƒ½é–ýŸ¾Z<�˜öÕë³ûã°gZ£¤ãñsŸ¹.îMózffvŸó�ütïbí³[Õ6TzäjY:ÿ Dâ*qÕ8†ÿûRÄí =µ@ 5Ak6a(¢at$;^‚Z,–HÚº­ �ÿÿÿ÷H(©¸Dzœ†3EЮe§3¦;&QÂä9ou%Ån C”‚d=+_ÿÿþÝèT»X™%8á< bHÃG‹ ‚01C‚ Qÿÿþ�53{ÿú¢°ÚsÉ–¥~ß|…™AÑ4Í�˱Sá:Ì#rm%di?2³Èïô½´ü¿çc_ût×™¶Ne [|óLL,�%é8&Y7™lõ:1¹£±ìÿûRÄì‚ ±µ @A}¶ ¨³ ‚?ÿÿþͨVÝÁ¿ÿøŸln4 �‘ò8õTÅû,EY¯ «ÉN57C“5TlÉ‚n{ Ó€¬¥=guÿŸéÈêYò¼eP–•‚~ÙU (i–q &®pH@)H„�©ŠpBÿÿÿý×%—7ÿµü)ýM>©-;c®k9r/©Ä…ä‡ áb]C‚†AˆÉëŠ$0äLYpÛõÿÿœ§oª½dV’{8ªtú‘Q 1#moHt´YerRDL(ÿûRÄì ‘±À “�=¶¡Œ–  ÅÓ˜]ÿ° 4zb£ÈfËþ|¤0 ¥  ˆ‚ªC•¤>ÁH›IV¾{¦×°å2l“)M1 R3ÿÿÿT·e£±ŽèŠŠ ÊU,1ÑŽ–$Á� Õ`Ò µ¬Õ\u"˜ÿô¿™æ¡…?«m8ëT),ùK_û¾^UQó3õ­H†©ò”>‰ò2%~#¯�øùþ~:ŽÛt(s8×¢¤¨†« ñ2F �ݱ`ôÐwk�¹ÆÉ(ˆ€ÿûRÄìKõ³@��w6`Œ§iÿÿþi3�m EMÿÿ¼È_nLDWcIÅ3“Ú ¨G!)\ÊyûE:ŽÇpÖÃ&CmMZÙ7‡¤ÿ–þ|º™ÿ¨ Èì&ÚÙžL™‰*(¡"bLÕ$"�]!*©•Qÿÿÿ S¬eÿùFg/’³4&g§õÑ Ì蔿J1¬ TÃ1ëK;„nå\Äšc(0£N´,òÛsüçsŸ)%�“‰ S*DsŸü‡óüóu�ûb¤ÅF䉜¤àüÆ\Â(ćVZa”BŠ ,`v�²JŠ• ´@�Ò·ÿîÙgs{ÿù•©<Æ&Nr=îyÎÆ¾¼vì8¿™æ’ö«XÛ;G们ªçÿÓ·íëÊ®£QJìŠÊ ÎìcÄ1ÅPˆ&4ÿûRÄïƒ }±@ ‰}¶ Œ§i85a«d?ÿÿòm?À2ÓZŸýÊfyÝÃá•QŸÏ)%[+lg®V£#‘¡^¬à��*�ݺ©�×êìÞ÷ûÛ¿/!rÈT®}÷'.�¢U惒¦Òç¢mÀ›Q\V`}f€QÿÿþN×�Lù¿ÿºñ–¤^CžêÞÎwÓ `ÖVq%Kà yÝ¢C=Zó$Ô‹:Êt¢Òòú^\ÙçŪ*鋃 É,m' œ2F �¤š¤ÿûRÄë‚ u³@�>É‚¶ ¨§hL›À�R)\ÚúášÿÿýSÙÎÇ&‹7ÿMœ"ŒÞ‡–kŠ: ”a!Á%-ÐÿûRÄé‚ I¯ ¡ ;IX6a´�è› ÿÿÿ±ÌÅp†@£¡,Ìßÿœ%èw*LS³3ÁËìÝ209TÄžs)ʦEtº¹T΋S©èVf{nÏFûÿÿÿµ:ŽÞBÛ¶'¨bZÔ(–HË €™í“Ì”¨ ‹j¾u[kiþî—ÿŽŒ£e aö¿ùezà’<Zõ2UÎE3-P¢p¢²;™�Ó1•Tò¡*­IÊÃv:5ÕÕ¦–WbÿÿÿÿKF½mK^áÆØ#.•ÿÿýÿûRÄëJñ±¡ UÑ?µâtŠ»�<Èæ(²äb+‘=í5˜‰—Ù¡jÿý�jB5Œ�t{·ˆ�J¼b"ìðÒÅ $/7“Û­Ê_ÿ‘fÜëæìË��‰•›{¾{9ï|Ú8>0 ë `…eKkI?‹²žrØÃ³çmŒ«Üó±)’Ò2þÎÔÆ<¥ØÏ•s9‰º!YÔyÌbM™† **:Ì×mÑU[ÿÿÿÿÝ™¨ö»:µdaö•�C (¹Š9»î ?ÿÕÿûRÄõNµà™�ƒ¶ ô!&ø£':¸—8µc…3¶ôéïsAЫõª'ßû¯4÷{2ÓKcÕ>È…X™‹eÄ43B3Ýn…ùŸ—åÿoJ§¹Sœ™Œc$‰4šFÌWU®¡"M3¥Ãž*j(Cp ¢rÝ« ÿÿØd<ͱ¦ŒD8L».ÿ Y“€¬=�{¹?]T.sž]…u¦m©9Ú�ÊÝ *»æ°›ß_ü¿ïçñõ^_Ýõ:­Vá[4®a÷’» Ð/*B„Ô ÿûRÄê m§  ­Ù”¶ ´!³¡£ËcD�œ§Çó�‘”¡Ð@ß*´¿â²ŸKÿ4#õp”[¡kUI„G$7)¡gÖÚ$ÍlÖˡγ?ÿÿûw§g»3vA„©Âܪ@3¡�îF$Êrï³@ÿÿÙ²ODd9ƒJ7"5Ïü¥þטWBMsé[Ae[íCPÐ� )ÓËË´ÏrSR6*O3z›1ùÄËŽ^ÇYÿÿó¿;Ÿg<„÷!MÕ]Ïfžá¦QCêi$zR²Ó`ÿûRÄë‚ é³  ±Ñ“6 ¨!§ÙJá€6µ�ÿÿÿ½Њ1�~„¦ÿù&GIÐäæZ Î+×·ÒzZ®U$·s…)iw*•·78YäQÖ‘U«ñ!žóÿþþrGÜsn[Ò„çßä‚^eÚiœÌU‚¯É�Ð.K*߬Eÿúô*å“3Yħÿì’"§íöš)œ³ÈŒó¶  ªAj¥hÜP £ ê�*9`¢ jÿŸŸçÿò¿ý·{³ç­2eÎ@ÎÇNh¢ÿûRÄë‚ ± �>ÉN6aèŠz´†Õ³‚‰‘$ ·mcŒttäÕ3ÞÞ^ó?¿þw§G/>}Š«ŸÃ6õÚWMH(€ˆçB1#ª‹F‰Æ#ÖÎŽ£¢À6ÿû?L‚V@˜‚ïóH€ä¾nˆR…•2»d‹·g�š÷‹[z¾àšÝˆ=Æ)ú,Ľ>el×î�‹h›ê©š¯Ÿùë¾úÿþ8žõi¿AšI̳¹Æ F<É$ñ �p†â„(¿r4IÿþÿûRÄï -¯¡ 7Ƀ¶`ô!§h( L ”�ã·t?ÓþûèºV¶áÈs5B¶U)8�&°õH?pÄ  ÚÛ«Â uÒ/5amë>åùÿÿÿÿþß;3¶únôY#šKC²þ-R�z¥ºÌÀ±i½¾HÑ$ e¹îÖ8fBÞ-vtïÿyÑfœ…Dµ³… óë=B“ÐszI›ba’ª\‰T’“]–_??ïÿÿÿ·÷;™{~uÚ²cÓIUP%€ŒC+‡0ç8W-Œ€ÿÿÊ-ÿûRÄç‚ ]± ¡ Ý ¡ã´�Ò{™ Ó¤rìF‡,ÈÒÏ'=A¼C—'émåP™ ª›ÊÃ[T¶³Û�‡&”�cÛòn•5-~Égù_ÿ‡3úiZ¼­÷ŒbŠàÖ4ÉÅ g¬tÉH,Œ2†¦!ipM4 ‘ 4ÌŒÀ×—ÿäÖË™ÉHÈÕ–¡‘“Y�ZËPÉ•”'#Y&²Ë!”¹¬œ²öJGü¿ÿö‘¬¿#“,²Ô5k,ŽF³Ï²æ_ù�Ë–( NŽF¡�¬˜‚šŠf\ÿûRÄñ Y³  Á‡¶!hšúrnªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªLAME3.97ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄì‚ õ± @oÙ�¶`h¦øªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄìƒË]°Ú €t4€ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªbeetbox-beets-00724b7/test/rsrc/image.ogg0000664000175000017500000002307215253035401017567 0ustar pieterpieterOggSþ–ç=݃[vorbisD¬€»€»€»¸OggSþ–ç=”ô€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ2vorbisXiph.Org libVorbis I 20050304+METADATA_BLOCK_PICTURE=AAAAAwAAAAlpbWFnZS9wbmcAAAALYWxidW0gY292ZXIAAAACAAAAAwAAACAAAAAAAAAAm4lQTkcNChoKAAAADUlIRFIAAAACAAAAAwgCAAAANohJ1gAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94CCg4MEEoBFpkAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAFUlEQVQI12P8//8/AwMDEwMDA4ICADkbAwPRhX8nAAAAAElFTkSuQmCC£METADATA_BLOCK_PICTURE=AAAACAAAAAppbWFnZS9qcGVnAAAACnRoZSBhcnRpc3QAAAACAAAAAwAAACAAAAAAAAACdP/Y/+AAEEpGSUYAAQEBAEgASAAA/9sAQwD//////////////////////////////////////////////////////////////////////////////////////9sAQwH//////////////////////////////////////////////////////////////////////////////////////8AAEQgAAwACAwERAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8AkoA//9k=vorbisBCVcT)F™RÒJ‰s”1F™b’J‰¥„BH�sS©9לk¬¹µ „SP)™RŽRic�)™RKI%t:'�c[IÁÖ˜k‹A¶„ šRL)Ä”RŠBSŒ)Å”RJB%t:æSŽJ(A¸œs«µ––c‹©t’Jç$dLBH)…’J¥SNBH5–ÖR)sRRjAè „B¶ „ ‚Ð�UÀ@² PСЄ†¬2 (Žâ(Ž#9’cI² ÀpI‘ɱ$KÒ,KÓDQU}Õ6UUöu]×u]×u 4d@H§™¥  d Y F(ÂBCVb(9ˆ&´æ|sŽƒf9h*Åætp"ÕæIn*ææœsÎ9'›sÆ8çœsŠrf1h&´æœsƒf)h&´æœsžÄæAkª´æœsÆ9§ƒqFçœsš´æAj6Öæœs´¦9j.Åæœs"åæIm.ÕæœsÎ9çœsÎ9çœsª§spN8çœs¢öæZnBçœs>§{sB8çœsÎ9çœsÎ9çœs‚Ð�UA6†q§ HŸ£�EˆiȤÝ£Ã$h r ©G££‘Rê ”TÆI)� 4d!„RH!…RH!…Rˆ!†bÈ)§œ‚ *©¤¢Š2Ê,³Ì2Ë,³Ì2ë°³Î:ì0ÄC ­´KMµÕXc­¹çœkÒZi­µÖJ)¥”RJ) Y€d�AF!…Rˆ!¦œrÊ)¨ BCV€<ÉsDGtDGtDGtDGtDÇsUõ}Sv…áteß×…ßYn]8–Ñu}a•máXeY9~áX–Ý÷•et]_XmÙVY†_ø�åö}ãxu]nÝç̺ï Çï¤ûÊÓÕmc™}ÝYf_wŽá:¿ð㩪¯›®+ §, ¿íëÆ³û¾²Œ®ëûª, ¿*Û±ë¾óü¾°,£ìúÂj˰ڶ1ܾn,¿pËkëÊ1ë¾Q¶u|_x Ãótu]yf]ÇöutãG8~Ê€€Ê@¡!+€8�$‰¢dY¢(Y–(Š¦èº¢hº®¤i¦©ižiZšgš¦iª²)š®,išiZžfšš§™¦hš®kš¦¬Š¦)˦jʲiš²ìº²m»®lÛ¢iʲiš²lš¦,»²«Û®ì꺤Y¦©yžijžgš¦jʲiš®«yžjzžhªž(ªªjªª­ªª,[žgššè©¦'Šªjª¦­šª*˦ªÚ²iª¶lªªm»ªìú²mëºiª²mª¦-›ªjÛ®ìê²,Ûº/išijžgššç™¦iš²lšª+[ž§šž(ªªæ‰¦jªª,›¦ªÊ–癪'Šªê‰žkšª*˦jÚªiš¶lªª-›¦*Ë®mû¾ëʲnªªl›ªjë¦jʲl˾ïʪ)˦ªÚ²iª²-Û²ï˲¬û¢iʲiª²mªª.˲m³lûºhš²mª¦-›ª*Û²-ûº,ÛºïÊ®o«ª¬ë²-ûºîú®pëº0¼²lûª¬úº+Ûºoë2Ûö}DÓ”eS5mÛTUYveÙöeÛö}Ñ4m[UU[6MÕ¶eYö}Y¶ma4MÙ6UUÖMÕ´mY–ma¶eáveÙ·e[öuוu_×}ã×eÝæº²í˲­ûª«ú¶îûÂpë®ð p0¡ ²ˆŒaŒ1�RÎ9¡QÊ9ç dÎA!•Ì9!”’9¡””2ç ”’R¡””Z !””Rk8Ø )±8@¡!+€TƒãX–癢jÚ²cIž'Šª©ª¶íH–牢iªªm[ž'Ц©ª®ëëšç‰¢iªªëêºhš¦©ª®ëºº.š¢©ªªëº²®›¦ªª®+»²ì릪ªªëÊ®,ûªº®+˲më°ª®ëʲlÛ¶oܺ®ë¾ïû‘­ëº.üÂ1 Gà @6¬ŽpR4XhÈJ €0!ƒB!„�RJ!¥”0à`B(4dE'C)¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RH)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ©¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)•RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”R �Šp�z0¡ ²HŒQJ)Æœƒ1æcÐI()bÌ9Æ”’Rå„Ri-·Ê9!¤ÔRm™sRZ‹1æ3礤[Í9‡RR‹±æškVk®5çZZ«5לs͹´k®9לsË1לsÎ9çsÎ9çœsÎà48€ذ:ÂIÑX`¡!+€T¥sÎ9èRŒ9ç„"…sÎ9!TŒ9çtB¨sÌ9!„�9ç„B!s:è „B„B¡”ÎA!„J(!„B!„:!„B!„B!„RJ!„B ¡”P`�@€ «#œ�²€– R΄AŽA� AÊQ3 BL9Ñ™bNj3S�9�tjAÙ^2 € À (øBˆ1AˆÌ …U°À  æÀD„D�˜ H»¸€.\ÐÅ]BB‚X@ 88á†'Þð„œ STê àà ""š«°¸ÀÈÐØàèðø8>€ˆˆæ*,.02468:<€€€@€€OggS@–þ–ç=ý‚å'02310276;:?CCBl…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹¬Ø%ô B8FkF#ëœzÊýýžåJI`Ÿ76BU5À: š†îK.Þ[/IÀ´˜˜€Ž€ ~ÊýýžåJ¼çÛJÙ@!TÕ€ €z wPˆ{@Û‚š_,ß5ðè@ 4>ªýÿüå žík¥°@!TUè40ÑMtô™àÉÆ+ÚÙÁ…WÇуàÐ>ªýÿüšäâvy¨…PU¡ô…|G×�OӱЂ††�ÊpBÀ&€>ªýÿüšäîô4ª…PU'Ð@$¸O}�Ç%åMÒ;†:€ žä>ªýÿüšäÒ´ð&”ªÊ* @t𨴯ùçaï¥)t (4 ƒ˜šýÿOre1éM0BU 1>ÞY(¥ÚsYÀ&-RJgè¡ÕMkòØÀ‚VšýÿOr¥2ØåIØUUÅ@EO5š‚nE~IôÆÓ´JÊqØ)d¢U)°$ @šýÿOr¥28åMèªÊj ÌY�¬"æeç…d×Ôdþ‘òcw¢ ±“¦‘€d :šýÿOr¥`°Û›¸TU:Ì]¹¤¿\Ïô³\ÏÒ{QFH4¬T05Þyýök”‹2¸ÛÛXaE…P + &EÒæ^ ô#©”¶&Ú!ir}Ï””Ωaku¨“)lY �‚&˜ HÞyýök”‹2˜íMP*jT¦Þ1{Ã�1^_Y•¢~vçt×ZŸ}¹.ó­¡£ª9“5\1á)èàÁ_#ÞyýÿþåR Ny“B1ê,˜r(¶Øò³4ptmp sR›¦£L/g9‚èÞ?®Í0—M)°”,ZýÎu¹ƒ‘Þ8 4´X‰ h©u À÷ßÒ‹ö~>S£Èü†ý$=cr¦Èß7²ü¼öŽ¥ÏÃŒóù0ƒÊ«®b¥*¯ß·þQ�ÿŠá¨Y4®#öO¤Å± Š«=¡ P{údX]ÎÔýÎ59 £¼ „f)6ðÖ”³A`fœ“€½^�Ä!ƒ<©¬˜i0/d¥·?/Ôh³=é«m¤ò¶Þ­™ž��wÛÕZ:Ý–ÿ‰�^®¦×Ö‘&uVwû’CÅ_Åjð-˜mŒýÎu9 %½ Ð"++IÀ@âÊAGÕ�rý5]óo”X€¯/sãÎ�\ú çHÇ‘ÙqoÅóÈÐ3ú.+¼ð¬qÖ\E�¬SF’¿1R-à"ç ÜI¦ÏlÂjÂɘÌìæˆýÎwÙ4-= Ĥ¼ÌdÀ¢ÐIà,1æ8‘qü]âj­_è÷⥧Թéô''ïsçõu|‰ìwûæ¹ÅÇë�³Îå‹�/ó¡<:�0ÑÛå$¡Í½'—3Œˆí®�ý ýÎu9q­< B¡¡ËÂÉg�Pà€~57kg§P¿d´]�ÙÛü¹œÎo¿’_Ú¹Js)êã5÷Òä¤Åp–ô•õÚc\^;Ç¥QåtFôbˆ[D®áì §­“ýÎ5¹ƒVÞh’ʦ¡°@vv¿´ÄN˜¾d ¦²²Ki*¯u67[˜`&· 'nV‡§¯‹“ËÈcºt“Ÿq’C>-VþFŸÄ¼VÙ ]êïtGNÊy49ªéaœÙMãýÎ5¹ƒä�¡Xd‰‘\%`8�'\àÁÁû5ô�7‰M?/'x‘,ׯ×}Y¿Ž½nmcfFU)¸¸ð“‡0ÙëÞ¾ÕÑøÚ��·•êP[©+T²ûë¼ý2š\ÍüÓSœ ÂG.W¹èX©;·åUFÀhkôo†FØ/÷àÂu cÊ:ýÎ7Ùƒ–Þ8€˜š• ›0Ød7•\´×vÎ}ií½E«MÝ M3‹Š"äðºÏ~µ½b³¶#Ah©'òR‚ÑÖ&y,]~�MG“-9¶#8…þùäë¼�#s/yýÎ7Ù8ƒQ¾1ˆ•Ö%ˆ8€iup;š¤_I5…ÀÖÿ?»ØÄ&òÒµädu¡n±{½ï…é!‰Ÿ»:•¬Ï…úzÅU.25žBÉ–+Êèq0ïîQ®*/CUë&^ܱé-ýÎ59q#} „&å68ZÀ€ôлt3ü´WÜ™ohm™äP»-¨Y?Ç{ž°êŽLXø8&MöØ f%ªO©›÷NÉ”‰Íͯ®b¢ì½›ìÎÈPw¡ëWI;–ýÎwÙ(ƒ–ž„*hRdÁPL�Kºá?7œ�I—»B��Á¦Ñ|_O&±arúäºvQà$¹k×°d­Áå²l­Lc/["°R#lcú,èVÀÝ�Š…«äàHïbz¬Û{8˜TýÎ7Ù8ƒQÞ1ˆÉJQ3=HÐi—� ‚©æÊì•ä¸óM6¿ÝRmöµ|fê «ö’ôÑZ*Ìü(NbÎÑÙ&ç²ýÎu¹ƒ–ž@-jIÁ…&&èh‹o\ˆœ‰[¢ÆüJx2ÝÏÚ ^Cí7^:«YGcF¦òO}žÝºž‡ƒž�™‰°±<É~¾¬2Pâü"SÔÞ‰íõªÀö™!Gæ&ÛóS’‰�ÎI…¨ýÎu¹8ƒQÞ(BÌR¬H¦Ð‡YB,ƒ’²-oÅx3CT§XÈèòßÑ| éÈÓùÆûѳ^^ª„^‰)5=‚%G½pïb€{fy](€>(Ö÷:;ubjÙ:kGG:OggSD¬þ–ç=‡¿²¬‹‹‹‹‹‹ýÎ59 %½ ‚”. :>�þè]µ¤?÷TãÌxL€çsÔ˜žM›PÏXšÁ„—+q!^#§ÃaâèÑ|S«ã.�„™ãµ•«Q®%(Îsnå¶©lõ]”N-{~ýÎwÙ8ƒ™ž0B“b…qÄñ–X9vñ)l}¬Å¼�b‘Id=!û…t,W¢7Åæÿ9±¸õñ­Ûÿâ® Rñˆçƒfƒ©ÄÀoé<ïËÓ—·§¾UÚe±”׫üpõ0Úé[(wÉÎ"…ýÎu¹8ƒ–Þ„2h–¢"hrðÈ)=|éP›Û"ýr:Iò"q�ö°Ì˜è¹¨š¯à޾Rß"à€"«•uÞ½‰ þ¹Ú‡¿š.øAsñ©Ïˆnµïn7…£'òèeŽ~ ýÎu¹ƒÞ0B Í c@2 °8èä>h»ï_6ƒzyu—YÆü|$Ô•»¹Žëö¬ÊÀÅ…÷ñSìÙ n'E²0!¸¶²ö>~v3üayè™zŸ›9óMÔk ¦1×5„éW7ñ#ÞežÈiýÎwÙ8ƒ‘ž1h–bÞFh‚¦zmœòp4<¯å²é*é´ ´ÚäœÉ"N¨„ªñ|oâSðjl’ÌôøœxŽMqIß–Š'S´Î—WøKw®²:&U0TÌn;�‘bbž ÆPÈeýί² 8P‹<Üà0P8�Ó¹­j xz}]�Übeetbox-beets-00724b7/test/rsrc/beetsplug/0000775000175000017500000000000015253035401017775 5ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/beetsplug/test.py0000664000175000017500000000075215253035401021332 0ustar pieterpieterfrom beets import ui from beets.plugins import BeetsPlugin class TestPlugin(BeetsPlugin): def __init__(self): super().__init__() self.is_test_plugin = True def commands(self): test = ui.Subcommand("test") test.func = lambda *args: None # Used in CompletionTest test.parser.add_option("-o", "--option", dest="my_opt") plugin = ui.Subcommand("plugin") plugin.func = lambda *args: None return [test, plugin] beetbox-beets-00724b7/test/rsrc/image.mp30000664000175000017500000002432415253035401017513 0ustar pieterpieterID3SAPIC3image/pngalbum cover‰PNG  IHDR6ˆIÖ pHYs  šœtIMEÞ  J™tEXtCommentCreated with GIMPW�IDAT×cüÿÿ?‚9Ñ…'IEND®B`‚APIC image/jpegthe artistÿØÿàJFIFHHÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÄ ÿĵ}!1AQa"q2�‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2�B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?’€?ÿÙÿûPÄInfo(!w  &&,,,33999@@FFFLLSSSYY```fflllssyyy€€†††ŒŒ“““™™   ¦¦¬¬¬³³¹¹¹ÀÀÆÆÆÌÌÓÓÓÙÙàààææìììóóùùùÿÿ9LAME3.97 ¥-þ@$|B@!w_»õ^ÿûPÄ1ªü@TØ5"L‹‰€TÇÿÿÿÿÿBhNs‡y�„}@3žÇ;çBú2¿úŸï!?úþ}C¡„'B�‰¨ÀbÊ€,=°² 7›âýcE`M.¦2 :ºJw� f}w§[?ÿÿÿÿ®�‘Ò�W:®ª…F Œø·BÒ5¥Ê纡Ö^³­*+R:kB·ß¿Û®Ÿÿßÿå™ü¾[�&8—Ub0'QX`€h¡eÿÿŸÿÙ2yÕYäÿûRÄ!ƒ)± @} 86`€³¡µ�àv"6‡¬ƒF” ³äÄÓ”š£ŸÃ=ØŠÿÃÿíçÞvó?Va˜VÓ¯S˜ä¤ËŒIùóläe÷M[#@~¸¨H'ŠÝz£U0¤fÿÿÿúZc{²™Î¤d îî‰tÖÇiƒ1ާ+Ó>b—Wn¯›¾·ÿÿÿüÿújÝkv}I*shìCÚ #9§™„Ä! ×u»kÑ{µjk¦¨™É+Q@·ãÚ·]šÙ+¶ŽºmÿöéFÿ¿nïâçÃWõÈó¯ÿûRÄ;ƒ­µ @×À÷¶aˆ N#œ4ìœHšW®JU?¦^gÍç=¿¥v„y*g^M)\ŒèÑZ¿½W$4>ÚdLN[Íûåú>¥S3õê*Ööß G_ÊxV#³B)ë´eT¶H Œ–šN@Ñk%©§GI,™eU]¦zQ.û«,¶-¯¬ª£"Ùõó·ÿõ¤~ù}ßJWò�}ÞÖT˜E¤>é ÈMŠB#–�¤D™?Èÿï–\dáO=!›Ÿbtph½'r†PŒ·¨ˆX.vlÈKÿûRÄWƒ ­µ =¶!'¡½…Ö.™|Ÿÿ÷ºùãnµXNkíÝbß aWIvȇ¢'HT'@if³³"rÙ•µz:ö²í£<êàŠZZVˆl¥VC¦žÌ´dO¯÷G+>F{)M¨¦³k-«¡‘§!M.hñqõ•Ò'ÆfŒz0@úÿÿúï�ºYïmV¶ígÔÖwµT†‘ x…!G!'GtÕ ÌgùÖ�2éK.ªüÖµ«mÞ“ºŠkœR1U¦cë’ë&ÈÊ ÄhÓF…ÿûRÄnƒ‰Y± = ¶ Ä'¡’�#¤´UdVißr˜Œ —N^’1·|ÓÜQêåZ=ÞÎëO7Z¶ÆÒ�}ùã�û³«×ÆwáñC¼[fB¢¯> ’†R*ˆŠ(£ ?ÎŒŽÿk;L¨�f*nS¡SyÌsfiÝT…*2ÙŠ&®ã;+È•ïÿ¦�µ ¿î‚YSõcY4FÚ™s­Î(M 4�q°È¬4EXuà�(ÐfJ8 vhã dznE"p z³3¬Ó¢zÿþr|í…ÿûRÄ„ Áµ@ 7Á#¶`È' ÷oò°×«¬Übß—w.Lû7eŠ’@K”¥)um.W§[MF¢‹vR6"î‘mÚvbÖf±QY˜ªGuJd³ý¾º~ü2[q޵öŸ�šŠÜfÊBýI�Œ“Ù+q Ñ áY¤û¾èàl;4·pÌ2!˜�äê£fŒKËCŽ˜…I¤«»Y%>®#Þ¾Ûøþ?Þ¯‰�y—³,¸b¡AY‡ž �,‘+�…” %*Œ?ÿÿÿËÿÿÿÿéíçX‘©ÿûRÄ–ƒ ³ =ý¶aH› Ò+Œ§º…-zÎv»c±¸F”ø1Þ�V”Ôß?Bøü'‘ßÈ‹ûßþoë$–R[ Ådt�¯# 4± KY$íq:4s²#M’ÀÊÀÕ= „gìdLt2•f;^«é�cµ]Lô[;£ÕS–ÕßÿúßD÷¾½ú~"‚i]1N^ w/jɃO)ª MFW+MÈ�6_+i¼oÌŠ¬ó%Èìéô™Á® )Ë $'¬ž\W'5³’ŸŸ6?'ÿþpüÏ&Ý™ÞãqÿûR݃ɯ =9¶ È£Xô¡Ùì”<ö =}aÔw¥“ꫜL»©ä¤NýÝgf¡V X‚�Š÷uQNkØJ$&¨gÈ©s©ÐªèÈ„\ôôµ?M?Ýÿ’ÛXßéCe+0Ylö¦Ñi4�,b`ø=@DˆWÿÿÿ-oU¦—ƒIT;f�Ê·j‘ ÇÕ’:ìtÑ… ¹ès5KÝ[$Ú?Ó#D ˆ§�øþ?þxç“ëˆÌ�ô¬-5ñ d_e°ÙSä9Ç$, ÿûRÄÄJͳ �= 6!'¡Øaþÿ?éö”`ÂI‰‚”]ÏKi»eóf;éi#R ¶/;:FSœ}LÄ×s ÓÔÏW¶ó£–=h¸c ¤4\jŒ" Eî A 8. `&¡ r ðäà‡å�¥?ôõÿñò‡¬¿-ŽB¼}åøåVAT÷QÞ>™Z­v_ÿWS›QW3µPÍÇ ›;ÙóÙN~U~íÿëåxJ§nÑ,¹!h,è–Ôš Òdj�-i² ¿DH\”ÿûRÄÕ ¡¯ �5ᡌ˜ËA€ J ŠÆ@ßÿÿÿEV"£¸ÌkÌeR‘÷w)ЬÇtz¯.æE!êK©nèÆvz¹W[ºûþúµu—ö¶ëÆ7”…N�J(ô˜"5±›Öó@ÁaL=#ŽÅ @ÿü¿ü R‡ÿÿÿ䉕àt½wiÒ«UGQl�wE²‰ì¬#GðPà‘ƒ°ºâNÜ#›±Î_ùSÌžž‘œ¬?Wý¢�“c‚ÃNB¥%©ëÎn_XèƒaåÑ0²Áej±ÿûRÄèƒ 5µ`‡¶à!¸I¶ÇïÿÿÿÿiòÌ—31˜[šÏ-¾y?ï œ””󤊮nK6‘â–ªÔÕ{±†yÕN~;sùU/µ¾ö¼½Í¯Š¸»k¡œÐMl0>Pø`ùÑP 8XLÆT,aLq€ÿÿÿþ¥Yÿÿu­>yñ²ïr‡•vá†Ïù¸JK×u|â•1ÚEf®´0’ rl즽þÕ¥éö6\on-dfY”š·®ßi ÕìÑ*¢'m9Å!D##à98ùÿûRÄèƒ e³ �-ÉA¶¡ &øÿÿÿ¯ÿÿÿÞü�"1µ“Y˜2 ÊiR+E½‹'Ç  NàÍOJä(aØ™dÚ%‡y©µþû3;%fr®g,«ŸXP˜¹üKÔ1¬´¼Õ�îS&!§“I…ó—–—ª°Ðÿÿÿüçÿÿÿb]ˆÍaI¤ÝÑÂàšW„=Ë»¨K=\ˆi“ÅñlÁIus?W;ŸñÉeûåß8g—UYñCcÂIêË®)M–VX`‰L3b3EØ„$TVÿûRÄìƒLeµ@�žÁw¶ ¦¨Œ<Â/ÿÿÿÿÿÿþwËMr:jdZ‘—uƒÊ@œÍåW‚ÉÉWŠ�ÉG’=A ‚Á.�yXžÎ<²,·ÎçîWQ`®f[:º+gdr´�’—2vÕ02+#`˜PH"(ø•ÐÿîM©4D6±Ï‹2•ÕJùݲn¬0^ŒgZ"‘ClV�¤±ÔªÒîEy~Ÿóï±¾²ü ‰ú…Èa5TŠ…W¦djj¨a#ÉÉTDL@Ðl”\Ò¶Ä€ÿÿÿëðÿÿûRÄêKq³@�= ‚¶ ³Ùó‘v¾Y™©¶q‰'þj»%#»+Ñž„l2ƒŘ$hœ^´ Ñ‘PIÄå/é^S4à?Ì›Ë3ѱ1WO\+uîŒý”† —¤:�!H¸€N /Š„sµ?@ù>ÿÿÿÿÿÿŸ;Ô)*_�ª¹jdJŒå$Ç™Ya´ LŒê ʃˆ „Ï8Ù«c¾ï¹ç}» Q©ûÝðm™¡Q†çXËïTQÙØ7(ÏB¢£Ääm�2• ÿùKÿÿÿûRÄéƒ ™±@�= q6 H¦ùúÿÿÿçlA¯û÷l|õ¿Têmš(þ™ýˆê-r ðm±Ôe¶ïȧ9Y™å¦â›þþcwßo¬÷OÏ̆awV­“¨)“dK‹ž°àðÆå“&Θxÿÿÿù”޲ÿÿëáÚ¾Ë �œ�ú]¹²ñ¾ê­\)„›�q„]»LBåÂU—RÐó†eNÞ~þ~W™Ïßž¾R»±;'––ZÆ×À\µx©,�·ÙKÂßM·ŽÿÿûRÄë }µ@ ;A”6à³Øÿÿþ¦/—ÿÿǘ�9sIBé¡ EËu;#XŠÊV¢�‚…¹Î—D8�TuGtF[Š‘.Ôïò+»0–õÍêl²ÑÇQêAŽj$¦?~ê•(@MNV'ž -Œ–©6pÿÿÿïúúÿÿ‘œ™P\Т/?ôéB%¯ZÖ*Jt¢a.fæýÁšÖÔ’p‰µ-sÿ.ßÿý9¿ô¿î?K=�¶ÓK^gϬÁ•Ö3‹ :--€Üý:ö„› Û`@ÿûRÄìƒ %µ` 7Á’6 3ØÑ Ë×ÿúµ6Úò²ä4�"ª(‡)�芢êCÕ°¹$3ÝXî-,t9XÆ»4çeSUÿú©Õf¨š?Y“jM¸ñ ðß%\ȸm ‰`dºND ˆÈVÅꀽWÿÿõÝï5’©î›k3·SH ~œëÍX);“ZÔŸQ‘ˆ{ù­- JIxeÞçù·Wýüùó+Ö{¿°òõLäo&�³I1ŠŸÔÄI¢ÈìD`5ÃÀh6 �•A1@�•²ÿûRÄëƒK™µÀ��…6 H³ØÊ$D�ëª~Çÿÿ‹<÷cb4Ås\\ÏB·ÐérZå^ï™n†åMÄÚS¼™Rg̺ìÏÎßzÿü÷×z¬uW¾ØÂ¥µJB‰VsŠÁjá`j¥ ¡‰ÈFŠœ½.ábD °òà0»/ÿõ)�_ Í ¼hÞecöÔ»éäcE3³ÔÑdÙïhÃ(·h÷ÚÎòƒî>¯ÿù‰^?ÿÿ¿ûþ»ˆíüuEŒe�Æ ©ÔQ …””Â:   ÐáÿûRÄêƒ yµÀ�žÁj6`Œ&ùÿÿþ_š@;v¿ÿ©­D üC0ðu"�,g¼C„¦ #6†þœ|¯“Å5„ùnÍÒ7�ˆ�¹ÏΟÞgržnßù¼´4ö7õÛ]å¬+Þ‚æaCÔÈO]:HOˆX×0>heÕ,�­úìÝÕ(½Tšn‰5ªâ4uƒ½é–ýŸ¾Z<�˜öÕë³ûã°gZ£¤ãñsŸ¹.îMózffvŸó�ütïbí³[Õ6TzäjY:ÿ Dâ*qÕ8†ÿûRÄí =µ@ 5Ak6a(¢at$;^‚Z,–HÚº­ �ÿÿÿ÷H(©¸Dzœ†3EЮe§3¦;&QÂä9ou%Ån C”‚d=+_ÿÿþÝèT»X™%8á< bHÃG‹ ‚01C‚ Qÿÿþ�53{ÿú¢°ÚsÉ–¥~ß|…™AÑ4Í�˱Sá:Ì#rm%di?2³Èïô½´ü¿çc_ût×™¶Ne [|óLL,�%é8&Y7™lõ:1¹£±ìÿûRÄì‚ ±µ @A}¶ ¨³ ‚?ÿÿþͨVÝÁ¿ÿøŸln4 �‘ò8õTÅû,EY¯ «ÉN57C“5TlÉ‚n{ Ó€¬¥=guÿŸéÈêYò¼eP–•‚~ÙU (i–q &®pH@)H„�©ŠpBÿÿÿý×%—7ÿµü)ýM>©-;c®k9r/©Ä…ä‡ áb]C‚†AˆÉëŠ$0äLYpÛõÿÿœ§oª½dV’{8ªtú‘Q 1#moHt´YerRDL(ÿûRÄì ‘±À “�=¶¡Œ–  ÅÓ˜]ÿ° 4zb£ÈfËþ|¤0 ¥  ˆ‚ªC•¤>ÁH›IV¾{¦×°å2l“)M1 R3ÿÿÿT·e£±ŽèŠŠ ÊU,1ÑŽ–$Á� Õ`Ò µ¬Õ\u"˜ÿô¿™æ¡…?«m8ëT),ùK_û¾^UQó3õ­H†©ò”>‰ò2%~#¯�øùþ~:ŽÛt(s8×¢¤¨†« ñ2F �ݱ`ôÐwk�¹ÆÉ(ˆ€ÿûRÄìKõ³@��w6`Œ§iÿÿþi3�m EMÿÿ¼È_nLDWcIÅ3“Ú ¨G!)\ÊyûE:ŽÇpÖÃ&CmMZÙ7‡¤ÿ–þ|º™ÿ¨ Èì&ÚÙžL™‰*(¡"bLÕ$"�]!*©•Qÿÿÿ S¬eÿùFg/’³4&g§õÑ Ì蔿J1¬ TÃ1ëK;„nå\Äšc(0£N´,òÛsüçsŸ)%�“‰ S*DsŸü‡óüóu�ûb¤ÅF䉜¤àüÆ\Â(ćVZa”BŠ ,`v�²JŠ• ´@�Ò·ÿîÙgs{ÿù•©<Æ&Nr=îyÎÆ¾¼vì8¿™æ’ö«XÛ;G们ªçÿÓ·íëÊ®£QJìŠÊ ÎìcÄ1ÅPˆ&4ÿûRÄïƒ }±@ ‰}¶ Œ§i85a«d?ÿÿòm?À2ÓZŸýÊfyÝÃá•QŸÏ)%[+lg®V£#‘¡^¬à��*�ݺ©�×êìÞ÷ûÛ¿/!rÈT®}÷'.�¢U惒¦Òç¢mÀ›Q\V`}f€QÿÿþN×�Lù¿ÿºñ–¤^CžêÞÎwÓ `ÖVq%Kà yÝ¢C=Zó$Ô‹:Êt¢Òòú^\ÙçŪ*鋃 É,m' œ2F �¤š¤ÿûRÄë‚ u³@�>É‚¶ ¨§hL›À�R)\ÚúášÿÿýSÙÎÇ&‹7ÿMœ"ŒÞ‡–kŠ: ”a!Á%-ÐÿûRÄé‚ I¯ ¡ ;IX6a´�è› ÿÿÿ±ÌÅp†@£¡,Ìßÿœ%èw*LS³3ÁËìÝ209TÄžs)ʦEtº¹T΋S©èVf{nÏFûÿÿÿµ:ŽÞBÛ¶'¨bZÔ(–HË €™í“Ì”¨ ‹j¾u[kiþî—ÿŽŒ£e aö¿ùezà’<Zõ2UÎE3-P¢p¢²;™�Ó1•Tò¡*­IÊÃv:5ÕÕ¦–WbÿÿÿÿKF½mK^áÆØ#.•ÿÿýÿûRÄëJñ±¡ UÑ?µâtŠ»�<Èæ(²äb+‘=í5˜‰—Ù¡jÿý�jB5Œ�t{·ˆ�J¼b"ìðÒÅ $/7“Û­Ê_ÿ‘fÜëæìË��‰•›{¾{9ï|Ú8>0 ë `…eKkI?‹²žrØÃ³çmŒ«Üó±)’Ò2þÎÔÆ<¥ØÏ•s9‰º!YÔyÌbM™† **:Ì×mÑU[ÿÿÿÿÝ™¨ö»:µdaö•�C (¹Š9»î ?ÿÕÿûRÄõNµà™�ƒ¶ ô!&ø£':¸—8µc…3¶ôéïsAЫõª'ßû¯4÷{2ÓKcÕ>È…X™‹eÄ43B3Ýn…ùŸ—åÿoJ§¹Sœ™Œc$‰4šFÌWU®¡"M3¥Ãž*j(Cp ¢rÝ« ÿÿØd<ͱ¦ŒD8L».ÿ Y“€¬=�{¹?]T.sž]…u¦m©9Ú�ÊÝ *»æ°›ß_ü¿ïçñõ^_Ýõ:­Vá[4®a÷’» Ð/*B„Ô ÿûRÄê m§  ­Ù”¶ ´!³¡£ËcD�œ§Çó�‘”¡Ð@ß*´¿â²ŸKÿ4#õp”[¡kUI„G$7)¡gÖÚ$ÍlÖˡγ?ÿÿûw§g»3vA„©Âܪ@3¡�îF$Êrï³@ÿÿÙ²ODd9ƒJ7"5Ïü¥þטWBMsé[Ae[íCPÐ� )ÓËË´ÏrSR6*O3z›1ùÄËŽ^ÇYÿÿó¿;Ÿg<„÷!MÕ]Ïfžá¦QCêi$zR²Ó`ÿûRÄë‚ é³  ±Ñ“6 ¨!§ÙJá€6µ�ÿÿÿ½Њ1�~„¦ÿù&GIÐäæZ Î+×·ÒzZ®U$·s…)iw*•·78YäQÖ‘U«ñ!žóÿþþrGÜsn[Ò„çßä‚^eÚiœÌU‚¯É�Ð.K*߬Eÿúô*å“3Yħÿì’"§íöš)œ³ÈŒó¶  ªAj¥hÜP £ ê�*9`¢ jÿŸŸçÿò¿ý·{³ç­2eÎ@ÎÇNh¢ÿûRÄë‚ ± �>ÉN6aèŠz´†Õ³‚‰‘$ ·mcŒttäÕ3ÞÞ^ó?¿þw§G/>}Š«ŸÃ6õÚWMH(€ˆçB1#ª‹F‰Æ#ÖÎŽ£¢À6ÿû?L‚V@˜‚ïóH€ä¾nˆR…•2»d‹·g�š÷‹[z¾àšÝˆ=Æ)ú,Ľ>el×î�‹h›ê©š¯Ÿùë¾úÿþ8žõi¿AšI̳¹Æ F<É$ñ �p†â„(¿r4IÿþÿûRÄï -¯¡ 7Ƀ¶`ô!§h( L ”�ã·t?ÓþûèºV¶áÈs5B¶U)8�&°õH?pÄ  ÚÛ«Â uÒ/5amë>åùÿÿÿÿþß;3¶únôY#šKC²þ-R�z¥ºÌÀ±i½¾HÑ$ e¹îÖ8fBÞ-vtïÿyÑfœ…Dµ³… óë=B“ÐszI›ba’ª\‰T’“]–_??ïÿÿÿ·÷;™{~uÚ²cÓIUP%€ŒC+‡0ç8W-Œ€ÿÿÊ-ÿûRÄç‚ ]± ¡ Ý ¡ã´�Ò{™ Ó¤rìF‡,ÈÒÏ'=A¼C—'émåP™ ª›ÊÃ[T¶³Û�‡&”�cÛòn•5-~Égù_ÿ‡3úiZ¼­÷ŒbŠàÖ4ÉÅ g¬tÉH,Œ2†¦!ipM4 ‘ 4ÌŒÀ×—ÿäÖË™ÉHÈÕ–¡‘“Y�ZËPÉ•”'#Y&²Ë!”¹¬œ²öJGü¿ÿö‘¬¿#“,²Ô5k,ŽF³Ï²æ_ù�Ë–( NŽF¡�¬˜‚šŠf\ÿûRÄñ Y³  Á‡¶!hšúrnªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªLAME3.97ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄì‚ õ± @oÙ�¶`h¦øªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄìƒË]°Ú €t4€ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªbeetbox-beets-00724b7/test/rsrc/full.mpc0000664000175000017500000000571415253035401017455 0ustar pieterpieterMP+' \@”7–sÌÿþ ÿÒÅDfÑçüÿÿÜ3Ï?óÏ<óÏ>÷Ì>÷üóÿüsÏüóÏ?EDDþñð>@Èñ_éÒá @ Ñ @;8ºo´è€€Þ ‘ÿE¾|‘_Dä¤È—DDDDù""_ˆˆ|¾ˆˆ""ED""""‘""ˆÈà‹ˆˆP 8ºÑh ½Ñ�¶mÛ¶Óµ]×KÛ¶m^UÕ6ª^õ÷jå/ú{¯ª‹U¯¶m»ò—mkšg{¦KÛ[Ú,H’³mÑ¥çç&ŸÛliÛ¶³smÙ"Ò”(�ªº­lu~傽ÿÝgUÝÓ·õ—U÷U±o Úó5„4ÆiŒß@N¥jT=�’¦SÒ©NÿÿÐÿÿÿÿùD&¼|�/]à½|_þÿ8yèÿÿAWÿÿÿÿ˜üúÿDÀÿüCx/þ‹Ÿàÿ]ÿÿÿÿ@bòÿçyŠÄáï1øëý�Á!ôóé€?A_OØ�ÿÿ?ÿÿÿÿ>Àÿÿºÿÿÿÿýv½ä`oôôyCÀ�Wì€Ážpø öú‚@ŸÀ§ÿÿAWÿÿÿÿЗüûù‚½À /觇~¿žÏè úùv>ßô¿ÿÿÿðÿÿÿ®pñÿÿÿƒùÿÿÿð2."âåß?€/¿‹�ÿÿÿÿøÿÿAW¸uÿÿÿÿüÿÿø EDäÿD@àwðÿÿ@ÿÿÿÿçÿÿ?è ÿÿÿÿtù“ÿ ò¿€ñ "ƒˆ|ùàEी|ÿºÂÿÿÿÿÈ—ãÿ ˆ€�ÿ䀈ˆ|¾ˆnÿÐÿÿÿÿâ?,ÿ" |ù ‘ÿ;€ÀÜÀ€mSº(›ÿ þÿ9öŸ�çìÓgõŒµõ¼ž³|ΟßKŸ÷ñ‹ÀDDÄ"m›vù´kÛ¶Û¦mÛ´ÛvmÛ¶mÛmÛ¦]¶kÛ6Ðà 8ÀxÀРhÐh Ð£oÀ¸Àápи£poÀ"Àá" """""‘/""ˆˆHˆ€ˆˆˆˆˆDDä‹PDD€7€íРð@ènt£ކÀèÝ�p´Ý@ÃÑ׸mÛ¶k¦mÛuÛ.]Û¶]»nÛ®kÛéÚ6mÿÛvÿ¿ÿÿÿ¿ÿßÿ¿ÿÿßÿÿªq*ùN%+ªcEU5�Jª ’ªÂX=W£ýÐsÞ!§Ðçr ýW8yÿÿÿAüÿÿÿ?ˆô^þ�þø]/àä{€@ÿÿÿÿþÿÿÿÿÿÿÿ´àÿè]Ìÿÿÿ?ÿÿÿÝ tŸ£ 8€�î: 8p4tt ÿÿÿÊÿÿÿ0ôíƒ?ß 0ô?Á¯øçû…? ° ×ë ]Ÿÿÿÿòÿÿÿ}Ã__¯ô…»¼ï×èú|‚½q0þü‚¾+àSÿÿÿ þÿÿÿaзK}>@PÈóñ|{<0°Çãú‚Á_PÇ…“€ÿÿtÿÿÿÿò»üÉùÀ‡ß/_ä‹‹€üΠÿÐÿÿÿÿùò'ÿDäË�/âÁ Èù "cÿt…ÿÿÿÿ‘Íÿ€|/_à äË�/ _D{�ÿtÿÿÿÿ€öÎÿwhÀ@Ã�ÐO¸ÿƒ®€ÿÿÿÿ /ùÿ@¿ /8Øûýx¼�//,ùz@ß_±ô*|=.ÐÅLÿÿÿƒðÿÿÿàÞs€8€àáð ÞÀp à AWPËÿÿÿÿ°üÿÿóÔg¡ÁƒÜwðÀ|þîÛ§Ï{íõÐ_>âûoŸ?úÁëGŽÿÿÐÿÿÿÿñß@>Hþù|ù_ÿï¿àÿÿÿàÿÿÿÀÌd¶mÿ`€ÿÿŸÓg“çú/øaäL’�–8›N­u@€•¡BÚô]…èH>pEƈYKƒ©Ì&—g‹‚ȘxÚ'øaà+¤ôšª½P§0¾Ïþ›l2nNÖE±d‘ÁªËLŠ5Ÿ”.ÒúšÂ‘Ç <´¢À “ É}`n´ñDc½býºA{•òï@ê9`FSô© ÄÖHgDJøù×£·£]燿–«<Ò& 6°?ç:ó1‚õ±MG¬“Я�øaäL�Éÿs¯!�jåN,¼ÉH_{H¨šs�±Š3.!0Æ\}7ü_j—ª·"h E¶pÇ-Êïc¬¢ÓYÇ�½fÌèÂý�\†Û3 Ú"êUk¡»»º%×̰æm}�¸¾Á†e×:4鑜}Ë„%V¨ŸdZ f Føaà+¥#)}È쾘×`°Ï<‘=ó�üYó ³–ª¥¥;µüÒ‘ŽŽm†øomÿ6ôs ]FÍŸdÄoSxç‚l¥.šÌ»¯«T¤…˜‚q�wäŽkß²O׊œ_¯X8±<u•/d7JÎ8/)”Ñå¾Ë¯'ð•mdøaà%f–å�ª£uÇûé€7”¥\uøåQ*n:„‰søŒ¤kÀ…‹»”�gh�À^—A{˜Ùî_ú%IãŠðbÈmÑ.Ô%?&Ùñ9išË†ž>_I�¦×­ŒãÁ/„§80\rs’U †`Fœ*²ÇµŠ#ì ߈“Uá‰uk¦bSøaà$ü õ|“wÓÈ6V2$ ¨ëgÂê»ÛKB5·’¬_˜h )ýõìòF³™WÊ¥Uš ]VE‰f¹5Ïå°£*6s\²·vâÛÜ ‹E“ È6úϽ�£qpâ †Ž'àï ‡Yøaä[JÀ�5úï Å(zŽŸ-/§©ì®)ãD•ᣙo\bŠ—2zÑ]7ÏÕg¥šC6�r¿¾'#"×VÑ fÞe‘åë×ÝuXbƒ>Ñß>. £ºŸÚ› Kq?ø° FæåHx8áÊTpáþ*ߟGý~Á¡²6‡`Í`y…øaà%zõ£A>‹¢Îâ$ÙІҨ¹Œn+¶½Å5<õz6¶G`“Ò–¤xÐérhE¡'ðE:µÊsy™­—ÂÜç§²ãûM©ûts[¤˜6GÙyËàŠDÍ¢c{ú‰´Ç~·I7XEŒþdÊOœo Á¶ÿêôñ"IøaàCÔ–ÊnŒ(>·È4vaà·Gœ¶ ¯(5|óÿ1cË€?�®H˜ãööøaà„;³D§�KCB QÂÞcFKÛ<^ýú|j»3@01—ž£üyšôqJ·t ¾s‚ι”Be͆ODÒ(núò2GÂÓ3~ \ÔÝ9±MêÑÈû›°ë³ÉºKw=»x¤T$Ѩ�Ñ[Eo@G|ƒÙIA¯düÅŸøaàÔÇíè$â´Üãy©]u¡;ÿßÊð ’\ªßçÈ!êIt@æØ+ ÷NÆ"øaà„1ÞçN£Î‚e�%[¦Lƒ>Œ¯~F ‡n�]:nEþ ãc~qs’ÝÄeÓÏ­CßçÎØçOƒ8·Yãl*~úÝÉ4׋ð[< GîWOïϲØc®¶«“lé5º‡Xð¯7"fø–¾F¥l J}’søaà:ø#5ÍM7Ý‚§8:5Y ¿òNï«w)@X½¶ŠÑûÆ7Jàƒ³Ë@õçYŽÜÍLÛÿzhcX AÆz©™Œ©W6ߊ ô>Þ5:÷?W þäÝL¿/‡ÀâpuGžŒ½ŽãºìNËS¬)Xréøaà+§_²Bh+ä9€:ø1ñÜ~M¬�Ý\I�·ÍÞÓ–iª<óÎÐÇÒ(�kµ �·Uuzc´_툥õi…üPîI|.ÎŒ¼Ké8@œ#v¦[;m=Ý�ŠP—ÏÙ5ˆ«€9UþžÜÔ©o–¯¡þ&Ù‹îšØPD®(`Iøaà…�6Ø1ši\Eì(,ÙŠ³ª•‡èE] R¹ÀÛ)FV%ê÷_ûŒ‚,2�+Lªï;U­A$?µ75�b‘ÓÜ_³Ô‰+L¬”í?{yoÖ°Pœ· &³Gëé|ˆjC•á‡ï@$Üy$.À³Ï3ì”q øaà!kœ¶‹ËpÞýãTïÅjô‡UGwCqâ†aVöÆÍKŸ<ð}ƒ„P'T7G‚¿¤Ä(/�ÃT}‹E¾D ÄkœŸMôº•åÝEÏëy-æe%ÛFŽý1ÑÀÔ;+\ÏyÀã'ö¦|µuÈÃøÖ«?ÊUJ ²m1QGÓøaäyðä¶ê�™»š*ºQK—í–›gr¤ƒÒÖɽò&“y‰�[ÿd3y¾ë5ÓÜÅr˜Ëôzf§�BBeGý î`ñV-…Q»J÷âßÝ([=´ ¯Ô¶¼Ëa¿™Z)ýžn·c½ ²eelç#ß3ø7ÛøaäY1ÕÙJ¢xô>RÖ3Þ&Xï%ayÀæ`Ÿ÷Ȩ°ãi9xäÏXu’„‰;˪[c_Q|ÇTÔ—ŒÎozeuS=n1hú¤ƒ’ðž²g„+Kô^ÕÓ�e_'^9uÆxÌ´ÕI„±1¾nå6ãò‹H: “£bøaà$àÎ1Ú~ÒíÃüZïz�$Ü}Zw ŒÈ5Ø[F5™æEH3H†ÞÝ·x��ÚkžÍákŠ×<§TU¥‘Ø“¨ú¬V=Ïÿt߸µõ½+ �FtÂsÀ…=³©½1l¡½Î¯mùYÞ1w[ÚÅ«çXÇhJꡟAøaà9øbÜYXÝðäÕ€Pj\õùA#12j‹ì—Eä€Vðû¾»øjö£@ d²|/ö¯TâöAïÅ=9�¥ÍÉ…Î0ÉÃÿãìÊq£Ê9æM>wP‘€­Ûý¦Uémϲí—ùƒŠ~’G ¦„Š%[>ŸiZ oâøaà$*k�°Púò©Kç‚°º|óødn:ãZµ ä;7QR}e«á øaaŽ‹®mò?lÂI(q¬è�Ÿk6ìUËïïöílžÆÂÚYuOˆtôn¾6ù6ûaÜFÜLî¶3.Lla…K ªi sz¥SõòF⬩‘[åøaà„6×êÒ¡€7œËÐk¶Ö6þ ìð–ÂGòÖDù*‡4l¼Ÿµ›¡%OÀLo¯#9™c[oH�ï¹S²x©Þ'¯#‡¦SUîu¨@%‘aàTÙÜáiMù�·k;iùÔ©µˆf¯y�Ä1z #„øaå´`á£rwqEÈM’™cC˜DP糞þV¤´ŽøÑÓ`\ùÔ‰2†ò5•C§RSñÜíßÝÌ �mf›÷œ%u�6g( ½+4pÞΗpùoQ%Èð;XÀžÇbÄ› VI×¶_ñ¥ÿÂTŸ§OìU€Ï'ÅÔ¯„&øaåV¹Éœq ˆ‚)²‡EÁy8E§±¼DnÛ pPÓõ¡Òf_!æÇÛ+‰vÖôsžÔÕ%Da€'gbiÃY>ÉSEÿ“�HFjf«ÿá±%Ð0áÿç“:„NÙ> SÝ$.7S’·äM)â‰/DPî°'øaäN>=)�Ô"µâ…G¡�Ó±&ƒpÃדá%=�Ôè@Jß²4i)V÷¶[ÇÀÉV�¤Ohix¯´³<\"¹•e€}Âá*L¨ëoå­Å·U,ÿªOú/Ó)C0}”"_ býò§Vc@9Xì·([+d—_øaà,™~‰“î:@HÏ”xÞC¿°ÞÄåNPVÏc„5iL¦�îª9ô¹uOàª,™#IO®C˜hôÓu+ }®=Cü7\®+õ*�ëòŒìöé„^“Æ„ûÖê¼Â¾–n9{Ëu�.Cûm×�g1féŸÐ‰a�¬{iž"I`‡rS Aøaà+¥#dÆ·Ä‚¶¹ä]qaVÿ8×ròÅ™É>%Û�Çu’¬ÞTÃMv$³¾^ð½(Or'� ]ÿ¶M¥A¥ƒ˜7�Ps«N²ÇØ[‘Tí‡"âU¤ÀÌéè•Ê¢Y¹õ¾ÓÁ¦B?bî°TeTl�ö ΀e¤k0sT?Hà¯ßôøaà+¯ÿUp)„@êÌoÜÇ>i+¥Un{(BkOO$H<ïßA»y™ / Sî�Þ 1L“§tè1¾ö™qú�Ò]l÷=§iªÂ™m�h0€!”áßåJÌ€Àüê<�«q° ZØ·r ŽŠc`vÊYp¨£øaà~Óc¿^ÇsBtB 8ô»Ñ¦ÝùŽ×J ¦j%Xg}pÛ i 4êRNÙ¾/}Q‘hj@¬À¶- ÁÃzä;_A bs¼´¹H™Ð„Liµ=ŸàCÎò*‡Wݶ‹ê‚Nl¬˜€á+/í^†Îù<:qf\«UЇΛ?ÚøaàsWÚNͻҿŠ}ÁYì’)hàd P0H©F¨5rû}§Ñ”Í—fd1Zo¬õ~©ÚÈ{µ%qLå×É1| jà üs®¥LÚœH¨ö˜dé§ñ×­¾€µ~φÜl§'‡‘˜»~ æÌ‹èì±ñãV4o1qHøaàƒ§Êt0¾lÒ‡óÒþFÊ„1žž‘ºÊ_ÁY�ñÔ�íaøi'Ÿ,V0âÃ¿Ž¹ÉTkûôb‘€ve/ŸuÝx"Ôâ,b1Ðf£=ÛŸ¿v›‹U½à™fá}†;ÊÏÛ‰2>u{c?,…¼ĵ,©Î¦QëwÛYÕ&þñ†¿m¥ºyøaäx» IUíG>ñ¿L‚õdGNÌÃîÀ$”%¤ /Ž˜ØÕM@Ù‡»ô•t?lsªìÖ›ÙÎ&×"aÄogÌ3G[à€½²ç¯W%a—PãøÎz¬á¾’F}E­‹CŠÞUeâo{iä–׆IJF¼âp£»—¶+±/ ¡%n¢øaà€ f¬i<Èp ,9òe(°Qæîh9ÝÎ|# ‚‡ª.U‰«u ¦¦)š�Ï…]¹fý237p–±M\¬wE]�ìÒ ·± Õ¨ÌÓV*¶MyãYcyŠÀ_yÃ``„w}´á:b<4a½Ë6?Ùå‘„‘DG–¼£}öä÷5q<ýøaåŠß~šâ0±réG)YådP›yyÁ+e…Á7k“#'q8 Ò¥ˆñìó™lÍæLh .~_9|±�À‡d»7—ŒH¦ ä¤n&×/üÞj’F÷Ì=­b®ŽÓñ†Á»fŒ_<û™QÝV€øú¿,~YóãBøaäyDÌôsH‹5¿qG Ñ µP î$ö˜­ÃƯ³b÷òlæä¬ÐÍ…! £o†ÄëWÃò+è%õâƒ~ÔÄóMVÇê„dÕÒŠ¾}à\"âŠQSÕ!Ü>[}+D½ý,dËé+"©`ÄOŽŸ“E–Ågøaà,{tþ\ÛEpÒÒ€Ë>Sò,›ìCk{ ¼à}…}¨ô©wÙ_¬35µ²ç͵ÑNèð÷©P³tþ;8eû#eNX‚Çn]­©�Û6÷)û”æ:úF z2è!Ž�@kGåÛ’ŸR ©jfT¯\¼VWó�"Ù‹ƒD�P†×ëb…Cøaà…‰¿{á‹§…L±3ørñ±·%C‰uÂŒu…tA̰ڕŽHæþãopŸƒ×pÕèŒÿ„<³«àFfŰÀÁvÉaÓÒàÝÃø³7À1Ûpß ;5.ÜfˆY²kñx¾^rÂS—¯¿ñ%G‘©iå…]‡ª4Й Xùøaà……iæ#ˆ�á¡I Óí"TˆÀ ;Lù\^S µRÝC" lú†Vª¡ÌMdÕ@C­ÿ[Ó5­Y5r¾#T¦Ö%^°lílÓ’R0SÒz<äOÒ±c<õi÷o’pw3\øßuöEn8 n+D €Œùžé ˜qùòøaäFǹö¡è­imªîŠo¼~–y¬­(p|Èð‹g¡Ÿî*tÄ’Iû0ï0ê½XÑ€YXÖßä�°8s˜úoÔÄÊ�K»tXL¢îKã(ºð?Åé…/81"Û1½‘ŒÛ5G]ÑÒçl=7ÍÑžØr=ÂN_×ãX5Ü®VÅÀªœ*¼R^ßÝÞ7¹·`TÐÍçç»ýùì“'Žy�Q¿XÀqù M Ô¯HPN¤@OggSä¼'·oJ¤@0¤ø}ú¡>Ú¤ªîpxZ„=BF>³-&ÿëAÌz"œ:>³˜Ö'óªKóqß\Fî:!N r€h «}�ñ'M¤yz5雯G4®Ë³nœ‚QhgŠQ¡sŽ’ÁT*†¥´›NÈ�ƒïÞ�³¦¡X)v¬)ÊŽU,QN ¶´ø�©¬}ŽH_ª«¬2ì2ô©ì,'\I¼e·½Áfk–³y5ùXbeetbox-beets-00724b7/test/rsrc/test_completion.sh0000664000175000017500000000566215253035401021560 0ustar pieterpieter# Function stub compopt() { return 0; } initcli() { COMP_WORDS=( "beet" "$@" ) let COMP_CWORD=${#COMP_WORDS[@]}-1 COMP_LINE="${COMP_WORDS[@]}" let COMP_POINT=${#COMP_LINE} _beet } completes() { for word in "$@"; do [[ " ${COMPREPLY[@]} " == *[[:space:]]$word[[:space:]]* ]] || return 1 done } COMMANDS='fields import list update remove stats version modify move write help' HELP_OPTS='-h --help' test_commands() { initcli '' && completes $COMMANDS && initcli -v '' && completes $COMMANDS && initcli -l help '' && completes $COMMANDS && initcli -d list '' && completes $COMMANDS && initcli -h '' && completes $COMMANDS && true } test_command_aliases() { initcli ls && completes list && initcli l && ! completes ls && initcli im && completes import && true } test_global_opts() { initcli - && completes \ -l --library \ -d --directory \ -h --help \ -c --config \ -v --verbose && true } test_global_file_opts() { # FIXME somehow file completion only works when the completion # function is called by the shell completion utilities. So we can't # test it here initcli --library '' && completes $(compgen -d) && initcli -l '' && completes $(compgen -d) && initcli --config '' && completes $(compgen -d) && initcli -c '' && completes $(compgen -d) && true } test_global_dir_opts() { initcli --directory '' && completes $(compgen -d) && initcli -d '' && completes $(compgen -d) && true } test_fields_command() { initcli fields - && completes -h --help && initcli fields '' && completes $(compgen -d) && true } test_import_files() { initcli import '' && completes $(compgen -d) && initcli import --copy -P '' && completes $(compgen -d) && initcli import --log '' && completes $(compgen -d) && true } test_import_options() { initcli imp - completes \ -h --help \ -c --copy -C --nocopy \ -w --write -W --nowrite \ -a --autotag -A --noautotag \ -p --resume -P --noresume \ -l --log --flat } test_list_options() { initcli list - completes \ -h --help \ -a --album \ -p --path } test_list_query() { initcli list 'x' && [[ -z "${COMPREPLY[@]}" ]] && initcli list 'art' && completes \ 'artist:' \ 'artpath:' && initcli list 'artits:x' && [[ -z "${COMPREPLY[@]}" ]] && true } test_help_command() { initcli help '' && completes $COMMANDS && true } test_plugin_command() { initcli te && completes test && initcli test - && completes -o --option && true } run_tests() { local tests=$(set | \ grep --extended-regexp --only-matching '^test_[a-zA-Z_]* \(\) $' |\ grep --extended-regexp --only-matching '[a-zA-Z_]*' ) local fail=0 if [[ -n $@ ]]; then tests="$@" fi for t in $tests; do $t || { fail=1 && echo "$t failed" >&2; } done return $fail } run_tests "$@" && echo "completion tests passed" beetbox-beets-00724b7/test/rsrc/full.aiff0000664000175000017500000025632015253035401017604 0ustar pieterpieterFORM\ÈAIFFCOMM¬D@¬DSSNDX�ÿÿÿþÿþÿþÿÿÿþÿþÿýÿüÿþÿÿÿýÿþÿÿÿÿÿÿÿýÿûÿýÿþÿüÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿþÿþÿþÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿþÿþÿüÿýÿþÿþÿýÿýÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿûÿþÿÿÿýÿþÿÿÿüÿþÿþÿýÿüÿÿÿýÿýÿýÿÿÿþÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿúÿüÿÿÿÿÿýÿûÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿþÿÿÿÿÿÿÿýÿýÿþÿýÿþÿþÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿûÿúÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿþÿýÿþÿûÿýÿÿÿÿÿþÿþÿýÿÿÿýÿýÿýÿÿÿþÿýÿþÿÿÿþÿüÿýÿÿÿþÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿþÿûÿüÿÿÿÿÿþÿüÿûÿþÿÿÿÿÿýÿûÿþÿþÿþÿûÿûÿÿÿþÿüÿýÿþÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿþÿþÿþÿÿÿýÿûÿýÿýÿüÿýÿþÿþÿþÿÿÿÿÿþÿÿÿþÿþÿÿÿýÿüÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿþÿþÿýÿÿÿþÿÿÿýÿýÿþÿþÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿÿÿþÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿþÿýÿýÿýÿþÿÿÿþÿýÿüÿûÿûÿýÿþÿÿÿþÿýÿüÿýÿþÿýÿþÿýÿýÿûÿüÿþÿýÿûÿüÿüÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿüÿýÿÿÿÿÿüÿþÿÿÿÿÿÿÿýÿþÿþÿýÿÿÿýÿýÿüÿýÿþÿþÿÿÿþÿüÿüÿþÿþÿÿÿüÿûÿüÿûÿýÿÿÿÿÿþÿûÿüÿþÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿüÿÿÿÿÿÿÿþÿýÿþÿýÿüÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿüÿûÿýÿÿÿþÿÿÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿþÿþÿüÿûÿûÿüÿþÿÿÿþÿþÿÿÿÿÿýÿýÿþÿþÿûÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿûÿýÿýÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿýÿÿÿþÿþÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿÿÿþÿþÿýÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿþÿÿÿþÿýÿýÿýÿüÿÿÿýÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿÿÿÿÿÿÿþÿüÿþÿýÿûÿüÿþÿýÿþÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿüÿüÿüÿÿÿþÿüÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿüÿþÿþÿÿÿýÿþÿþÿÿÿþÿþÿüÿÿÿþÿÿÿþÿûÿúÿýÿÿÿþÿÿÿÿÿÿÿýÿþÿýÿýÿþÿþÿþÿþÿÿÿþÿþÿýÿüÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿþÿþÿÿÿþÿýÿýÿüÿýÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿþÿÿÿþÿýÿþÿýÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿþÿþÿýÿþÿýÿþÿþÿýÿüÿüÿþÿÿÿÿÿþÿýÿþÿþÿþÿþÿÿÿÿÿüÿüÿýÿþÿþÿþÿÿÿýÿùÿûÿýÿþÿþÿþÿÿÿÿÿüÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿþÿüÿþÿÿÿþÿûÿýÿýÿýÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿüÿüÿýÿýÿûÿÿÿýÿýÿþÿýÿÿÿÿÿûÿýÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿÿÿüÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿþÿýÿüÿüÿþÿþÿþÿþÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿþÿýÿþÿýÿýÿüÿþÿÿÿüÿüÿüÿýÿýÿüÿüÿþÿÿÿýÿûÿûÿüÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿþÿþÿÿÿþÿþÿþÿþÿúÿûÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿþÿÿÿþÿþÿÿÿýÿþÿüÿüÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿûÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿþÿüÿüÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿýÿýÿþÿüÿûÿýÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿþÿýÿüÿýÿþÿþÿÿÿþÿüÿûÿûÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿüÿÿÿýÿüÿþÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿþÿÿÿÿÿþÿÿÿþÿþÿÿÿüÿüÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿüÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿûÿþÿÿÿþÿýÿüÿýÿþÿþÿþÿÿÿýÿûÿûÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿüÿþÿþÿýÿþÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿüÿýÿýÿþÿûÿüÿýÿÿÿÿÿýÿÿÿÿÿýÿþÿþÿüÿýÿýÿýÿýÿþÿþÿÿÿþÿÿÿÿÿýÿûÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿûÿüÿþÿÿÿüÿüÿÿÿÿÿþÿþÿÿÿýÿýÿþÿþÿýÿýÿýÿþÿÿÿþÿýÿþÿüÿüÿþÿûÿþÿýÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿýÿýÿÿÿÿÿþÿþÿüÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿýÿüÿÿÿÿÿþÿþÿþÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿýÿûÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿÿÿþÿýÿÿÿþÿýÿýÿþÿûÿûÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿüÿüÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿÿÿÿÿýÿýÿüÿýÿþÿþÿýÿþÿÿÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿþÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿýÿþÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿüÿüÿüÿüÿýÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿþÿþÿÿÿýÿüÿþÿûÿüÿþÿþÿþÿÿÿÿÿÿÿüÿüÿýÿþÿþÿþÿÿÿþÿþÿýÿúÿýÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿýÿýÿþÿÿÿþÿþÿþÿÿÿýÿýÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿýÿþÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿþÿýÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿýÿþÿýÿþÿÿÿýÿþÿþÿüÿüÿþÿþÿüÿýÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿûÿûÿþÿþÿüÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿþÿÿÿýÿþÿýÿüÿüÿüÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿÿÿþÿþÿÿÿýÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿýÿþÿþÿÿÿþÿþÿÿÿûÿüÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿýÿûÿýÿþÿþÿýÿüÿþÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿýÿþÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿüÿýÿþÿüÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿüÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿþÿÿÿüÿüÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿþÿþÿýÿýÿÿÿüÿüÿþÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿüÿýÿþÿÿÿþÿüÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿýÿþÿþÿþÿýÿþÿÿÿýÿüÿþÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿüÿûÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿüÿþÿýÿûÿúÿüÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿýÿúÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿüÿýÿþÿüÿýÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿúÿýÿÿÿýÿþÿÿÿÿÿþÿûÿùÿýÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿýÿýÿûÿûÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿýÿüÿýÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿþÿýÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿÿÿýÿûÿûÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿüÿúÿÿÿþÿûÿûÿúÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿþÿÿÿþÿÿÿþÿþÿÿÿüÿýÿÿÿüÿüÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿÿÿýÿüÿýÿüÿÿÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿþÿþÿÿÿüÿÿÿÿÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿþÿüÿüÿýÿÿÿÿÿþÿýÿþÿþÿÿÿýÿûÿüÿÿÿýÿþÿýÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿüÿýÿþÿÿÿÿÿþÿÿÿþÿüÿýÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿþÿÿÿýÿüÿþÿÿÿýÿþÿÿÿÿÿýÿûÿþÿüÿýÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿýÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿýÿûÿÿÿÿÿÿÿÿÿÿÿþÿûÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿüÿýÿþÿýÿüÿþÿÿÿýÿûÿüÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿüÿüÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿþÿýÿüÿýÿýÿýÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿýÿÿÿþÿþÿüÿþÿþÿÿÿýÿýÿýÿýÿþÿüÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿþÿýÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿþÿþÿûÿüÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿüÿýÿÿÿÿÿÿÿÿÿÿÿüÿýÿýÿüÿþÿÿÿÿÿþÿþÿýÿþÿýÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿýÿÿÿþÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿýÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿüÿÿÿÿÿüÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿýÿûÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿýÿÿÿþÿÿÿûÿùÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿþÿüÿýÿüÿýÿþÿÿÿÿÿüÿÿÿÿÿüÿÿÿÿÿûÿúÿûÿÿÿÿÿþÿþÿÿÿþÿýÿüÿþÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿýÿþÿþÿýÿüÿýÿÿÿýÿþÿþÿüÿüÿþÿþÿýÿÿÿþÿüÿþÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿþÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿýÿýÿýÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿþÿÿÿþÿþÿþÿýÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿþÿýÿþÿÿÿýÿÿÿþÿÿÿýÿüÿÿÿÿÿûÿûÿýÿÿÿÿÿýÿýÿýÿÿÿýÿýÿüÿþÿýÿûÿýÿÿÿýÿùÿúÿüÿÿÿþÿþÿÿÿüÿþÿÿÿÿÿþÿþÿþÿýÿüÿÿÿþÿüÿýÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿýÿýÿÿÿþÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿýÿýÿÿÿþÿÿÿÿÿþÿýÿþÿýÿþÿûÿüÿþÿþÿþÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿýÿþÿýÿûÿûÿÿÿÿÿýÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿýÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿýÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿúÿûÿýÿÿÿÿÿþÿüÿýÿþÿþÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿýÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿüÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿÿÿþÿüÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿþÿþÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿýÿýÿþÿÿÿþÿüÿýÿýÿþÿþÿýÿûÿýÿÿÿþÿüÿûÿýÿýÿÿÿþÿýÿÿÿþÿÿÿüÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿþÿÿÿþÿýÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿÿÿýÿüÿýÿýÿþÿýÿýÿÿÿýÿýÿþÿÿÿÿÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿþÿÿÿþÿþÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿûÿþÿÿÿýÿýÿÿÿÿÿýÿþÿþÿûÿûÿýÿÿÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿûÿýÿûÿüÿþÿýÿþÿþÿûÿüÿÿÿýÿýÿýÿýÿÿÿüÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿþÿýÿþÿþÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿúÿýÿÿÿÿÿýÿüÿüÿþÿþÿÿÿüÿþÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿþÿþÿÿÿüÿýÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿþÿýÿýÿÿÿüÿýÿÿÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿþÿþÿûÿùÿûÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿÿÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿùÿúÿþÿÿÿþÿýÿýÿþÿþÿÿÿÿÿþÿýÿþÿýÿýÿþÿüÿüÿþÿþÿÿÿýÿüÿÿÿÿÿýÿüÿüÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿýÿüÿûÿþÿÿÿýÿþÿþÿÿÿÿÿýÿüÿþÿþÿýÿýÿþÿÿÿþÿÿÿÿÿþÿûÿýÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿüÿÿÿÿÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿüÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿûÿúÿýÿÿÿþÿýÿüÿüÿþÿýÿÿÿÿÿýÿþÿÿÿþÿýÿüÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿýÿþÿÿÿþÿÿÿÿÿüÿûÿýÿÿÿþÿþÿþÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿúÿüÿÿÿÿÿÿÿþÿýÿÿÿýÿûÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿýÿþÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿüÿúÿûÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿüÿÿÿÿÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿýÿûÿýÿþÿþÿÿÿþÿþÿÿÿÿÿüÿüÿýÿþÿÿÿýÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿþÿüÿÿÿþÿÿÿþÿýÿýÿÿÿþÿüÿúÿúÿûÿÿÿþÿÿÿþÿüÿûÿûÿýÿþÿýÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿýÿÿÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿþÿýÿüÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿúÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿüÿýÿýÿüÿüÿüÿþÿÿÿÿÿÿÿýÿüÿÿÿþÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿüÿüÿûÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿýÿÿÿÿÿþÿþÿúÿþÿÿÿúÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿýÿþÿþÿýÿÿÿþÿþÿþÿþÿÿÿÿÿþÿüÿüÿýÿþÿüÿüÿÿÿÿÿûÿûÿüÿþÿüÿüÿþÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿýÿþÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿýÿýÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿýÿüÿýÿÿÿþÿþÿüÿýÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿþÿþÿþÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿüÿüÿüÿþÿÿÿýÿüÿþÿýÿþÿþÿýÿýÿþÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿúÿþÿÿÿüÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿÿÿýÿýÿÿÿþÿþÿüÿýÿýÿûÿüÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿþÿþÿüÿýÿÿÿþÿþÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿýÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿüÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿüÿüÿûÿýÿþÿýÿýÿýÿûÿýÿýÿýÿýÿþÿûÿþÿÿÿþÿÿÿÿÿþÿÿÿüÿûÿýÿÿÿþÿüÿýÿÿÿýÿýÿýÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿýÿýÿýÿýÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿýÿûÿýÿÿÿÿÿÿÿýÿýÿÿÿÿÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿþÿûÿùÿúÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿýÿýÿþÿÿÿþÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿÿÿþÿüÿûÿþÿýÿÿÿþÿþÿýÿýÿýÿýÿûÿüÿþÿÿÿþÿþÿýÿúÿúÿúÿûÿÿÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿüÿþÿýÿüÿýÿþÿÿÿÿÿüÿûÿþÿüÿýÿýÿþÿýÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿþÿþÿÿÿýÿþÿÿÿýÿþÿþÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿÿÿüÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿýÿýÿüÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿüÿüÿüÿýÿþÿýÿýÿÿÿÿÿþÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿÿÿûÿûÿûÿûÿýÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿüÿþÿþÿþÿýÿÿÿþÿýÿýÿþÿýÿþÿþÿüÿþÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿüÿüÿüÿüÿüÿüÿýÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿüÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿþÿþÿþÿÿÿüÿûÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿûÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿûÿüÿÿÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿüÿþÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿþÿþÿþÿüÿÿÿÿÿÿÿýÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿþÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿþÿþÿÿÿþÿÿÿÿÿüÿüÿÿÿþÿþÿþÿýÿþÿÿÿÿÿýÿÿÿþÿýÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿúÿùÿüÿþÿýÿýÿÿÿþÿýÿÿÿþÿüÿýÿÿÿýÿúÿýÿýÿûÿûÿÿÿþÿýÿûÿüÿþÿþÿÿÿýÿüÿþÿÿÿþÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿýÿÿÿþÿýÿüÿÿÿÿÿþÿþÿþÿþÿþÿýÿüÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿüÿûÿýÿþÿþÿþÿþÿþÿþÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿýÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿþÿýÿýÿþÿþÿûÿùÿúÿýÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿûÿúÿüÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿüÿýÿÿÿþÿúÿùÿþÿÿÿÿÿÿÿþÿýÿþÿýÿþÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿýÿÿÿÿÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿüÿùÿüÿÿÿýÿÿÿÿÿþÿýÿÿÿüÿýÿþÿþÿýÿýÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿüÿþÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿúÿûÿÿÿÿÿüÿýÿþÿýÿþÿüÿýÿÿÿþÿüÿûÿýÿýÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿýÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿýÿýÿþÿÿÿýÿÿÿýÿþÿÿÿÿÿþÿüÿýÿÿÿþÿýÿüÿþÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿüÿýÿþÿýÿÿÿÿÿþÿýÿþÿýÿþÿÿÿþÿüÿþÿýÿÿÿÿÿþÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿþÿýÿþÿÿÿþÿÿÿþÿþÿûÿýÿÿÿÿÿþÿýÿýÿüÿûÿþÿÿÿþÿþÿÿÿÿÿüÿûÿÿÿþÿþÿþÿÿÿþÿúÿþÿþÿÿÿÿÿþÿþÿýÿþÿþÿýÿÿÿÿÿþÿûÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿûÿýÿÿÿüÿþÿþÿÿÿüÿÿÿÿÿþÿüÿûÿúÿüÿÿÿüÿúÿþÿþÿÿÿÿÿþÿýÿýÿþÿüÿûÿýÿÿÿþÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿúÿùÿýÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿüÿüÿüÿýÿÿÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿüÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿüÿþÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿüÿÿÿþÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿÿÿþÿýÿþÿþÿüÿüÿýÿþÿüÿûÿþÿÿÿÿÿýÿüÿýÿýÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿþÿþÿýÿýÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿýÿþÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿþÿþÿþÿþÿüÿüÿýÿýÿþÿþÿÿÿþÿüÿüÿýÿÿÿýÿûÿûÿÿÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿýÿüÿüÿüÿÿÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿþÿüÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿýÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿûÿýÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿüÿýÿýÿýÿÿÿþÿþÿÿÿÿÿýÿüÿýÿüÿýÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿüÿþÿÿÿþÿüÿþÿÿÿÿÿüÿýÿÿÿþÿýÿýÿþÿýÿûÿüÿýÿýÿþÿÿÿÿÿÿÿüÿúÿýÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿüÿýÿþÿýÿÿÿÿÿÿÿýÿüÿþÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿþÿþÿþÿüÿüÿþÿüÿÿÿþÿþÿýÿÿÿÿÿþÿýÿþÿýÿþÿüÿýÿýÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿûÿüÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿþÿþÿþÿþÿýÿþÿÿÿýÿýÿÿÿýÿýÿüÿþÿûÿýÿþÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿþÿûÿùÿúÿýÿþÿþÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿüÿýÿþÿþÿýÿýÿýÿýÿýÿýÿþÿýÿþÿüÿþÿþÿþÿÿÿÿÿÿÿýÿüÿüÿýÿÿÿþÿüÿüÿÿÿþÿúÿúÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿýÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿûÿþÿÿÿÿÿýÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿýÿüÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿþÿÿÿþÿþÿüÿùÿùÿýÿþÿÿÿþÿÿÿÿÿÿÿüÿûÿüÿÿÿÿÿþÿýÿÿÿþÿýÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿýÿýÿÿÿýÿüÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿýÿüÿýÿÿÿÿÿÿÿüÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿýÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿýÿüÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿýÿþÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿýÿþÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿþÿûÿûÿþÿÿÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿÿÿþÿýÿþÿüÿüÿþÿÿÿÿÿÿÿüÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿüÿýÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿþÿþÿÿÿþÿýÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿþÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿÿÿþÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿýÿþÿþÿþÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿýÿþÿûÿüÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿýÿýÿýÿýÿþÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿþÿýÿüÿýÿþÿÿÿýÿÿÿþÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿýÿýÿüÿþÿüÿúÿüÿþÿýÿþÿüÿüÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿýÿþÿýÿýÿýÿûÿüÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿýÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿýÿÿÿþÿûÿýÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿÿÿÿÿÿÿÿÿþÿýÿüÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿýÿýÿþÿþÿüÿûÿýÿýÿýÿýÿþÿÿÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿýÿþÿûÿþÿÿÿÿÿÿÿþÿýÿÿÿýÿúÿþÿÿÿüÿþÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿýÿüÿÿÿÿÿüÿÿÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿüÿýÿþÿþÿýÿýÿûÿÿÿÿÿüÿÿÿÿÿþÿÿÿýÿÿÿþÿûÿüÿýÿÿÿþÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿþÿýÿüÿýÿÿÿýÿüÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿÿÿÿÿýÿûÿýÿþÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿüÿýÿÿÿþÿþÿýÿþÿÿÿþÿÿÿþÿþÿûÿýÿÿÿÿÿýÿþÿýÿýÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿÿÿþÿüÿÿÿÿÿüÿýÿûÿýÿýÿüÿýÿüÿüÿÿÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿýÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿþÿüÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿýÿþÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿýÿýÿýÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿüÿûÿüÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿüÿþÿþÿýÿýÿþÿÿÿÿÿüÿýÿþÿÿÿþÿÿÿûÿûÿþÿüÿûÿÿÿÿÿÿÿþÿþÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿüÿÿÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿüÿýÿþÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿÿÿÿÿýÿüÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿþÿþÿýÿþÿýÿþÿþÿþÿþÿýÿüÿÿÿþÿüÿûÿûÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿþÿúÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿÿÿÿÿÿÿýÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿüÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿýÿþÿÿÿýÿÿÿÿÿÿÿÿÿüÿûÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿýÿþÿþÿþÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿýÿýÿýÿûÿûÿüÿþÿýÿýÿþÿþÿþÿýÿþÿýÿþÿÿÿþÿýÿüÿþÿýÿüÿþÿÿÿÿÿþÿþÿþÿþÿþÿüÿüÿþÿýÿýÿÿÿÿÿÿÿüÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿüÿþÿÿÿÿÿüÿýÿýÿþÿýÿþÿÿÿÿÿÿÿþÿýÿýÿüÿÿÿÿÿÿÿýÿþÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿúÿüÿýÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿýÿÿÿÿÿþÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿýÿüÿûÿþÿÿÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿûÿþÿþÿüÿþÿýÿüÿþÿþÿþÿþÿüÿýÿÿÿÿÿþÿþÿÿÿþÿþÿýÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿþÿÿÿÿÿýÿüÿûÿúÿúÿýÿÿÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿÿÿýÿÿÿþÿüÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿÿÿþÿþÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿÿÿýÿüÿüÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿþÿýÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿýÿÿÿüÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿûÿûÿúÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿûÿþÿÿÿÿÿÿÿþÿýÿüÿýÿþÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿýÿüÿÿÿþÿýÿÿÿýÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿýÿûÿûÿþÿÿÿÿÿÿÿûÿûÿþÿýÿþÿýÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿüÿþÿÿÿþÿýÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿüÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿÿÿüÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿýÿýÿÿÿÿÿýÿüÿþÿÿÿþÿûÿýÿþÿþÿÿÿþÿþÿþÿýÿÿÿýÿÿÿÿÿþÿýÿÿÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿûÿûÿþÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿÿÿþÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿýÿûÿýÿÿÿþÿþÿÿÿÿÿþÿþÿüÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿüÿûÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿþÿûÿûÿþÿÿÿÿÿþÿýÿûÿÿÿÿÿÿÿÿÿþÿýÿýÿüÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿýÿþÿýÿÿÿÿÿüÿüÿýÿÿÿþÿÿÿÿÿýÿÿÿþÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿüÿúÿûÿýÿÿÿþÿýÿÿÿýÿýÿÿÿÿÿýÿþÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿüÿýÿÿÿýÿýÿûÿúÿüÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿüÿùÿûÿþÿÿÿÿÿÿÿÿÿþÿýÿüÿþÿÿÿÿÿþÿÿÿþÿþÿýÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿýÿýÿýÿýÿýÿýÿþÿÿÿÿÿýÿþÿýÿûÿþÿÿÿýÿþÿüÿýÿÿÿÿÿþÿþÿÿÿýÿúÿüÿÿÿþÿþÿýÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿþÿüÿýÿüÿúÿûÿýÿÿÿþÿýÿÿÿþÿþÿüÿýÿÿÿþÿýÿþÿýÿÿÿþÿþÿÿÿþÿþÿþÿþÿûÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿþÿýÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿüÿýÿýÿþÿÿÿýÿýÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿþÿþÿþÿþÿüÿûÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿþÿþÿþÿÿÿþÿýÿýÿÿÿüÿüÿþÿÿÿüÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿûÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿþÿýÿþÿþÿýÿþÿÿÿÿÿþÿýÿÿÿþÿüÿýÿýÿýÿþÿûÿûÿûÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿýÿþÿýÿýÿýÿþÿÿÿýÿüÿÿÿÿÿÿÿÿÿýÿüÿüÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿþÿýÿþÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿþÿýÿþÿýÿýÿÿÿýÿþÿþÿýÿÿÿþÿÿÿþÿûÿûÿþÿýÿýÿÿÿÿÿýÿþÿÿÿýÿüÿýÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿþÿüÿüÿúÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿüÿÿÿþÿþÿþÿþÿûÿýÿÿÿÿÿþÿûÿüÿýÿþÿþÿÿÿþÿþÿþÿýÿýÿþÿýÿÿÿÿÿÿÿþÿþÿýÿýÿþÿýÿýÿýÿÿÿþÿþÿýÿÿÿýÿþÿýÿÿÿÿÿþÿüÿýÿüÿýÿÿÿüÿùÿúÿþÿÿÿþÿüÿüÿÿÿÿÿþÿÿÿÿÿÿÿÿÿüÿüÿüÿýÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿúÿûÿþÿÿÿÿÿüÿýÿÿÿþÿüÿýÿÿÿþÿþÿÿÿþÿþÿþÿýÿÿÿþÿþÿþÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿýÿýÿþÿýÿûÿýÿþÿÿÿþÿþÿÿÿýÿýÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿýÿúÿýÿþÿþÿÿÿÿÿÿÿÿÿûÿúÿýÿýÿûÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿýÿÿÿþÿûÿûÿýÿüÿýÿÿÿÿÿÿÿÿÿýÿýÿûÿýÿûÿþÿÿÿüÿþÿÿÿýÿûÿûÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿýÿüÿýÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿûÿûÿüÿþÿÿÿüÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿÿÿýÿÿÿýÿþÿþÿýÿþÿýÿüÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿüÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿüÿþÿÿÿýÿüÿþÿÿÿþÿÿÿþÿÿÿüÿüÿýÿþÿþÿýÿýÿýÿÿÿþÿÿÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿÿÿüÿýÿýÿûÿûÿûÿûÿýÿþÿþÿýÿÿÿþÿüÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿüÿýÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿüÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿüÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿþÿþÿüÿþÿÿÿþÿþÿüÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿþÿýÿýÿþÿýÿüÿÿÿþÿÿÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿýÿûÿúÿþÿþÿÿÿþÿÿÿýÿüÿþÿþÿÿÿüÿþÿþÿÿÿýÿýÿþÿÿÿþÿüÿüÿûÿýÿÿÿÿÿÿÿýÿÿÿþÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿþÿýÿýÿüÿüÿýÿÿÿþÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿþÿýÿûÿùÿûÿýÿÿÿþÿþÿÿÿþÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿüÿüÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿýÿýÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿýÿÿÿÿÿþÿþÿýÿüÿþÿÿÿýÿÿÿýÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿþÿþÿþÿþÿÿÿÿÿüÿüÿÿÿÿÿýÿüÿþÿÿÿþÿÿÿÿÿýÿüÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿýÿþÿýÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿüÿüÿýÿÿÿþÿÿÿÿÿÿÿýÿüÿýÿþÿüÿÿÿÿÿÿÿýÿýÿþÿþÿþÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿýÿýÿüÿûÿûÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿûÿþÿÿÿÿÿýÿýÿþÿÿÿþÿýÿÿÿýÿüÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿüÿþÿüÿýÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿýÿÿÿþÿýÿþÿüÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿýÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿýÿúÿûÿüÿÿÿþÿþÿþÿÿÿÿÿýÿüÿüÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿþÿþÿþÿýÿþÿýÿþÿýÿÿÿþÿþÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿÿÿýÿþÿýÿüÿÿÿÿÿüÿþÿÿÿþÿþÿþÿûÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿüÿüÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿúÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿýÿýÿýÿýÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿýÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿýÿüÿýÿÿÿÿÿÿÿþÿýÿþÿýÿýÿýÿþÿÿÿþÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿüÿúÿüÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿûÿûÿüÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿüÿþÿÿÿÿÿþÿÿÿýÿÿÿþÿþÿüÿüÿÿÿÿÿýÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿûÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿüÿûÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿýÿþÿþÿþÿþÿþÿþÿÿÿýÿýÿÿÿÿÿüÿÿÿÿÿþÿýÿüÿþÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿþÿþÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿÿÿýÿýÿüÿûÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿþÿýÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿýÿýÿþÿûÿýÿÿÿÿÿÿÿþÿûÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿüÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿýÿýÿýÿûÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿüÿýÿûÿýÿÿÿÿÿþÿþÿÿÿþÿýÿþÿþÿýÿÿÿÿÿüÿúÿûÿÿÿþÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿûÿúÿÿÿÿÿýÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿüÿûÿÿÿÿÿÿÿýÿýÿþÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿýÿüÿþÿþÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿþÿýÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿþÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿÿÿþÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿýÿüÿýÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿþÿÿÿýÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿþÿþÿýÿüÿýÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿýÿýÿþÿÿÿÿÿýÿûÿýÿþÿÿÿþÿýÿÿÿþÿþÿþÿÿÿýÿüÿþÿýÿüÿýÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿýÿýÿýÿûÿýÿþÿþÿýÿüÿýÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÿüÿþÿýÿúÿúÿûÿýÿÿÿþÿüÿûÿýÿýÿÿÿýÿþÿýÿýÿþÿþÿûÿüÿýÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿûÿþÿþÿÿÿÿÿýÿþÿüÿýÿýÿþÿÿÿÿÿÿÿÿÿûÿýÿýÿüÿýÿþÿýÿþÿÿÿýÿþÿÿÿýÿüÿþÿýÿüÿÿÿþÿÿÿÿÿÿÿûÿüÿÿÿÿÿþÿþÿÿÿýÿüÿþÿÿÿþÿþÿþÿýÿýÿþÿÿÿýÿüÿþÿÿÿýÿüÿýÿýÿýÿýÿÿÿÿÿüÿüÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿÿÿýÿúÿúÿýÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿýÿþÿþÿþÿýÿþÿþÿýÿüÿýÿþÿþÿÿÿþÿýÿÿÿþÿüÿüÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿýÿýÿûÿýÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿýÿûÿûÿüÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿýÿÿÿýÿýÿþÿüÿûÿýÿÿÿþÿþÿÿÿÿÿþÿþÿýÿüÿþÿþÿþÿÿÿþÿýÿÿÿþÿÿÿûÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿúÿúÿþÿÿÿýÿÿÿÿÿÿÿýÿüÿýÿýÿþÿþÿþÿÿÿÿÿþÿÿÿþÿüÿÿÿþÿþÿþÿÿÿýÿúÿûÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿûÿüÿþÿþÿüÿüÿþÿþÿÿÿÿÿýÿüÿüÿþÿþÿþÿþÿýÿüÿüÿþÿýÿüÿýÿþÿþÿÿÿÿÿýÿýÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿüÿüÿüÿüÿÿÿýÿþÿÿÿÿÿÿÿþÿûÿûÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿýÿÿÿÿÿþÿýÿüÿýÿþÿÿÿþÿûÿûÿÿÿÿÿÿÿþÿýÿýÿþÿþÿþÿÿÿýÿýÿþÿÿÿþÿýÿþÿþÿýÿýÿþÿþÿÿÿÿÿüÿÿÿÿÿþÿýÿþÿüÿüÿþÿÿÿþÿþÿþÿþÿþÿüÿúÿüÿÿÿüÿýÿÿÿþÿýÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿþÿýÿûÿýÿÿÿþÿýÿþÿþÿýÿýÿýÿýÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿþÿýÿýÿÿÿÿÿýÿûÿýÿûÿûÿýÿýÿýÿýÿýÿÿÿþÿþÿýÿüÿýÿþÿÿÿþÿüÿýÿÿÿþÿÿÿþÿüÿþÿÿÿûÿýÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿüÿÿÿÿÿÿÿþÿÿÿüÿûÿþÿþÿýÿÿÿþÿýÿÿÿýÿýÿþÿýÿýÿýÿÿÿÿÿþÿüÿüÿÿÿýÿûÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿûÿüÿþÿþÿþÿÿÿþÿþÿþÿüÿýÿþÿýÿûÿüÿþÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿûÿýÿÿÿÿÿþÿýÿþÿþÿÿÿýÿüÿýÿýÿüÿÿÿþÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿýÿüÿüÿþÿýÿþÿþÿýÿüÿþÿÿÿýÿýÿûÿþÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿüÿþÿÿÿüÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿýÿüÿÿÿÿÿýÿüÿþÿÿÿýÿüÿÿÿýÿÿÿüÿûÿþÿÿÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿüÿûÿýÿþÿþÿþÿþÿþÿþÿýÿüÿÿÿþÿûÿþÿþÿþÿýÿÿÿÿÿüÿÿÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿýÿüÿûÿûÿýÿÿÿÿÿþÿýÿýÿüÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿýÿýÿþÿýÿüÿþÿÿÿÿÿýÿýÿþÿÿÿüÿýÿÿÿýÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿüÿüÿÿÿÿÿûÿüÿýÿþÿþÿýÿÿÿþÿÿÿýÿþÿÿÿÿÿýÿýÿýÿüÿýÿþÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿýÿÿÿüÿýÿþÿýÿýÿýÿýÿÿÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿûÿùÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿþÿÿÿÿÿÿÿþÿýÿþÿüÿýÿþÿþÿÿÿþÿþÿüÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿþÿþÿüÿþÿþÿüÿüÿþÿþÿþÿýÿÿÿÿÿýÿÿÿÿÿüÿýÿþÿÿÿþÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿþÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿûÿûÿþÿÿÿýÿþÿþÿþÿþÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿüÿúÿûÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿýÿýÿþÿÿÿÿÿÿÿþÿýÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿûÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿüÿÿÿþÿÿÿÿÿþÿþÿýÿüÿüÿþÿýÿüÿþÿýÿþÿûÿþÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿúÿýÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿüÿýÿþÿýÿþÿýÿÿÿþÿüÿýÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿüÿýÿûÿüÿýÿÿÿÿÿþÿÿÿÿÿüÿþÿÿÿüÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿÿÿþÿýÿÿÿþÿþÿýÿþÿþÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿýÿýÿüÿþÿÿÿþÿýÿüÿþÿþÿýÿüÿüÿÿÿÿÿÿÿýÿþÿûÿûÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿûÿþÿþÿþÿþÿýÿüÿüÿÿÿþÿþÿÿÿþÿÿÿþÿüÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿþÿþÿþÿûÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿÿÿþÿþÿþÿûÿúÿüÿþÿýÿûÿûÿýÿþÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿýÿþÿÿÿþÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿûÿýÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿüÿýÿþÿýÿþÿÿÿÿÿÿÿþÿþÿüÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿþÿýÿþÿüÿþÿþÿþÿÿÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿþÿýÿüÿþÿýÿýÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÿÿÿþÿþÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿüÿüÿÿÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿýÿýÿýÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿýÿýÿýÿÿÿýÿüÿýÿþÿþÿþÿýÿüÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿÿÿýÿýÿþÿÿÿÿÿþÿýÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿýÿüÿüÿüÿÿÿÿÿüÿþÿýÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿûÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿýÿýÿýÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿþÿýÿþÿÿÿýÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿþÿþÿÿÿþÿþÿüÿüÿÿÿþÿþÿÿÿÿÿÿÿþÿüÿþÿþÿþÿýÿýÿþÿýÿþÿþÿÿÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿûÿüÿþÿÿÿþÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿýÿüÿþÿüÿüÿûÿýÿýÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿüÿüÿÿÿÿÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿûÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿýÿýÿþÿÿÿÿÿþÿûÿýÿÿÿþÿþÿÿÿÿÿþÿüÿþÿÿÿýÿþÿþÿþÿÿÿÿÿüÿúÿüÿýÿüÿþÿÿÿþÿüÿùÿûÿþÿÿÿþÿÿÿÿÿýÿýÿÿÿþÿûÿþÿÿÿþÿþÿÿÿþÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿþÿþÿýÿüÿüÿþÿÿÿÿÿüÿýÿþÿÿÿûÿþÿÿÿýÿýÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿüÿùÿüÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿýÿüÿýÿÿÿþÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿýÿüÿÿÿÿÿÿÿþÿÿÿÿÿüÿûÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿýÿýÿÿÿþÿüÿþÿþÿýÿýÿþÿÿÿÿÿþÿûÿýÿþÿþÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿüÿüÿþÿþÿýÿûÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿüÿûÿþÿüÿüÿÿÿÿÿþÿýÿÿÿÿÿýÿþÿþÿÿÿþÿÿÿÿÿýÿþÿþÿýÿþÿÿÿüÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿüÿýÿüÿüÿþÿþÿüÿüÿûÿüÿÿÿÿÿýÿûÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿúÿûÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿþÿýÿüÿÿÿÿÿüÿýÿÿÿÿÿÿÿýÿýÿýÿþÿýÿÿÿýÿýÿþÿÿÿÿÿýÿÿÿýÿÿÿÿÿþÿýÿýÿýÿþÿþÿýÿþÿÿÿýÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿþÿþÿþÿüÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿýÿýÿýÿþÿþÿÿÿüÿýÿþÿýÿþÿÿÿÿÿþÿýÿþÿüÿÿÿÿÿýÿüÿûÿýÿþÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿûÿþÿüÿýÿýÿþÿþÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿýÿÿÿþÿýÿüÿýÿÿÿüÿýÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿüÿýÿýÿþÿÿÿÿÿÿÿýÿþÿýÿýÿþÿÿÿþÿýÿüÿüÿÿÿÿÿüÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿýÿýÿýÿþÿúÿüÿþÿþÿÿÿþÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿþÿþÿüÿýÿÿÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿýÿÿÿÿÿüÿþÿþÿýÿüÿþÿþÿÿÿüÿþÿþÿýÿüÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿþÿÿÿÿÿúÿüÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿüÿþÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿüÿÿÿýÿûÿþÿûÿýÿÿÿÿÿþÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿþÿþÿýÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿýÿüÿÿÿþÿþÿþÿÿÿýÿýÿþÿÿÿýÿûÿþÿÿÿüÿüÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿÿÿÿÿüÿüÿþÿÿÿþÿüÿýÿÿÿþÿýÿýÿþÿÿÿþÿÿÿÿÿýÿýÿþÿýÿûÿüÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿýÿþÿÿÿýÿþÿüÿþÿýÿûÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿüÿýÿýÿÿÿüÿýÿýÿûÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿýÿþÿÿÿþÿþÿýÿúÿûÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿüÿþÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿýÿþÿþÿýÿüÿÿÿÿÿþÿýÿýÿÿÿþÿþÿþÿþÿþÿýÿýÿþÿþÿüÿýÿÿÿþÿüÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿýÿüÿýÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿýÿýÿýÿþÿÿÿýÿÿÿþÿþÿþÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿûÿúÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿÿÿýÿùÿúÿüÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿüÿÿÿÿÿüÿþÿüÿüÿÿÿþÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿÿÿþÿÿÿþÿýÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿûÿûÿûÿúÿüÿþÿýÿüÿþÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿýÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿýÿûÿûÿüÿýÿþÿþÿûÿúÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿýÿýÿýÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿýÿüÿþÿÿÿýÿüÿÿÿÿÿýÿþÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿüÿüÿüÿÿÿÿÿýÿÿÿÿÿþÿþÿþÿýÿûÿþÿÿÿþÿÿÿþÿýÿþÿýÿÿÿþÿÿÿÿÿýÿüÿüÿþÿÿÿýÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿýÿüÿþÿÿÿÿÿýÿüÿûÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿþÿþÿüÿüÿÿÿÿÿþÿþÿþÿÿÿþÿýÿüÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿüÿûÿúÿûÿýÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿýÿýÿþÿþÿÿÿþÿþÿþÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿûÿùÿúÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿýÿüÿÿÿÿÿýÿÿÿþÿþÿþÿÿÿþÿüÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿýÿþÿýÿÿÿÿÿþÿÿÿþÿüÿûÿýÿþÿþÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿþÿÿÿýÿþÿýÿûÿüÿÿÿþÿýÿþÿÿÿþÿýÿþÿþÿüÿþÿýÿÿÿÿÿþÿÿÿþÿÿÿýÿüÿýÿþÿþÿüÿþÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿûÿùÿûÿÿÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿüÿüÿüÿüÿüÿýÿýÿûÿüÿþÿýÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿýÿüÿýÿüÿûÿþÿýÿÿÿþÿþÿþÿýÿüÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿþÿÿÿþÿÿÿüÿýÿýÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿüÿüÿÿÿþÿÿÿÿÿþÿþÿþÿýÿýÿþÿþÿÿÿþÿýÿüÿüÿûÿýÿþÿþÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿüÿüÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿþÿýÿþÿÿÿþÿþÿüÿþÿþÿÿÿÿÿýÿÿÿÿÿüÿýÿÿÿþÿþÿýÿýÿüÿýÿÿÿþÿýÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿüÿûÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿûÿüÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿüÿÿÿþÿÿÿýÿÿÿÿÿÿÿþÿüÿüÿüÿþÿýÿþÿýÿüÿüÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿþÿûÿüÿÿÿÿÿýÿÿÿýÿþÿÿÿÿÿýÿþÿýÿþÿÿÿþÿþÿþÿýÿûÿýÿÿÿþÿÿÿÿÿýÿýÿþÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿÿÿÿÿÿÿýÿüÿþÿþÿþÿþÿþÿýÿúÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿþÿýÿýÿÿÿÿÿýÿÿÿþÿþÿþÿþÿþÿýÿûÿúÿüÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿüÿýÿþÿüÿýÿþÿþÿþÿþÿþÿÿÿüÿüÿÿÿýÿýÿÿÿÿÿþÿüÿûÿûÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿÿÿþÿüÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿýÿþÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿüÿþÿÿÿþÿþÿþÿþÿýÿþÿþÿþÿüÿýÿÿÿþÿÿÿþÿþÿþÿþÿýÿýÿþÿÿÿþÿþÿþÿþÿÿÿýÿýÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿýÿüÿÿÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿþÿþÿÿÿýÿüÿþÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿÿÿýÿýÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿþÿÿÿýÿþÿÿÿýÿýÿüÿûÿþÿÿÿýÿýÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿüÿúÿýÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿþÿþÿþÿýÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿÿÿÿÿýÿÿÿÿÿÿÿýÿýÿýÿÿÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿüÿúÿýÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿüÿûÿþÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿÿÿþÿþÿýÿþÿÿÿýÿüÿÿÿþÿúÿûÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿþÿýÿþÿþÿüÿýÿýÿüÿþÿÿÿÿÿûÿýÿþÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿüÿûÿþÿÿÿÿÿþÿýÿÿÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿûÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿúÿüÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿþÿýÿÿÿÿÿüÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿþÿÿÿÿÿýÿÿÿþÿýÿþÿþÿþÿüÿþÿþÿýÿýÿýÿÿÿýÿýÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿýÿüÿüÿüÿýÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿýÿýÿýÿþÿÿÿÿÿýÿþÿýÿÿÿýÿýÿþÿÿÿýÿþÿÿÿÿÿþÿþÿýÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿþÿþÿýÿüÿýÿÿÿþÿýÿüÿüÿýÿüÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿþÿþÿýÿþÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿÿÿüÿüÿüÿûÿûÿþÿÿÿÿÿÿÿüÿûÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿýÿþÿþÿÿÿýÿüÿþÿþÿÿÿþÿýÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿüÿüÿþÿÿÿþÿüÿûÿýÿÿÿýÿýÿýÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿþÿþÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿÿÿÿÿûÿýÿÿÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿýÿÿÿÿÿþÿýÿüÿûÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿýÿüÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿüÿüÿýÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿüÿüÿüÿÿÿþÿüÿýÿþÿüÿùÿøÿûÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿûÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿûÿþÿýÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿþÿýÿÿÿþÿýÿýÿþÿûÿüÿÿÿýÿþÿÿÿÿÿÿÿüÿüÿÿÿÿÿÿÿýÿûÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿýÿüÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿþÿüÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿþÿûÿüÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿüÿûÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿúÿûÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿþÿÿÿþÿÿÿÿÿþÿýÿüÿýÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿýÿÿÿþÿüÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿüÿüÿüÿþÿüÿþÿþÿýÿúÿüÿÿÿüÿûÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿüÿüÿÿÿýÿûÿûÿüÿýÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿÿÿþÿÿÿþÿüÿþÿþÿüÿüÿüÿýÿýÿþÿþÿþÿþÿþÿýÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿýÿþÿýÿÿÿþÿþÿþÿüÿþÿþÿþÿýÿüÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿýÿþÿýÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿúÿûÿþÿÿÿþÿüÿÿÿÿÿýÿüÿýÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿüÿüÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿýÿÿÿýÿþÿþÿÿÿþÿýÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿýÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿþÿÿÿýÿýÿüÿþÿÿÿÿÿüÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿÿID3  ID3TIT2fullTPE1 the artistTRCK2/3TALB the albumTPOS4/5TDRC2001TCON the genreTBPM6TCMP1TPUB the labelTCOMthe composerTIT1the groupingTENCiTunes v7.6.2USLTthe lyricsCOMMthe commentsTPE2the album artistTXXXREPLAYGAIN_ALBUM_GAIN0.00 dBTXXXREPLAYGAIN_TRACK_GAIN0.00 dBTXXX REPLAYGAIN_ALBUM_PEAK0.000000TXXX REPLAYGAIN_TRACK_PEAK0.000244TXXX;MusicBrainz Album Id9e873859-8aa4-4790-b985-5a953e8ef628UFID;http://musicbrainz.org8b882575-08a5-4452-a7a7-cbb8a1531f9eTXXX<MusicBrainz Artist Id7cf0ea9d-86b9-4dad-ba9e-2355a64899eaTXXXCMusicBrainz Release Track Idc29f3a57-b439-46fd-a2e2-93776b1371e0COMMhengiTunNORM 000003E8 000003E8 000009C4 000009C4 00000000 00000000 00000007 00000007 00000000 00000000beetbox-beets-00724b7/test/rsrc/date.mp30000664000175000017500000003102415253035401017341 0ustar pieterpieterID34TIT2fullTPE1 the artistTRCK2/3TALB the albumTPOS4/5TDRC 1987-03-31TCON the genreUSLTengthe lyricsCOMMhengiTunNORM 80000000 00000000 00000000 00000000 00000224 00000000 00000008 00000000 000003AC 00000000TCMP1TENCiTunes v7.6.2COMMengthe commentsTBPM6COMMengiTunPGAP0TIT1the groupingCOMMengiTunSMPB 00000000 00000210 00000A2C 000000000000AC44 00000000 000021AC 00000000 00000000 00000000 00000000 00000000 00000000TPE2the album artistTCOMthe composerÿû`À F=íÉ‘A#ô‰¹ÿÿÿÿF0ÃßÿC ÿ_ùïÿÿÿÿóÏ£)çÚa”2ùŠz<‚žyõ=xù=O `ÐÊÇ�  ¥à�Æyé>`øÜá ÐÀXè" z)ãBœ"À$)‚ �A„ ÿÿÿÿÿøÿ×?ÿûÿÿÿÿþ¾Ývb£×B�¬¦ ³4Àã°²+¸µÂ¤Ír¹Á�ÔR°Ä%;�îR£Q[ÿÿÿïÖÜîÿ³¾Ú7UW6dTUT!ub8´Çø çèx?ñ.Ì€ˆˆˆˆ�ÿÚÚ¢³<ŒaeŸDY/ÿÿÿ½ÿPœ¼·$D¬(躡ïPŒi§ÿû`À€Š9à… éâH#4•¸‹RÒAbÉuÏ&Ž ü:=ÄÝL´2!Ô¶#9îŽÔ#"5¿ÿÿÿú­ÿfE$ìȉ,ª1HËez²1’ª!ĨR ˜‰Ì§)¢((â¢,Êc°š)ÄÜX¢¬,qE„T9N@øˆtÿÿÒþ÷ÿ?ÿû`À ò= mÁ¸È#t�¸¿ÿÿóËäܯðÉ÷IN¡æiÞÿ{ÞžYg§S—ÜëdE/'ÿÿÿÿÿÿÿçþ§Ì¸g Wëï&%ÍirÄDuñ6.ÝítÜ‘mtP&ê,Ž�«¢’Duhâb¨D›ÀN±ÿÿÿÿÿý`Zÿý{ÿÿÿÿÿçÌímÞó¥/Þj¾GH„<&ñÎC¥ÿü„žl÷ÿÿÿÿÿÿÿýþÿçJÎÉP��1•¥I’òÔä»ò9£3³ZHFÊ;ŽÔr/viƒÃ�1  Ü‰…£2‡ ìÁ�ÿÿÿÿÿÖõÿþyÿ?ÿÿùz\¨Û+dDΪ�1ˆÆckTIw˜ÿûbÀ æ% „MɬH#t‰¸™¨…¶R²¶Í´öÿÿÿÿdÝꓳÐ÷1êr© ÊϳîÒ»³lÖ• lΆmC‘Uê÷c,ì$(tÈ4BKÿÿÿÿÿëåý²ëZSÿÿÿÿü¹QRÅ­ÝŒ‡>³Ìl®®è§1Œ¨ˆËf:V¨m&¾åDGB;?ÿÿÿÿÿù­RÌé+ƒ9‡}•+ϳ+±ÍUÐèÊbPSú;1Œ%Ü; Š…R•Ìwt”€Î9Bÿÿÿÿþ¶ƒÿëÿ•ÿÿÿÿäìúRwó5�lª„s>ʸõ#ÌäºuFlëÐêɕћÿÿÿÚÿ³«ÔªFJȪyŒEus–ÿû`À" ? „­Á¬Æ#t•¹a2ft*3άVwVl̸â•êc�@@Ç‚o2ÇåQÇ;> ¢£€?ÿÿõ�sÿÿÿÿÿü»µ®å:=¨îïv:ºº•VB/Îlêèö-ÊZ$Û™5OÿÿÿþÍ'*MD£�'» È.–z¹›S«”ÌêW!„Ça溡Z!3#NǞ#!ƒ¢âcH5VA¸ò¨`†`±�óõùþ¿ÿÿÿÿ®•g;RWT�ÙUÕ½ÔÝQeÑÑTľÎB%OÿÿÿõùÑgêÕ9F F‘�T‡j9"Î(cJb#!Ç�xˆÕ3³ ªEÿû`À, Ú= „­É¯È#4‰¸vcœqL8áaàÊPq¢�Ñ2$48ÿÿÿÿþÖ¯uÿºÿÿÿÿÿ?£‘Ý”„5›Rl›ogGÐŒªöi7ºÕŽ·ìKwÿÿÿÿÿÚÒ"1Ý_™Ü§8¤T„Dg�ä;YƒœFä%PìÆ \ÈäRŠF €‚äS3: ÁÈQBªà•Ü(ÿÿÿÿþÍ�—ÿ/ü¡ßŸõÿÿÿo‘œíbnYØz(‰‘ëu×J:ä·Id£ïZÐÔÙÿÿÿÿÿþŸJ'»Jƒ Ff®ï©Ne+ È 8ä*&*†q2 0�Ì AŠAD…0’�Q!2ª”¥A§aQEÿû`À6€ ¶A „­Á¬E£t�¹0ÿÿÿý°/ó׿ü¿ÿÿÿÿò]s¹œÐô… 仪Dþ9FzÓ¦[7‘t¥+M¹2ä³ÿÿÿÿÿÿÿéÿ9æÓ*FE‘D‰»ë2³×r™9“Ò·I­|¼UèÊã±Áz°spÂ+† JÛØ8ÿÿÿÿþ��©ü¼ògRfÒÏåÿÿýþ•$íc1üý§º!Yz:d÷#ê×*º%Pú?{¯ÿÿÿÿÿèɦ·5\ÎR£¾ì‚ŠTv{˜Ä$A™ RkÑi†ˆ!£±ÅÊ�Ö(|¨rˆ˜pðé¢î<ÂÁÀ+)�h0À5�"ü¿ÿÿÿÿÿdîÿûbÀBVA „­ÁÄÇ£4•¹�F±:¼Û>yê­)Ý�ì¬åºQò²+7cfTÿÿÿëÙ[óÉW£•hr¿ÿÿÿÿ�iO‰�&�׊aÒ¶§ö’ѺkL“ÔW0÷?ÜpµpÝÿÿÿÿÿÿÿ1ÿ×ýúÚuz÷¤sò8ë›~9�çˆ^;Ž’˜…ìar:¦hZ—Ro|†AwÚÖìXòo®Ü**>@Ö0ÿÿÿÿÿëËWuûJ�FÑYìîåˆòYÙræ\ˆîjí»*"±Hßÿÿÿÿ~î‰m¨—g*:˜…+"ofi•ÞÂ#E� �¨²)JçWACê,$aqÊÇ)„€p1Œ"Pè‘ÅH‡(Ñ¡`8�ÿûbÀo€5 … ɽH"Ì•¸3èòÿ¯ÿÿÿÖ×Ýzè¼ì×»Èr/È¢ Ê®”d£3Ñ—yN¤qÿÿÿ÷ä{"Zåu#ÌeR ¸ñŽÄsî®e-ESi‘�pÕ( ›0“�„bŽ3‡Àãs�†�yNEr”ÓŠˆ¨€� ŒÀÿÿÿÿÿí�yïÿéßÿÿÿýz.¥1,o5ä+9·Ežuvf±Îõ¹v}ÈÈ–NÿÿÿÿDû}l³µ+3UTŠCo¼¥>%èOyS!�XŒ‡‘Æi;�\ê8#)Ń:‰cÅ•Êt(P‘À?ÿÿÿÒÿùÿóÿÿÿÿù´š÷fÿû`Àx 9 ­Ù¤G£t‰¹b$„vºftgdû©kU-™œèƤÆVäfÛÿÿÿÿìŸêR>Ó­ÕK5(i5; Îñ“•ÑŠwiÇ*¹ˆ¤"âŠ*.*1â¦c´x´çRH@“ˆ#•bÀÿÿÿö@¿ÿ-»<ŽÄjµ=]ÖÓTª¤®Æ96Kä<îäsn³¼ó—ÿÿÿýv"Ñõ{Ñ]LëgR�g©ªF5ŽFuõZÇQ3�QÓ ‡Ç°›”a‡¨Ô ˜µÌ.tP‰GQCå<ÊÿÿÿÿÖþ]ÿþ«¯ÿÿÿþÞˆy‘žr3ÚÛg§Ÿ¤m4U++!d“Ö¶_J´Í{ÿû`Àƒ nA „­ÁªG£4¹ÿÿÿÿÿÿÿÿöù7ÈqyiHsC0¤Er_?* –gÐNP�‰îF¸v#UCªˆ9ŽB!* jè�A‡1Y(0ÿÿÿÿý`_óòþ_ÿÿÿÿüßíÑžïzJ_¹K&´išôE3Šeu!&>ˆˆþFÿÿÿÿéÌý<ˆs±Q#•ÞcÚï39’Àœ“Ùœ[%ÜÑÝÄÇ8s¸Îd†; áXä …C0­ƒÿùZõº�Výi ­b¹*ªOf3U§,ÍD=®E%^ÝËÿÿÿÿóHêí³=Uή¯­]�™žØâ®ª9ÕŒfd#9ÿû`À� òA „mÁžÈ#t‰¸Ñ�Ô�¤C»Tˆpø…Å”HƒbÈ s‘� E,*Qÿÿÿÿÿý`9oËêkÿýýÿÿÿÎë"åE§KQîÖÝ�Jî·<†aG TGȪW›F}]iÿÿÿÿêÞªú#f«¢Ì¨ÅUTH̵Eç̪·;f¤€ÜâÀÙÑÕN]Dœr¬¨qNÈaÝ(ÿÿÿþ²ûçþ}~_]ÿÿëïôìÌÇûèw.šQÞrØÌÌäb-lzèÒÒšÿÿÿÿßé­ÝíSUÐæg«DL†îB�ÓœxÝ� ¶QE§™ˆc±îD €Ñ3‡PƒÃ¡ÿûbÀœ 2A €­Á²H#4‰¸$)Ÿ1Qd‚ £ýÿçÿÿÿÿýÖþ—tÍT!˜¦ÈwS5îêëfº�ÐÅ*”�lý؈ŠßÿÿÿÿôºµYÊÊKžÓÊÄB²¢�Ïvj±•QXÌB *”a”£¤q3”Á7 áº¡b±Îƒ!¬k **�6Hÿÿÿÿ¶ü¿¿Ëå_ÿòùß%é,«¿uÜöeæBÊìöJ¹Mwº®í­]Õr«7ÿÿÿû¢Ú®d+Tµ#!•ˆDeœ‡æ)Øì…F•®q`³�QËÊ·K ‡!:ÁÎÂÃ�ur‹C˜®àÿÿÿÿú@¾_âüÿû`À©€ ž; „­ÉÁG#4•¹¯ÿÿÿÿçïÿ%2ó¥xzžõËa©—ÝßÈͶMŸšÃ™);þe­Ûÿÿÿÿÿÿÿÿù~~KrS¬[uvzŸzYq¢ñ òlQ�wÑß#}¨\‰jZ |‹T �¸Ä!ÌéÀÀàÿÿÿÿÿ�Ÿž Øç —Ne9Ÿÿÿç eR!áçÖVê¢õœ}!wÂOí3UUÚZWU>ÑÿÜWÿÿÿÿÿÿÿÿ?íñó÷+kLÖÃùŽ*Øëk‘s*—gJ�4`ž¹EÆÇviF"‡$˜z©†9‚XõÂa�Ë”9pèP·XT]Çÿÿÿÿÿc`qîyÿû`À²€ .A „MÁ­G£t�¹‰#±’¿%¾§ÿþY¸tûîú㙬ꙉy¥˜†ýwŠõÚ©¦÷ÞÒ¥©S»éºæÿÿÿÿÿÿÿþÿ¿ÿû¿Ž¹šk¯«YO›­²<6<’±…&TÉ눢Æ!wB±E2ˆ ¸ö³J‡4\V…K1`°’ކ6Ëq1Š@ÿÿÿÿý±ƒÍ#˜Wå¿Ì«ÿÿÿý:*\Ȫuo™��H(έb+JB{1¨¦î·±•jjÿÿÿþ�7¥®·tT2+9#ÝÖ<–ºœÈ©*­ ayŒQ1§3•Ú&=¥B�:``ë‘‚¢§Š ‰Zpð[JQÿû`ÀÀŠA … ÂÈ"´¡¸ €k?ýþ½ÿÿÿÿÿþÕdR•¨É¿WDJ2oR›±ÎÓêUd©Šf3¦Óo5ŸÿÿÿÿòKk­Ê„y™bêìêt3–S’È5‹Ž «�,† 1 áòŽr�JâŠ0¢„#(@Xêè$,�âŠ�8Š4xD*…„ÿÿÿÿÿ’Ëäû×ÿÿÿÿûνey5v}úº*±K÷U2‘ÖgR™–tK"µoEÿÿÿÿÿéîíLÊŒE:2+Ù’}Hî8†fc ‹³)†ÅÌîìBˆaÇds¸“!…„XPr˜xñÊ,Š($0<*5 †4lüÿû`À³€²A „­ÁÛH"ô•¸Ö|ÿÿÿÿÿÿôM‘Û[VÛ²NI”¬ÚÖçbk3›ß¢ªÕ‘Z~¿ÿÿÿõ¡j‡»µ¶g*•Ø”ssB«¥r”¬QGª‰ ”„)å1˜0‚ädÆw<)]Ì($aE8pj‡ÐhÀ³˜À¢¦‰€ÿÿÿÿþ��ßüÿF—=ÆÚþ¿ÿùå®›±÷õÌk*"§f5§¢*YÕC^bºê§»LÜÕ²ÿÿÿÿÿëî‰wcª¦UÎ<Ê;0Ô=QÖ«žŽ¤�:³ó¿ÿÿÿÏé¹&q…+T©µ'ÙTU•ŒgeR á‡B32)—ýž·D|ïÿÿÿÿÓ]«Mɺ+YŒ[Ö¦0Ò)ÊbŽ¥Ž5EQ„ÄEa!˜\h˜AÂ!ذ ³BÃîg À(ñá‚ÂC &P 8|DV&Qÿÿÿÿÿû`À´€ÂA „­Á×Ç£4•¹ÿéä^¤–ú,‹ÿŸÿÿžÒ÷f»‘×d[Òº½ V¹Lës ws)P§z^¬t252]koÿÿÿï§£÷]»ÍÊS2•gsƙٞDkaœÔ9�Ç#˜Â"%F âƒDL*£¢ (B" ‡XÂŽAìb¼>ÿÿÿÿÿ±…åþY//ÿÿÿüæ©J$î”Y?RºÑôVT}ÞŠrQKjßZmu}vÿÿÿþ«ëzttz%¦TS•1ä#ÌÆ½�j=‘Òª”ªQ!0c ÓH,¢å £ÄÄÊ,¡Ñw‡È 8ç1Ðå†0¸ÐÛ ÃjÐöÿûbÀ¶€A ­ÑÙÈ"ô•¸}s—ÿþ¿ÿÿÄ@÷:XÈ®M*¨Cc¹§r”ü­#çDQz­ªý§µ)ÿÿÿÿýþ–ÑNbç›-LQl„0׳ )�Ük ;˜Â,5ܣŃ‹;"Š 8ЦA¨$ÁÑqÆ�\M…EAB@Áç( *ÿÿÿþ��ÿ-ã4Ñ—pþRÿÿÿ³¢îVlìU·K&öu+<Ï™‡tLììv3¡ŠÔ³I{×ÿÿÿÿúûû•YÑ ¥*«“êçªîR†Ð<Ž=ÇÔLU…aÅqáL (sˆ”ñ¨§D4P€È�‚Ä !˜€8ÿÿÿÿÿû`À·€’A „­ÁñÈ"´•¸ÿìŒ w"šçÏ’–«ÿÿþMÿÇýwóó¯÷Üu]fFÌÕH÷SR‰õô±×K¯×ÿÿÿÿÿÿÿÿÿÏw§qóßLò°»O¥O3r²1GÔ­mÍ»±å;=šSÊ8y£2lÏ#•0ÑÄÃHˆpò �¢¥�% « €ÿÿÿÿÿ²ŸÏ_åËzÿÿÿþþŠŒ÷Z2>ô±• ŒÌ]ªC\�È„VGGuyÕ(Êr¢J´ÿÿÿÿû[BUÝŸaj«ö£[‹Õ™HŠèãLRˆ˜«yŒ‡œ¬C%Üq]Qbì->A!Y�â†`£1\Xâ@`Ò y?ÿû`À·6A „­ÁâÈ"ô¡¸—#ÿÿÿÿÊ­ä&ʪË�ÕèêÊ}V¤1Ö³Fnn¹:û[¯ÿÿÿëmjÌës¡ÒÕF!ŠbŠê®Æ)˜†‹‚*‘LŒcˆ°�j¡¬*‰¢ï0p¥>$av!œXè4DHÁÁ5‡ÅĨU(p@1@ÿÿÿþ­ƒüŒÿ¥ÔËïëÿÿÿ7êˆìµR!Ÿ#£µŠè¨~ܦf5æfb1ÞŽÝS"ÛÿÿÿþßèÍiš£P®vJÖ®d1qèq”2ÚÈ0:Å+‘Tƒ6aÂbEl?2‡DD…‡‡\M"B £¢† ”Ácˆ4\6à ÿû`Àµ€.A „­ÁçÈ"´•¸´ý¹~öÿÿÿþT«Û"£—ÜÇž—ÑsÙÑhê®DÎmYd½îdSnÛÿÿÿÿéí¾­:ª3š§š•c%®5HQU<§!ÅEHcDH@8â(‡E`=‡(¹Ã§qR¸²:$&<(j¹‹ÆŠ¸  ˆhˆØ6­ƒóæ¿ÿÿÿÿ#í%)sMªØí1ærÚì·IUkwG‘rîGtTe÷Ñ—ÿÿÿÿÞÕêÛ++Jζ%ƱÞÈÄÌ<‹;‘XÇ8qˆ‚:‹ Aa6qe- @ÊAA¦`‘Dˆa"ÄÆĘ„@ð™”:?ÿÿÿÿý$ÿû`À·€A „­ÁïÈ"´•¸/þN_¬™ôëÿÿä ÷Gõ>¾J¥Ó:²�—G4¸±Q(„tC\î{+©•®gOÿÿÿÿ쮕½Ôˆ³!O<®ë!¨Žd,ŠæR1>‚%f0°¬@ê>qâ¡ô (¨˜åœ4ÖQ!0ø€ºX‚eQC€ÿÿÿÿÿÒäþgì?ÿÿÿÿÿ-‘œ¦ŽI"*ÌD£™•̧Y§In–jH~­’Vkg»T®Š¬‹ÿÿÿÿ•úÑÌŽäRËÕ®¬–K¦í[ÝF"Ψpá®ås ƒ”<îƒáC‡A r$ò 0ˆ×R‹ŽÌWˆ€ÿÿÿÿÛÿÿûbÀµ^A ­ÁéÇâô•¸½ÿÿß›ÿÿü¿->ùŞó/ß&@ºÒzšºË)¢Ô-^Ÿð¼Ž½Ïmûÿÿÿÿÿÿÿÿå‘ßæe ·îV›E‚˜6��Þõ$4C¹»¼­dPÀŽŠ$B¬ŽAÅ£E "£,†8SW©9 € €`5‘çÿËækúëÿÿòÿZšçTC£ú^5Ýõ‘œ¨bT©‘Üz-®–™=¤½ŸÿÿÿýiCž”èËB)©au”‚o,ÑÈ8‡c‡ ""@”AÐD¥*<:*‡ °x:@ùDEEH8:.Œ…Ї†ÿÿÿÿ¶ü¿ùëïÿÿÿÿ©ÿÿ–ŽÍ­îGH¢’°»NÞ±™ÄW%²zÕóØøDo“eÞÿÿÿÿÿÿÿþ_ü?)¹leyX†¿ç)ΜzR̈Ÿ"]Ë•L´'dxÈÐtS 3j±Û é àÿÿÿÿÿÀ~˜dsÿû`À½€>A … ÂH"´•¸æ½ ÿ#ÿÿÿ˲µÐÕc0‰&V‰ZâBÅrÌdpëFEyFˆm ¥*³¬Î¾ë×ÿÿÿÿÿ¿¿mYÊŠVÊÆ}LêÆ+>j=‚¨,å-*UcÅB²=� QSÎPèÑÎ"ÊY˜H  ÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿ¯ÿý~Æ(`JEª*!ÙÙÊbª”Vs ` �#³±Š©ÿ³”ÁB(ÿû`À³€ n? „mÁÑF¢ô•¹ÿûbÀ»€&@ÞMÀ[Àÿû`Àÿ€ÞÀbeetbox-beets-00724b7/test/rsrc/partial.m4a0000664000175000017500000001334615253035401020051 0ustar pieterpieter ftypM4A M4A mp42isom ŠmoovlmvhdÄLé_ÄLï ¬D¸@�trak\tkhdÄLé_ÄLï ¸@mdia mdhdÄLé_ÄLï ¬D¸UÄ"hdlrsounÓminfsmhd$dinfdref url —stblgstsdWmp4a¬D3esds€€€"€€€@xú€€€€€€stts.(stscÌstsz.22""'-+1/+&0''&%)(-,*).)(*%)-4&6.*,$,3/'& stcoÆé •udta �meta"hdlrmdirappl°ˆilst©namdatapartialcpildatapgapdatatmpodata6©too.dataiTunes v7.6.2, QuickTime 7.4.5¼----meancom.apple.iTunesnameiTunSMPB„data 00000000 00000840 0000037C 000000000000AC44 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000¢----meancom.apple.iTunesnameiTunNORMjdata 00000000 00000000 00000000 00000000 00000228 00000000 00000008 00000000 00000187 00000000"©ARTdatathe artist!©albdatathe album trkndatadiskdata×freefree(mdatЃì\«11;Ä<Àøƒ¤4„ `I�fàe—^àï�P0#Ü·›�Áb˜Ä»VOØÙ(*¾J€q8òƒ„q©-@>Ťè[-3þ!‹rtg¼¼(ι¶q]b¥¸úƒÄPEÙ€€ ª°DãÙ‘>JUl3ËA$Ö)i)ƒÀúƒÄA#�€+:3ï`Xa¶™˜ÉùQ;«À±˜ˆèàöƒ¢" „Î Ž× óf{q wZ“Ä 3z¿f#)NÙq'øƒ¢" „kËr½ÙÖ£ g�§ý'”ê )y*¦˜Úö»,°Îµx¡úƒ¢" „r †BXVFìì7nhϦNž|z%ôe0Ue®«Œ œöƒ‚B„_`9åo¢ðJ­Dz0¯)òøáÛ1F8‘ú·åÉ>7t·#‹Uàøƒ¤4#ŒXÛõÞ™¾áàÒ`¸Ž‚Þ×xT†aGˆ~fäHv<ý¶ÁÀúƒÄ`? &ˆ×63Дl:äGàë’ 莵š„ÇÓëåN‚àúƒ¢R#Aש9Ï<³ÔiÇ%Öøê¦—µŠÍÎê®yfžÎôƒ‚T„ `®!�I}uhnV$?‹+ä¡(Z«„Á�¡Üta¥Vi±+±l‰8úƒÄ3#P�0¼ñ•T`’3¹èžÓ#?}¥ÕõÚ»ìÔ‹€úƒ¤Q#Hl`µˆÁ½¥ËK§)Q)E‚ñõ>O²Âô¯SÔ¦úƒÆ"#P ÛdpËŸ¿Û2é­~sÛÈÓï�'Pîì=Í&ü!úƒÄPG<Ž0NÝÍ�Eø™_ƒõ'1…:õ˜‹å\øƒ¢ ˆ,l ƒq¼Ôº<�¬>èðÍ&ïÞ¦J3}•]dQ€€8úƒ¢`F  8I+–¶:aá–;0¥Ç>m>;ßM¾íÛ�Ÿ× ¥/gøƒ¤p>€ÞbSci›”¤L z:~H�5ƒM3©'°A+è&„f ‡Ö(pöƒ‚0!dÀ¢’¯:%¢C°9B³î+]þ3Z†¹ècJr†Â¶�öƒ¤`E€�a,]µ)\BiwÈ,yç@úD¸ù�ü'ħ¥¨Üøƒ¢ ˆÐÀ€0qóà=bžmBÅAwùH°×! šDSª� 8öƒ‚5 !`Â4†§å^ñíª^:$9µÏ…gs`M%…ÊZZtª^U£Y(o€úƒ¢"ˆ¤09œ’#NÑ·#̬zÚW›;t A-1dyß”3¤^ àúƒ¢" "ìFâwì¼ú„,µ¸rŠþ¬js%”ŸÒísÙfžep=¼øƒ¤`G €@ÀãÒ5?à¼`•Ø�ÉÍM²ÈöÆýYB^×;C€øƒ¢`BÈ ÆãiRø—‡iéŽ6ˆ0 9ü¾åÓvë…(ÜÿÿGYJ´…=˜¢oçlÇWøƒ¤3 BÐ3ÜQhLÖÆ$/ê‡b<÷~³µ8ëûÛΚS�­n*jõXeÅ×7’#àôƒ‚"(„@Ø Ad¨*Â`óÙ'ሬÁ®co·>Vûça &µ% øƒ¤`F‚ ¢±äßxã}¸<ëÊüfP[2ÚqXä.Š'Iµpúƒ¢" „¤*ÓØšÖ'êŠÇÉR™z[oÝÓ¬ía‚„¾”XÇS2p'ÀøƒÆ2! éZðÞx²µ¾ùìú$©¿Vn´%j(óVÀöƒ¤`F‚�€öŽ�F†@›c}}ðCÂ2>Û<ÆçO5£!¹QÞ/grD�ðúƒ¤aBàô‡2‰´S(^®Z�dð{¦P�¤Ÿ~‰ÙÛ˜¦‘6 Sºœöƒ¢ „,`¼-1wNÞAÀÍ”XPKh¡wKÛ#0R¬Y±X�-Àøƒ¢`E� "ÅImq¤>w¢È1s5{!ÁXº[¯/æÛ?ÓG�¥xøƒ¢2"%€Xä  aÔž®ŽæÏû©ÆÏç¿÷º�r¯˜LaÀƒì\ªRi"?pƒì\¬ „ô@À\beetbox-beets-00724b7/test/rsrc/lyrics/0000775000175000017500000000000015253035401017310 5ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/lyrics/tekstowopl/0000775000175000017500000000000015253035401021523 5ustar pieterpieter././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootbeetbox-beets-00724b7/test/rsrc/lyrics/tekstowopl/piosenkabeethovenbeethovenpianosonata17tempestthe3rdmovement.txtbeetbox-beets-00724b7/test/rsrc/lyrics/tekstowopl/piosenkabeethovenbeethovenpianosonata17tempestthe30000775000175000017500000025762515253035401033676 0ustar pieterpieter Beethoven - Beethoven Piano Sonata 17 Tempest The 3rd Movement - na Tekstowo.pl
2 170 744 tekstów, 20 217 poszukiwanych i 502 oczekujących

Beethoven - Beethoven Piano Sonata 17 Tempest The 3rd Movement

Utwór dodał(a): anmar09
Utwór instrumentalny Ten utwór ma słowa? Dodaj tekst
Teledysk dodał(a): anmar09 Edytuj teledysk
Ścieżka dźwiękowa:

Pokojówka

Komentarze (0):

2 170 744 tekstów, 20 217 poszukiwanych i 502 oczekujących

Największy serwis z tekstami piosenek w Polsce. Każdy może znaleźć u nas teksty piosenek, teledyski oraz tłumaczenia swoich ulubionych utworów.
Zachęcamy wszystkich użytkowników do dodawania nowych tekstów, tłumaczeń i teledysków!


Reklama | Kontakt | FAQ Polityka prywatności
beetbox-beets-00724b7/test/rsrc/lyrics/tekstowopl/piosenka24kgoldncityofangels1.txt0000775000175000017500000027444315253035401030154 0ustar pieterpieter 24kGoldn - City Of Angels - tekst i tłumaczenie piosenki na Tekstowo.pl
2 170 744 tekstów, 20 217 poszukiwanych i 501 oczekujących

24kGoldn - City Of Angels

Tekst dodał(a): asdfghjklmnop Edytuj tekst
Tłumaczenie dodał(a): tapcapslock Edytuj tłumaczenie
Teledysk dodał(a): olcia_197 Edytuj teledysk

Tekst piosenki:

[Chorus]
I sold my soul to the devil for designer
They said, "Go to hell," but I told 'em I don’t wanna
If you know me well, then you know that I ain't goin'
’Cause I don't wanna, I don't wanna
I don't wanna die young
The city of angels where I have my fun
Don't wanna die young
When I'm gone, remember all I've done-one

[Verse]
We've had our fun-un
But now I’m done-one
’Cause you crazy (Yeah), I can't take it (No)
Just wanted to see you naked
Heard time like money, can’t waste it
What's the price of fame? 'Cause I can taste it
So I'm chasin’ (Yeah), and I'm facin'
A little Hennessy, it might be good for me

[Chorus]
I sold my soul to the devil for designer
They said, "Go to hell," but I told 'em I don't wanna
If you know me well, then you know that I ain't goin'
'Cause I don't wanna, I don't wanna
I don't wanna die young
The city of angels where I have my fun
Don't wanna die young
When I'm gone, remember all I've done-one
Dodaj interpretację do tego tekstu »

 

Historia edycji tekstu

Tłumaczenie:

Pokaż tłumaczenie
[Chór]
Sprzedałem duszę diabłu za projektanta
Powiedzieli „Idź do piekła�, ale powiedziałem im, że nie chcę
Jeśli dobrze mnie znasz, to wiesz, że nie idę
Bo nie chcÄ™, nie chcÄ™
Nie chcę umrzeć młodo
Miasto aniołów, w którym dobrze się bawię
Nie chcę umrzeć młodo
Kiedy odejdę, pamiętaj wszystko, co zrobiłem

[Werset]
Mieliśmy naszą zabawę
Ale teraz skończyłem
Bo jesteś szalony (Tak), nie mogę tego znieść (Nie)
Chciałem tylko zobaczyć cię nago
Słyszałem czas jak pieniądze, nie można go marnować
Jaka jest cena sławy? Bo mogę to posmakować
Więc chasin '(Yeah) i patrzę
Trochę Hennessy, może być dla mnie dobre

[Chór]
Sprzedałem duszę diabłu za projektanta
Powiedzieli „Idź do piekła�, ale powiedziałem im, że nie chcę
Jeśli dobrze mnie znasz, to wiesz, że nie idę
Bo nie chcÄ™, nie chcÄ™
Nie chcę umrzeć młodo
Miasto aniołów, w którym dobrze się bawię
Nie chcę umrzeć młodo
Kiedy odejdę, pamiętaj wszystko, co zrobiłem

 

Historia edycji tłumaczenia
Rok wydania:

2019

Edytuj metrykÄ™
Płyty:

Dropped Outta College

Komentarze (0):

2 170 744 tekstów, 20 217 poszukiwanych i 501 oczekujących

Największy serwis z tekstami piosenek w Polsce. Każdy może znaleźć u nas teksty piosenek, teledyski oraz tłumaczenia swoich ulubionych utworów.
Zachęcamy wszystkich użytkowników do dodawania nowych tekstów, tłumaczeń i teledysków!


Reklama | Kontakt | FAQ Polityka prywatności
beetbox-beets-00724b7/test/rsrc/lyrics/tekstowopl/piosenkabaileybiggerblackeyedsusan.txt0000775000175000017500000027127615253035401031403 0ustar pieterpieter Bailey Bigger - Black Eyed Susan - tekst i tłumaczenie piosenki na Tekstowo.pl
2 170 745 tekstów, 20 217 poszukiwanych i 502 oczekujących

Bailey Bigger - Black Eyed Susan

Tekst dodał(a): Adelle Edytuj tekst
Tłumaczenie dodał(a): brak Dodaj tłumaczenie
Teledysk dodał(a): Adelle Edytuj teledysk

Tekst piosenki:

Black eyed Susan
Sun shines in your veins
If the clouds are moving
Never hear her complain
Yeah, black eyed Susan
Just waiting on a drop of rain

Black eyed Susan
Stands true and tall
If the storms are brewing
She ain't worried at all
Yeah, black eyed Susan
Just waiting on a drop to fall

Everyone calls her the sunflower
And no one knows her name
She's a little girl on the side of the road
Waiting on a drop of rain
Rain
Rain

Black eyed Susan
Ain't it just a shame?
'Cause now you're losing
All your petals in a vase
In a vase
She got picked and I never really knew her name
Everyone calls her the sunflower
And no one knows her name
She's a little girl on the side of the road
Waiting on a drop of rain
Rain
Rain
Yeah, she got picked and I never really knew her name
Dodaj interpretację do tego tekstu »

 

Historia edycji tekstu

Tłumaczenie:

Niestety nikt nie dodał jeszcze tłumaczenia tego utworu.

Dodaj tłumaczenie lub wyślij prośbę o tłumaczenie

 

Autor:

(brak)

Edytuj metrykÄ™

Komentarze (0):

2 170 745 tekstów, 20 217 poszukiwanych i 502 oczekujących

Największy serwis z tekstami piosenek w Polsce. Każdy może znaleźć u nas teksty piosenek, teledyski oraz tłumaczenia swoich ulubionych utworów.
Zachęcamy wszystkich użytkowników do dodawania nowych tekstów, tłumaczeń i teledysków!


Reklama | Kontakt | FAQ Polityka prywatności
beetbox-beets-00724b7/test/rsrc/lyrics/geniuscom/0000775000175000017500000000000015253035401021301 5ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/lyrics/geniuscom/sample.txt0000664000175000017500000002420715253035401023330 0ustar pieterpieter SAMPLE – SONG Lyrics | g-example Lyrics
#

SONG

SAMPLE

SONG Lyrics

!!!! MISSING LYRICS HERE !!!
More on g-example
beetbox-beets-00724b7/test/rsrc/lyrics/geniuscom/2pacalleyezonmelyrics.txt0000664000175000017500000201461515253035401026373 0ustar pieterpieter 2Pac – All Eyez On Me Lyrics | Genius Lyrics

All Eyez On Me Lyrics

[Intro: 2Pac]
Big Syke, 'Nook, Hank, Bogart, Big Sur (yeah)
Y'all know how this shit go (you know)
All eyes on me
Motherfuckin' OG
Roll up in the club and shit, is that right?
All eyes on me
All eyes on me
But you know what?

[Verse 1: 2Pac]
I bet you got it twisted, you don't know who to trust
So many player-hatin' niggas tryna sound like us

Say they ready for the funk, but I don't think they knowin'
Straight to the depths of Hell is where those cowards goin'
Well, are you still down? Nigga, holla when you see me

And let these devils be sorry for the day they finally freed me
I got a caravan of niggas every time we ride
Hittin' motherfuckers up when we pass by
Until I die, live the life of a boss player 'cause even when I'm high
Fuck with me and get crossed later, the futures in my eyes
'cause all I want is cash and things
A five-double-0 Benz, flauntin' flashy rings, uhh
Bitches pursue me like a dream
Been known to disappear before your eyes just like a dope fiend
It seems, my main thing was to be major paid
The game sharper than a motherfuckin' razor blade
Say money bring bitches and bitches bring lies
One nigga's gettin' jealous and motherfuckers died
Depend on me like the first and fifteenth
They might hold me for a second, but these punks won't get me

We got foe niggas and low riders in ski masks
Screamin', "Thug Life!" every time they pass, all eyes on me
[Chorus: 2Pac]
Live the life of a thug nigga until the day I die
Live the life of a boss player (All eyes on me) 'cause even gettin' high
All eyes on me
Live the life of a thug nigga until the day I die
Live the life of a boss player 'cause even gettin' high

[Interlude: Big Syke]
Hey, to my nigga Pac

[Verse 2: Big Syke]
So much trouble in the world, nigga
Can't nobody feel your pain
The world's changin' every day, time's movin' fast
My girl said I need a raise, how long will she last?
I'm caught between my woman and my pistol and my chips
Triple beam, got some smokers on, whistle as I dip
I'm lost in the land with no plan, livin' life flawless
Crime boss, contraband, let me toss this
Mediocres got a lot of nerve, let my bucket swerve
I'm takin' off from the curb
The nervousness neglect make me pack a TEC
Devoted to servin' this Moët and pay checks
Like Akai satellite, nigga, I'm forever ballin'
It ain't right: parasites, triggers, and fleas crawlin'
Sucker, duck and get busted, no emotion
My devotion is handlin' my business, nigga, keep on coastin'
Where you goin', I been there, came back as lonely, homie
Steady flowin' against the grain, niggas still don't know me
It's about the money in this rap shit, this crap shit
It ain't funny, niggas don't even know how to act, shit
What can I do? What can I say? Is there another way?
Blunts and gin all day, 24 parlay
My little homie G, can't you see I'm buster-free?
Niggas can't stand me; all eyes on me
[Chorus: 2Pac]
Live the life of a thug nigga until the day I die
Live the life of a boss player 'cause even gettin' high
All eyes on me
All eyes on me
Live the life of a thug nigga until the day I die
Live the life of a boss player 'cause even gettin' high
All eyes on me

[Verse 3: 2Pac]
The feds is watchin', niggas plottin' to get me
Will I survive? Will I die? Come on, let's picture the possibility
Givin' me charges, lawyers makin' a grip
I told the judge I was raised wrong and that's why I blaze shit
Was hyper as a kid, cold as a teenager
On my mobile, callin' big shots on the scene major
Packin' hundreds in my drawers, fuck the law
Bitches, I fuck with a passion, I'm livin' rough and raw
Catchin' cases at a fast rate, ballin' in the fast lane
Hustle 'til the mornin', never stopped until the cash came
Live my life as a thug nigga until the day I die
Live my life as a boss player, 'cause even gettin' high
These niggas got me tossin' shit
I put the top down, now it's time to floss my shit
Keep your head up, nigga, make these motherfuckers suffer
Up in the Benz, burnin' rubber
The money is mandatory, the hoes is for the stress
This criminal lifestyle, equipped with the bulletproof vest
Make sure your eyes is on the meal ticket
Get your money, motherfucker, let's get rich and we'll kick it
All eyes on me
[Chorus: 2Pac]
Live the life as a thug nigga until the day I die
Live the life as a boss player 'cause even gettin' high
All eyes on me
All eyes on me
Live the life of a thug nigga until the day I die
Live the life of a boss player 'cause even gettin' high
All eyes on me

[Outro: 2Pac]
Pay attention, my niggas! See how that shit go?
Nigga walk up in this motherfucker and it be like, "Bing!"
Cops, bitches, every-motherfuckin'-body

(Live my life as a thug nigga until the day I die)
(Live my life as a boss playa, 'cause even gettin' high)
I got bustas, hoes, and police watchin' a nigga, you know?
(I live my life as a thug nigga until the day I die)
(Livin' life as a boss playa, 'cause even gettin' high)
He he he, it's like what they think
I'm walkin' around with some ki's in my pocket or somethin'
They think I'm goin' back to jail, they really on that dope
(Live my life as a thug nigga until the day I die)
(Live my life as a boss playa)
I know y'all watchin', I know y'all got me in the scopes
(Live my life as a thug nigga until the day I die)
(Live my life as a boss playa, 'cause even gettin' high)
I know y'all know this is Thug Life, baby!
Y'all got me under surveillance, huh?
All eyes on me, but I'm knowin'

How to Format Lyrics:

  • Type out all lyrics, even repeating song parts like the chorus
  • Lyrics should be broken down into individual lines
  • Use section headers above different song parts like [Verse], [Chorus], etc.
  • Use italics (<i>lyric</i>) and bold (<b>lyric</b>) to distinguish between different vocalists in the same song part
  • If you don’t understand a lyric, use [?]

To learn more, check out our transcription guide or visit our transcribers forum

About

Genius Annotation

The title track off of 2Pac’s album All Eyez on Me samples Linda Clifford’s “Never Gonna Stop� (also used for Nas' “Street Dreams,� which was released a few months later in July 1996). Producer Johnny J recalls connecting with 2Pac for this track:

That was the very first track I laid when we got together at Death Row. When he just got out of jail, just got released, two days later he’s like, “‘J’, get to the studio, I’m with Death Row now.� I assumed it was a joke, somebody perpetrating Tupac. I’m like “Hell no – ‘Pac is locked up!� He’s like “J, I’m out� I walk in, 15 minutes into the session, the first beat I put in the drum machine is “All Eyez On Me.� I wasn’t going to show him the track, honestly. I was like, “This track? Nah, it’s not finished. It’s incomplete.� My wife says, “Hey, it’s a dope beat!� So I just pop it in, titles just come right off his fuckin’ head.

This classic gives us an idea of what the media was doing with Pac’s life. At this moment, all eyes in the music world were on him due to the intrigue around his release from prison, signing with the notorious Death Row Records, as well as the 2Pac/Death Row/West Coast vs. Biggie/Bad Boy/East Coast beef.

Q&A

Find answers to frequently asked questions about the song and explore its deeper meaning

What did 2Pac say about "All Eyez On Me"?
Genius Answer

Kendrick on the Impact of Tupacs All Eyez on Me and California Love Video Shoot

“I was 8 yrs old when I first saw you. I couldn’t describe how I felt at that moment. So many emotions. Full of excitement. Full of joy and eagerness. 20 yrs later I understand exactly what that feeling was. INSPIRED,� Lamar wrote (via Pitchfork). “The people that you touched on that small intersection changed lives forever. I told myself I wanted to be a voice for man one day. Whoever knew I was speaking out loud for u to listen. Thank you, K.L.�

As Lamar told Rolling Stone, he was eight years old when he sat atop his father’s shoulder and witnessed Tupac and Dr. Dre film the video for “California Love� at the Compton Swap Meet. “I want to say they were in a white Bentley,� Lamar said. “These motorcycle cops trying to conduct traffic but one almost scraped the car, and Pac stood up on the passenger seat, like, ‘Yo, what the fuck!’ Yelling at the police, just like on his motherfucking songs. He gave us what we wanted.� Lamar would later shoot a scene at that same swap meet for his “King Kunta� music video, a nod to 2Pac.

Credits
Featuring
Producer
Phonographic Copyright â„—
Mixing Engineer
Assistant Engineer
Mastering Engineer
Recorded At
Can-Am Studios (Tarzana, CA)
Release Date
February 13, 1996
View All Eyez On Me samples
Tags
Comments
beetbox-beets-00724b7/test/rsrc/lyrics/geniuscom/Ttngchinchillalyrics.txt0000664000175000017500000056524615253035401026245 0ustar pieterpieter TTNG – Chinchilla Lyrics | Genius Lyrics

🚧  The new song page is now the default experience! We need your help to continue improving contributor features.  🚧

So far we've lost focus
Let's just concentrate on words that could mean everything

On nights like this
We drink ourselves dry
And make promises
Without intention

So fortunate that this was brought up
The last time. As I recall
I can’t hold up your every expectation

On nights like this
We drink ourselves dry
And make promises
Without intention

My God, is this what we’ve become?
Living parodies of love and loss
Can we really be all that lost?

So fortunate that this was brought up
The last time. As I recall
I can’t hold up your every expectation

One moment to another I am restless
Seems making love forever can often risk your heart
And I cannot remember when I was this messed up
In service of another I am beautiful
How to Format Lyrics:
  • Type out all lyrics, even if it’s a chorus that’s repeated throughout the song
  • The Section Header button breaks up song sections. Highlight the text then click the link
  • Use Bold and Italics only to distinguish between different singers in the same verse.
    • E.g. “Verse 1: Kanye West, Jay-Z, Bothâ€�
  • Capitalize each line
  • To move an annotation to different lyrics in the song, use the [...] menu to switch to referent editing mode

About

This song bio is unreviewed
Genius Annotation

This song is about those relationships with a lot of fights and reconciliations. The singer and his couple are aruging/reconciliating, telling themselves everything is going to be better and things will change for good, specially when they get drunk, just to fight and reconciliate over and over again.

Ask us a question about this song
No questions asked yet
Credits
Written By
Stuart Smith
Release Date
October 13, 2008
Tags
Comments
Add a comment
Get the conversation started
Be the first to comment
beetbox-beets-00724b7/test/rsrc/lyrics/examplecom/0000775000175000017500000000000015253035401021442 5ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/lyrics/examplecom/beetssong.txt0000664000175000017500000007034115253035401024201 0ustar pieterpieter John Doe - beets song Lyrics

beets song Lyrics



John Doe beets song lyrics
Lyrics search for Artist - Song:

Back to the: Music Lyrics > John Doe lyrics > beets song lyrics

John Doe
beets song lyrics

Ringtones left icon Send "beets song" Ringtone to your Cell Ringtones right icon

Beets is the media library management system for obsessive music geeks.
The purpose of beets is to get your music collection right once and for all. It catalogs your collection, automatically improving its metadata as it goes. It then provides a suite of tools for manipulating and accessing your music.
Here's an example of beets' brainy tag corrector doing its thing: Because beets is designed as a library, it can do almost anything you can imagine for your music collection. Via plugins, beets becomes a panacea
Ringtones left icon Send "beets song" Ringtone to your Cell Ringtones right icon

Share beets song lyrics

  RATE THIS SONG!

Add to Favorites Lyrics Email to a Friend John Doe - beets song Lyrics
Rating:

Use the following form to post your meaning of this song, rate it, or submit comments about this song.


0
Name:
Comment:
Type maps backwards (spam prevention):


There are no comments for this song yet.
ToneFuse Music

beetbox-beets-00724b7/test/rsrc/archive.7z0000664000175000017500000000453315253035401017713 0ustar pieterpieter7z¼¯'xi¨áZvæ|ãà ËÙ]&”_%7{ØÜ!ïQ4FUþ>Ë筢ߓ:S7ÞºE¨²0)ž~ÁÒÞHNÔFº#ÈH9âüa¢ ù0!µŸƒº vÙo°jÿ�â|~ÄF3å#9|o]{&ÅÓ촹㪼ùRrFFÛ>–†õŶ¯¥ÔÚ>)…në1Sw/釄Ò›" õ4Žu¦rkLÇ[�ˆØ«¹Xbí0àÒ>×��PÃï½Ïf“J;µ+øËUMÛ øl²Y£×;UÊñ±PVdñ¼×r¯�âå¸t„Z HéJeÄÅð�T ÉÊj!µó½|v·çn!uŠgióÕω®ï¸ªÑöh r†?E}cÿ8ªÏìv²:€o-a�ÎȵçV¬³�9½9Ò)o»U`áp×nûè'ùTªI?ù¼*x¾„Þ]4@z×`Dloo¼5´LUg–�Ÿ,.¾ûl‘°–_$�^EV^OZN½©`”=!ë):™�eÙi ·¥C~Du>cŸJUÜeÍ®¦ž¤Ë¹foÞ8V?û—\2“Ò#IK+Ñ6tÕÒç]+ Ée=>‚¥ÖYŠÌíö\@yêYw –Œ 4|#ÜŽ'WqìÜàšü²-ã âs¾"F�þ›RÇ/ˆ*¬Ã†ÒÿßdýÉ—ò¹3“ˆ\ÖY¬èò2Šal×](c¡GÉ/1óW’«6+bdCÜ(¼IÊ˯�ßã!#rMПÆ�Íý̰P66„Äm´e$ç>“Ú1Yr8nH¨·;=õW¨Ë{N'˜ß<8‚ê÷þÓÁ"Z ]æ/ÝéHY™ÌU!þ€gîòˆºgЍ@Ž-CýV(„äñâ¤IN$zÅø,bzŤ.ª_{ˆvŠÀ%—ôwõËpï7¼æÍ„¦Ê¾�,+ÎgÝGv™�;ŽÊÑMó‰ýÀ³zÕ°ë‹U¼•¸¯�9&ƒù·�ÂÚš ¬Â}†œæêÍþ×Üù„'.+éšqk±Nî¯.�J¹L>†m�̉x;g,{óh7I�,[M©"{.¯­Jgì …n}Åo¡Œñ;¹¨yx}˜ÊçÈw÷N &~`¬ÿ–À²ïO$¼‚ñA E*Fv’Ÿ@NŠ[O¶CÙ�ÝÝ ØWRîÅÎüeˆ¾h¢/ÂÜÓt"ЉG$ø_òZ]� Àº!d(<´sõ€ÿ6¨µ†ž”=&GE BÎ ZÑ�eãùµHL¹Ëh]¸KÓÁåMŽD¸ïQÙ�š›O<ÛIËÉ£íñû€áóJ܃ÁŸ�—Šzü’Ý(‹ o ”€#ê¸·Ž–  )#¦3°�e5©¡ûX[}æM†çúWMŽ7µ(`Q«†Ké�™úƒ>�‡pÒO…„¦Ã7/õÔ~Á=£üœ+b-}—nðÉ%‚pÀ9Õ_ý:;ö̆œŸhPcû)‰ì÷p_-ÊYÎ.ã”^I£ábÑ ŸNÂÝ�MµK8Í*æq‘_ÿ(µEaë˱†Š&Flx Gy¬ôŒ#›å—[MÇ¿\'#ezN¿xk–³/è“F Pþ½“.ZÛq�F©+Ñ$ÌŒåÈÅÖƒQF~‰SìÐÍõ!ÖßÕ:ëò�ý�xq5zjѤAœY¤!1}#R®�¹ÃÕOµÂûlkôMŽ"°6¶Íuó-;5§f‡�1<ÕIm?ý×Û£;HQ¥c°ÊÖäÑœØó~—s A/e�=¸¿cÚbo&¹Ê¬ YU¶f¯®¥ÎCí F¥® A‘ûIi:~«0b?Kr!šnU"Õq5…™‚cWâ6"!¦�wAL}Õƒ•T—“�“ø «‰»f¤£– ÿæ�èŸrôÛS*œZyüŽEs¼ôLdÛJiû©1e±:DÌ™EÂEލ•UJðzçCŠ�߬ïÕª48w3oL¯¶æM!6D^Ù+x¡ä �a ÅÁ|HG1Zµ¸Áê .ÔLãu³ÇÁBɪxã²5¤¤V‘oí�Å{ð[1v¶ýÀ €™ëáÕuÓ—ã*Í øæa¤‰•)`íÕÍG¡÷Læa ÅË#%a$šëŒý™³^»¢“ؾÓÂÕ?Á •:dhËÁ……`ÂYª˜:ûˆLEš�½¿y éZ{C×ã58,å2L,3iFÀý£TF(�9Ó‘’†PâN?Òj¿Ì¿Å‘Wb½è µÓÙ±r;òÌõ5åØÏÜ.jJ«Õ¤tÌ šÍêKtà =Yväâ\W\wˆš‚›Ææ g»o‰^ÚaNâ£Íú„yÑÆžõüáS{ª—¾êªÃE#@ŽšÿUʽ­by79\»1–³MT*,3º!8"•ääZVA�\ø³ÏŠ».ÃIØÕ‰2”è23÷ó£òé=@rÁš¨Y‹îµôº«¢ó«N¡=oEÜŽZŒmŸ‡&¼=ºX;ˆB²`ô ÷ŽCY5Œ&øûbËJ,fp?­NÖt“Ç¢|¨1Ó‘âÉOPÞ!ñe-q1ÍüVT7ä ¦p­¿hø®”»XaÏKœ¦·JÈs� RóY�Œ}qL¿áó£ ûï0wÞ“ �$}û÷ 04Ý §st“è:£ü‚ÎYt /ŠÃckAú¾ÞÍE¡Ó\÷Se�Øi‡[�­¼V¹½ÝÙð\¿gÑûÛqØÞÁÕéªôME”•PèBO†|Ei ]Æÿ#3K¿‚îÀ‰ÈpIKDšoØõ‰ç’Q-îHÅ3=0CSà øÿ\xÐ÷[´Ñ ™T¼³kÀj¥È@o�å„GX1­Ôgß ¸3æÓÕ͸rI¸ÿ–ß™Îñ…ÿ· xnÞ@ÿAÿGŒ]�ÎÀç Ìsž€~Ã�¯\RqÑ¥úÆü€s°yFüŒs°À$‡;üäs°ÀAã þ<9Ø?AÖí³©T…€Ý€Œ]nÞ@™ú¾òû‡;Ö0�ÎÆìÿ€9Fü1t€Ò0�ÎÀé¹O@þc­Ï@^vTFhR5•Oø LÉÜÉÿ('ü4¥»øR›KeußãÉÊ ÿU¿�ø|ˆæR´R�¨.²ØŠ„! DRJ…B¡R•)½É!ê‘×'&J(‚ZÄ ‰@¤,¨T3”¤�¸�™DV*ð×ù3’AĨŠS'l‘*SÀÕ�…["(+�‚9¨BPP%1"!A›þNw’#�)‰"I R™.P!ÁS"*”r �I²±(BSÀ ‡À $Çü�òêD«…)ºÀ JSÀ S]r#¿àr'·ü¶xäBSÀïøˆõþ þ ýr!C¿àÓcþÐT;“#À¦Oø ÌÒoø}û’Mÿá‘Ô&wðÒŠ?à'üxåv§ü¾ÿ‚‘pbeetbox-beets-00724b7/test/rsrc/unparseable.wma0000664000175000017500000005616015253035401021022 0ustar pieterpieter0&²uŽfϦ٪bÎl2¡Ü«ŒG©ÏŽäÀ SehÄQ€>ÕÞ±��ÐtÐÊ› € € ôµ¿_.©ÏŽãÀ SebÒÓ«º©ÏŽæÀ Se4êËøÅ¯[wH„gªŒDúLÊ”#D˜”ÑI¡ANEpT3&²uŽfϦ٪bÎl,@¤ÐÒãÒ—ð É^¨PHWM/YearOct 3, 1995‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104$WM/BeatsPerMinute6‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aTRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aWindows Media Audio V8a6&²uŽfϦ٪bÎl2K‚ ]“‹„ç ç“ÿ@ ÓÃÏ6Ó‚}mà ;€¦Jà$´æ“$�Ü$›ì ?'qU1Ù1%¦4©€` -I$ÀIP�c Ô I¨�R„UI10U5R’I‰¸IjR` Ù$Ę@«JTBTÓI¥1,E4” ¦”�Ò’ÒÒ€I:¢„bf¥1&C›°` �³QR@H@1Všˆ`šˆ †€H “:ÓP@¨þ¥�KÌI^o'�»@*@˜7C²@ •ÂL À$¨Ä %©--¦ši!T€H””¿HEPùj�H@&B4ŠJJÁóä"„0Ò•…ý Sƶ°|µALU2”’k?ßí/¨/ß¿¥,B(âýqôŠ1BÒÐ~¶¶š-ÜKlø¿!+t„H¢�„„å8� H¨‰¡h-Ûߥ)B Ûô-P_”PVéCäQný"—év0{eýIBÒÒ�ª¸�V‚i~·ÆüPè6òµA \@ÑÅA KT¿ÚÛëpã¥k‰¿, ñøRѤ ­¿vÙFPµB(âó^®oã§�Íù»yZÀUÁ”P„ã(À\KYFP…»}¿÷o¤ÓM–Ê?_¥ Rýmøâ·> ·× p?,£ŠÝúð´à*à}Æý–­ËKx)~üþ°óyKïÒoéãýÒ±~ìù¼§(ðƒïΚÆó\yïû§ó¬sXß•?´­-ÿµ´[–¨}BÞSJÒ8øÇ‰9ïùå>Á·÷úýqº_ͧ‹õE¾±øÿ'~ú—è·ÑÄ·ÙH¢š_%úiÝM.Ê]ŸÙK°´V²ž+sô~_§`;t㎟ߛü°c[ŸOšã[t-·A¥ ·?ü¿|T>¡ûúBÒÓêr•¥¡”­ñññ-¿ý¦ÞýÙ·[–Çý>ót~¿'A·Ð„%lÓE(?º0çÔñ­ºi )·Ûé¥òßîÞ·C÷ÉnÀ@­å4qºR#)O½k(ZvÏ¿:< ¿ÊhÀT"±Ÿ-­­y¼¥6úr‘Å@[Á*�XÈù­~뫈3Xöü§=ÿtþ¸¿\n�ÇÇ‚WÜi⦊Æ=©(Y�XùºÇ[[¨Œÿ)ýùº?+{ !öt½/¿Khó\võ³ÇO„Q•+yÊ-�ÀU�‚[ucåYò[Ð0òøqà?5€ÿtà”¥Ä\úÀN‚‡Á§`0þ¸2š2•¥†{Qàx6š>ÀT—ô%ù¤º[þðü_y»{ˆ7öáæí�·ñe)Ê_y â × ºØì¦šàâºÆ|NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç§ ç–ÿ@ˆð%,V,XU2¼�ƒ¢ d†´µ°DôZb`°D€« ’ZÒÄ’XªpÍR/¸I… &`c †²X¬ÀH1…$Œ)1´ÌJI,¡•2"MK¢ ˜A2¢B`’*!&©JADÕ€ë$Ši�–„¤‰ E&®‘(hØ+D¤„¥!¤Á$ˆ‰``:–h&FÄ꤈¸l¶¶ ¬Üô�F”a؈…E„–¹‚Cv[0¤á@™�˜˜00Š&¬“‡)EdìEB��MCQ 3P ¾4R EB( ±JKô¿BPPB0è@„„[‘M/Å¥‰ Û¨J€°¤¬Rü¡`ËTþêOT©QcM¼�°–¿-ZZ¥hÒý nÊ-ôñ:\kaúüÖÓùSÇÅæŸ~¿×OóÔ~Íp; yHZÊ ÿÌ¡q!ÒÆ¸8风ßùÓG®/É ¥¯Én‡ïÿkHóHÀ_µ¼ýõpºZ…§ÂÝ”ºSÄŸÏóãüߥm÷xÂiÊ_;t8ˆµn®§òO8‹êÆ}”ñ~¸Ðit²ÞSŸ¿[¬`ÿ`ª¸pD†¸„såBÞP_× P”Ö=Ž·BÕc'(ã�Õcy®'ÕÁ€ÿoè¡ÿp›cóåÁ^vkL£þ_“÷KWQÆ·‚WØ ­ÛŸ×ÁV}F §=ð_×ÞSBÕ4¾ð‚,¥(À~oóÁ*ÓúǬlù-ÜvǾq�NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“¹Œ„çÕ ç–ÿ@“¹Æ_­mšVÿ b†­°&6¢ H7#@&RI($L™&ú»’@(Ó£" h&gQ‡0c "`éì “†2QyJB%,Dš€&`–ŠÈ¦S„ 2Ì@0’i jH”Ã*J ƒ˜1 (‚i¤”  $¢©Ê ÂJa0BJI%�¥­$X €H–„ëD§ � X©³B «-#@Á!¨JoV ]G@Ðc¼«-TËNÉéªÁ³ ±¥†®˜ªI1Q‘¹BJ…� LÁ’…€À$˜„îši¦¥@“JÄ- .ËôŠQB@~„HDBÕ%4ST�(@JIJØ¡…¥�¡òX¿DS+eóä!/È~•ºBÊ”#ö´r¦„QNâ}Jj—ÁÛ¿·­ÛŸÒ‡Ï‘@vxŠ-£ö4>~mÅÛ-SÄùm%J-ëU_qþü)4&»)ZVô‡n´·H~·ùŽ?ÒVŠÚ?'ã(O©@}ú®È»gÏÒx�·ùÛ­ô¬V�húâ yíúâÍþ5¿É¡a€é·þNÚœ!mú+ŸÝ(óKÏ’HÊCëzVÈB?YHâCÿ4û�ôûЏO›¥mb�Ë•½Òïíß´Ž5¤¾OéÄ>SùÛÿ*P¶ÏÉõª°Ï|€©ókvî%¾/αè¡8Í­Sû§\täKùþ‹¥óÝëq|·B7K­WOçÅÄy¾#û}ùùº_£=Ê“üåÿ›Z¥o(·Óo¬zœCœ÷·þøøÖ¸ü#žÿ¾$ÛÖ–ðéóúÓOšÊy¼rŠÆ[Êx‡šûÊi·×QÇû§Í[¸ÿ!ûü¿^t¶{~ø––‡šÏl‚Kupeµù­QNP·ù¦ªÞ%ù¢ŸÎ¸ ¥€NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç ç–ÿ@üð-TÀ×ß½Gé=õ¶4C $š DΠ&I�:MOü`áÄ´€6 ‚FÈuaÌTAc áA@a@-2E@i0–,P I$¤ÔÀh“:I‰-/�B(, áá´¤¥cRL Љ(H©JMDÉi@š‚ÑIQ¬6  Š†KL’™‰‚PL„ÂJRH4Ë@YP 5€" $†ÀÄ iJH`$°fb`liÌC`)Û¼Àç¿�޶ënæ6€¬Ë ¤†5@Lµ hÃÉ$‚€Ä¦�Š¥`+:H„¬QE dÁŠQA¦…€E-|ù4ýúh B‡ô‹ú(BA@Ú){¡kÍW 8–ò‹cÜCeµ¿ÝEx o)Á1”»/¸«õ€©tÿŸ%câG€€¸¿óvÿ5æ¿o©KêÇ(Ê^NNNNNNNNNNNNNNNNNNNNNNNNNNNNç2 ç–ÿ@b—•aEDØ%�­iBLA2d 5Ôf¬vî‰ �”Õ Kd™ @ :„€&*’’!¤!bÔ"f@‘.%©¢¬‰¨�ÀZ JR a,’CP†! %3U RDI%×Q‚˜ªÂ$HA@“0™(XVPÁ 0�¦¬¦¬,Œ"€*‚°‰@0RK¨вІÔL†„TH‰U% ± (؈ ‚þLŠ¢ÃUkI ͬnTƒbe‚.ÔÈÂT�s!¦éDư€ ¶Z 1`‚ � Ja$¬°Ù k%Ôœ±~ý™5|¤¥m4;jΗéM)$iH ”>R"¢Â“Y ÒE @[¦€Ä)( %ý55–ÖÊ2ƒJ¨·Qý 4!(?·Ð‡ô¦ÞÑ&*>âvÜkOŸ,)BR’µBi ¡i`·JRùú©OÞèEDÒ(ðŠ?K||PýúpñXüD`>'ùN}oãý?Oäè+T-¤Ÿ ·&Þûˆe?¼¢ßúã‡ÅG¸ñRø¾â§óþ OpøUSoÊ-õ(+\h}O〟¿¬rrŽ7AFP¶ÿ">„e]¾[âü‘á,¦�É¥inœ§)â¤V7[Ÿ~¸éE[ø©âGQo|C¥ø�’VÇ¿a÷Q€¿iGëöâÿä]>U¾%·ëeoÀ@Të…o)[[|íèýå'Â%·>óVÇþÎ _`’¸JÛþ+{ˆ®ÁÏtñþíÔ„‹š@óx6’ÿòZ·¥mOïÍ­%kÂ.ŸŸà‘k‰ñZJ|׿+�öSoý­¾£÷æœDqö·æò‹c­Ç÷”å ßy²·ûÊ2šàÛæ©®ÿ’£Â+Vúàʸֲ•ºàÇú[/¿YO|šióTÑOèÓ”S””ñÕ„ç·éin•¿ÊÝ”qÛ‡ínÝáÒr�ùƒûÊi¡6ô�×ê±ß‡mlv{qññå/ß[ió\kYBÖù?4å±ÒµÄùiÿäùBp°IÇù?~µžÈÏn5 œ¥6êÆÊºü펥öQ€©/øŸÛèÀ^iÛÏê‡ùRZ`%ªÆÏ|‚[u¿‹=�|#žß»~Rÿ>J©ý[ò‡ø”-q×óUŒµoÏ5”¦ÝžÎ—·`•–Ê+œš”[–­Ïß¾¬u§mæÿ�ÜNŸ¨®ÚÕÄ;çáÓð}‚QoüÍ»ÍNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“s‹„ ç� ç–ÿ@Äò²AP{õ¶ƒges@� ²ZÕ5¶ÁÉJ ÆØÄ‚Æ„È'´„•Ÿ H5 �„&*N¿ä‚‚’¤T`b J †BRM ’„ÀD/HIª*%t. ˜"ЏA2iT"DH ª™€„’‘†[Q%• Hª-ˆRL€ @hD ¦pB6@À"óe KPI º,DÍB`D@… =ÞÜÛŒA˜UÕdʆb eÄ@D²HiÒBI’�)nä,$JD¡¦—ÉX€ @BL³�4‡È%“)&’”�KúJ%lÓÆH¥ô¡!mÙ‰vÜa4ÑI/‘ ûðø¥n¡¢ªVЊÁ}ÇHCõ¥´-¡ú8Ÿ…¤P‡Í¥õ’ú‚’·Æ„ÐŒŒQEÉK°?°ù ·Ük°úˆ ñ:´-­§�)X>Z[âÊKyO…­QÇKûzÛçÀR•¥�äµEÐ8Ÿ?h·ø“úÊ2—éâA·¾+t¸‚ÊVŸþOÿTÖ„mߢž;z×îØãXÕŠRþ¸E->E»¼±—Ïé·ˆ·¾·›}»ó£ÂÿB„PÿÍ;~%¿7\=¸©£ø_í÷íkò[›ësဩ #=©ÊÚÞ¬ÏÂûu4¾·e."Pr…»}4­­3Ùýpå’›wâ/ÿ+{ünýq-ç½)•¯Øü¿\|x%ü–Ö¼Óçå/«ƒ�;—ÇÍþÖ‹¥�µ”e9C§Þ­?°µnóuÔ۰?´~¸ëLå/¸œC`.7Ï�ýkôégÔWÞ{~­ùGäšáÀb±øÝ/\JÌí½ýpþíÔ­ñV˜[EOËÍ×Mpe6ï[ŸæŸçÉnʳÝk=ò•ªRâ"?_·ø ÍÇ{->tûñe`/7û¬{pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ç¾ ç•ÿ@˜O3  -ð9²ÄÉ×Xá«£Z�¶A�¡’Ö)ƒ:�Õ’T««À%A€�$ªd„!±LA’‰ŠÌD IJÐaIJÀ¤™lˆ¥)% BHLÕ ¢Q%0&ª%0‘I šHX¬RŠQ‡ I4¢RDÐCe IiŠP³‘&Š„S5�$„�˜–š‚²ŠP”‚* e! A;©Ù”š�‡DTMPIh"PfÓ2 ‘†XVy“¶@ �Íæ$À‘`4s�0W–X[$á†HbgD“ƒ½$UlÀ„*$€‰«R’¶DBQBhA4”?&Œ© „¦¬a¿/�šQAD´¤”š"„¡û°þ„-x\‚R*Ð샳IXR툤RA|š_ r‡Ä q¡jßJGJh‡Ô¿¦Š©(·daGHÈâmÄÕBBÕ/¤¬ƒ¶âM¹øZ}VÜ·ÅBhâÍ~IZ)§(ã¢ßM ¡òM [®Ï�­¾ ®Aºÿ’Ý8ö(Z£Š—Ä[ÿTëNƒ€“ûý¿óX Ýnü£óº?/ݹPiM?´Ð) vå®*ë¸B/ݽóühX§õG愾 Iü‚h·×Ïwþz/7ÅûðºÇ ­Û¿vàŸÉ÷…q[ß[ë‚ÞùÀÿ7ù„q¾(â£öù´Œü[¸ð ¿ 0Th·~GÍ%ÿZÊ-þi¬ù&‡ÿ§Þl>[Àoÿ<ý87¿ËÍ¢—öêV¼×€€Ø?ýøGõù"œZeÒø$¥ý¹ý¸Ö7íõpq>q ”g±ã·`•?¬öýWç”çÊú¸2—ÿ´Ð³8·€³Û=ßà7õ�o·ÓÅÅ€­èEcù¬§ò®æ±£�ͺ}¸ðqú ¶ü…¸ ¶êÇÃæŸV™q Xßž® ÷ZÀh‘'äø¸‰ƒjÚÅþ 2•¤á NNNNNNNNNNN çì ç–ÿ@õõ1à E.üÆÍÐwa(,± ­ÇB utL(fcDÁ`�. �‚%�ÉÚI¨€�-”¡ H$�„H’ØI’S&$…RàI,™)¦ZR¬6¢ÄŠ`BÔ”„‚)Am)HF¨(�C&˜MH u�(”ÌÊ�T$‚tH )A((Q5S'üÉ�†ÂAQ¥I”3q†`$QD a·S57$À³-Ð%¦ØÜFØ,ŽË&o­2¼hÌho`…„2I4Èa«’ÈI¥ a楇ŠS‘蔬IªìÕJj!4ˆŠ · $-¥ôBÚ Õ Jj¿ã(ŽFO•ŠPŠV…/¸‹çÉ·„„P_Ë'È¡ij‡îÇþ.$:)âG[H(Z·-:RÔÓÇBÁõ½l[ÐùnßA§ŠÝJÒx–ê%(+@|ÿ)+’]šhZKì%/¸¿e?ºZ vÿÈPµnãÊV+šÂÜé|¥—õŒh§ñ…º€[¸èX i¥õ‘-U¤~­þ$ñ~T¿~µû¯Õc?Ài¥öS”PþßCáNâýù¼2Ÿà­;`>ý¾ð‡R-Î"Û©tsïÐù&ܶÿ)Z[3”¿ÀX%ýq­å/©Mü£öÓùO„Vè9E4å/ßù¤g·›®ùRšá«ùÒÿ(¬l÷|°[.‚•·ÙFUÒùŠ)ÒÈÏj_×êÜ·ÇûÀhðµ«vPµæßWQùºío�ýuÃáX õ»ŒÓ‘.P¶éd~·-׸ù¯6•«vPét~uŽâ'è[“ÅÅù-¥múp.—KìöOêßM¼xA÷ì')E6òâ/š)Ê?#nãvË_«r?\N–}€­Ëx*Ê?UÂø× Ýpº^±Ý-H}XÞn´ÇæéI”çÉžç(¢„eÃæŸþ`NNNNNNNNNNNNNNNNNNNNNN çç–ÿ@ç%ø,H¿A~”’Åð!½�f%°Ö�Åíz ÀXd€ �ˆ$¸uÕ€PÈ- ’P ’� ™©1 ’J ¡!5!µ %‰L€I Œ3 ªDCú¥¨–ja†“¢ª‚œ$˜ `©…T’$–¤„ ´ ™0 ‰ˆ ‡Y(L ™aP2Á-;*j@ É–U2PvÖT@ˆØ€€È&bÉhh €I �Ø´Á*†ZÀº[- �²¡Ä•6I6��É]XD‚Š‚£¬ò�’YC¤¬…� S PxŠPP MRH¦TÚˆ•¤ˆ ¡hJĤPì¾ ¡l-?B—ô»)ÂÙ„�I¦Š�ÿoË ËúM (¡&š2…¤>-%+eb”ñ?ã§Šßú¢“JÃ(ÅÇ/ß­/Ú]—Ë|r)¡ FRý%`éz™Yž4')¢š-ç�"Šx¿Iâ¡úÇÅnÀAñZZAl>}C÷èn[ý-£ô‚´°?§á÷Rùÿ.7õ_å?’+Íe  ¿Ê8‚ßhóU�Äø>ÇGì>À_—ê±–gV’·GçûÀT£`'ß–SO·þÏðSæ²…¼öý?ýe9A£ò|!Çæê­äIn¬d»wëC‰§ôýòÞPµ@JŸåÿn!Ý,µ”-¾ãüÖg_ñÒ_  ”[Ñ\cÍq`*-öà2Šm�ÁR8ðKæ�š[ãüÿ'ùí€ßÖ3ˆ©óO¨~´|"·ù­Q”q¬g_~O‘àT¤V6 (BÞ{ y·?¦ØàJŒ¤[ÿ+{¥�_Ïß-V7êÜœ¥6ÿËŸ¡Æÿ>Jk�+Oÿ/ÎÝÄýó¥¼ÀÝÅ€Ý/ù× ½ilà,Æé~,øF‹xüë(§)§�)A£´þ––¼Ýce.—ZÁ"NNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“-‹„ çIç–ÿ@˜_×I°Æ44¢{ˆ`ÙRAL—TĨ�É€RÆK@*L)H-`‚ Lfgb*T 1 DÄ)0™„IEC%0"0¶üeé@v%þv+"”�TÀ$Œ9J*T‰dDÌJBh%aˆuÉ5)(5!"ê l"©’Pƒ„[´ ¡%ÖM!¤Í I(©8A•Ih5jBN�  ™è‰Ñ æ[T4oa€ïLl�ÑÀ“ÛNκ0fÁ‰$�3¶‰)‘TÅ‚H¨v4B*0�DJ)(Ja"­C@�˜(`)!4‚iJA|²‡ôÃó oÀ‚Š˜tÔ,_ÑJè¡I|„RâùÛSCäÒ�A)|ù)¢”ºRíÿB_ÒJ·n[¥in(¥n—Öþ:V“”>|ú©6íSúL­»)EDÓù V–ø�±ð»z4?|µGå”Ón«s÷Ï©[GJ€RƒÇæÿ€þ±‘NR] _ªÆ·~ø€âJßêŽ4­>|‹u (·­#)¬oÍ÷çEo–ðV¶2Š*üÕ4º ý:RÐRø$~ŸÛ’þ¸ÿ^k‹‰÷q;ZvüKKOÿT¾[¡.�à|h·~Ñ~‰âqö„QX߯ßçn£¸‚âýþU�”q­,¿Í¡múÞSNSùQ”W (Ê?*Ç¡o=ߺ2Ÿ`‘nßNZã[Ïgë\HJßš}”V2ж_-Ûß­­"� ¢´Å¾›v �–¿+rÕÿF±íÃ=ò•§Þmý!5Àò‡ùC±ƒm¹Ä:?o¸“Ç€²—ôþNƒ‚JÇýþßÍÄU¯Í––ÿèüÂ×…-à;cÂÆ)â§õ�Gï)·Û³ÚªÛúmÁ4x +vúÓ—çæÿ.*”¾?¿åV=EJà|û‹ŽØïÉbšàý~¨ãt°NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçwç•ÿ@5øYà J•þ{l¯¿¢Í*ƒ'þX¾ 4ݵ2ˆ€ ƒ¦I €Öl�(‚ˆØCœ8 A’tMY$Rœ3(IK“N’ɨÂA: ƒ,LLAiÔ(&BAÃ2€Ð0PU( “LÕaI@$B+2„’š€ª %™(š*U$Å&I5R€�DЍ%Òì‘%!¨B�‰‚P!'¥R„Š£Ä % 8S!AAAfXPµF†F�PÒ"Û:Ëš¤9Ê�¡—¶&H*–b ¨iB@HBH ÂH@4”¬àUv@j0@@ %‰h„PýúI¥òÚ(¥Ø«I¤…´Š$Ë÷áÓDЍGªÝ?[&•¾7d»4%nÞŠ*Ò”¢� Ïí`…‹þ*_¤Ð¶8Òýihq­¡inÝú lZ¥ÿð´­->©ÅEº¢(é㦈HJxÖèâ[åªSJñ$£ˆú„q->·ÓOï÷o}æŸäKK÷ÿ™E/ŠÒmëOÿ>4SMøéJ×ìeHN¥ú]ÝF –Š?5µ«sëz_Ñoói âBº c­›}pùºP�Óñú¥Ð+Íe#)üŸŒ¢Ü´¶ü¾þ:ý McÛÖÐûŠ”[ÿiFRµGïõXùíOäŸ7žé Æ—áÿš[ã ãZBmâÝû·»o5žä?ñ'õùþo¿OòŠp?•6ñlzkR‘æÏ們Y[Â\DüËêà¬t&±Ÿñeå¿Ë¾ûÍçµ.–AÊk÷›t³ü"þÞÿôx°é÷›ýù¼÷/‘Åùà.?×å€ÿ\IÊ-î—[¢Üÿ�àðŽPúšÆ}Io>L¦ƒžô×Êû®H×ÉÁ/šÀUÃ\5�ù`<£xBŒ”~ÿvÇ‚éoÎÝ€­Ø%t¹ÀN!ÿ_µ¯ËÂÎ{eíÇZak=‹ìHNç¦ç–ÿ@bð#ÕØòsg¡uÍ"HÚ›]²ËÃ&;b&#`�™�¦‰,n€h$Õ«±I"%2C̘ Âpà5;� ¤™I&jÁhh@I-5¥0¥ „HJ" ©‡EM”ÊHÈKeÕ)(4Õ‰TH"”dVDˆK ¤B@NA¦fU€�d¤‚RN’dP–¥«B`È„¤ÄˆI %’Ì&\’K"Ú°7 T¨lžî…XK™¸HøcR%Q¡…›É1 !&bZLƒ@YÀ¤“2ÒHJ*! ™šP±Á¤¤¢“ XÒPL>J""¡ „�±4ÐE¤Rš( „>4Õ4¦‚�ùlñÐ’°©Ä”Rú i Kô? ‘ BÓõº2˜KñRšh[âÐJVç(¾¸Ÿ~ÎPP„~Ëêˆ}o¥ÙâD”¿(£ŠÜìRšÎx�±|ì%Ðic\ XŠGR·FD¥ð[êÇvÔÛËô[ÊRì-ñþ’þßBQGíij_~O�…º)Ïk}?°ù9M5QÇo¡Ø~‡é¬z´¶´ýñÅGä< mÏзÅot¤óÑñQáúMâv¼(Ûßþ¿IZZHÊ0(}‚»~®Ñ æ©Ê,Xëv÷ëyJGéiþ�•ª?<hÊ_å6ì÷âãÀyFãü’kƒk~$;/¸°çù`ÙúÏ{w¹Û~UŽÿõ\[\Ö5¹þ -ô,Ê Â| _—Ζý-§(Zü–�ÿŽÝ‘- ¸Ÿ~b¯?;u¸øEóðú‹aÂÒÖS€¿KKK3–÷HÚ;}pøCò[¢±¸ß罺ܵ斖ø°·>£òýà4>¬t?Æ¿*x°KûOïõ”:~ÏwÞoµÂ·ƒe¥¥«çKþÏ…­ø+_ÀãZ®ÈNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçÔç–ÿ@ïð*|¨ßW¯!¢e‚Bª( �+ÚlIƒ¶D5"ÎÀ2AVT˜ÑH10dACDÁKpŠhê[$NÑ Ú€I*ÔBI"Ä ¥¨‚F©ª  DÌ  [ (¡a ¡PH/é‚$È2PA�‰I(A‚@! „§¬[Q`L‚° @¨·PDU �ÁI Ñ”…I $A2CZLÈ2‘ I€2bR©Z4n¾Îúu†††BªÙ`›•l)"[«£¸Â@’&!bL8`¥¦PH1NØR”Ø:ŠKö @¥ Th%úLÕE, JP]‡eZ|è¡­¾vô"�àq>?› TZãvôš8¨4~°î‡ô Š/ÖŸ¢ŸÛ·|“\/ÊÚÛê Ó÷ëX*(JÚ”ñ!úKo�‰ BÝÆíé4¥úÕ?¥¸À\Aò\?¯È Ò”[‘A·Ûß­åOR+… T¡â§÷”бý~T[¿_§ütùºEGô­Bmÿ¤¾}n·~x �[|ž$V5ºŠ–¼#ÅžÏݶ -Ö÷ÖêQ\ À´·æ­éZZ¢ßKþ5¿ÊßnÊ¿'ÕŽì­e)[üÐþŸÕ¹ØoŠÝGæ|ÞPµ\Û¨Ê?дýnÝžéýqдµùà”Qá×¼>üòšàÀ^j�Ï"9jÜúž:áÊ~–“”ù£žØ ?—åùå6ÿÚÝ¿­$'ôŠÇ·­[¿h¥k=ÿ4W„<Óˆ«T£Ž‡ï³äâ[¢Ÿ×ë=ë¸Uݹõ¿ÍÖ1ý8‡Áµ$Zq _¾® zاͭҊkÞýÐV’ýn±«„Q”yº_× ÏpûÍþ°Là'Òú…¿~te/ÝŠàÁ¶¸2€NNNNNNNNNNNNNNN‚ ]“ç‹„çç–ÿ@tÇ€€ +WÕ7÷ Žø;!¥„@è˜$I¬Ó*ÆÎÚ–€Â�„bálˆ.dD”P"ˆKa$Š¡!¤È0Xˆ„È�€X„� I" RQ)&DÓ J ‚V “`RÑÂ(EIL��ÒVx1TÔAL A& €°BeˆØÙbDP³„¬@T¤¦$ÀÙd´B!"¢V0:5Du¸"J$CH’@f¡�›$LôÖImELG`ã™,h,fö¼I!®»€„f‚„j2‚� B Ã’�P@ªtŒ*•Z)4&Zù&¬P�V)JjP‡ácBÚ’ ”>&‡È ¢ªÔ—d-¡ù¤Ð•ŠêŠ)ã~VñÛÓÆ¥ùã¥ð BP?r‡ô5JØã~„SQlˆ|�•µªVðTÿ#;4-”¨@ '‹ŒCê´¥õ!ÛÒù&šhã„~T}~ÓoÁRÆš8Ò‹zݸ¦€_,S”[Ÿ~Ö²š8¸íÖ쥨£Í¿K÷öÿÍÐ(·à'ïÿ+æëò)óO©Zt·›4­%#öù AÐVoy¥¤þgŽßXÉâ6즜ö§"T5ùù´qÛðKJ­?·‡ß¿Ì¿[üÂ+�$£~k_�)ýqe ¢Ørú‹tà/Û¥Åð¹oo‹õ¿ÏòtýnÁXÕÞþh×p>ótþht»ü£œ^n¢0šB+¸�?øFœ¡(¥òßš¥.–�áà8¸xèMc­y·ÉOš@NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç1ç–ÿ@ð*ÿ—ÚÞÅѳò.ÔcÕ� Ãgm ʳ53($”²2A!²0Á«!—6–ȆÀEI  Ë SwT$,D¤T€KÔŠ¤0 ¶€)‚”¡´@!² hM@‰¨Ó„ Âp’u Š’ "“%5@�HHË‚BP†msI€Ù )HAЈÃu²RÂ@:%�AJ˜p H%¦"MÚd¶a¬ÙDÉ`$À�¹a[¡F64\á­¹�cPeI$’Ð�ˆ-iI „¥(¨„:BA€±BBP/Â#dЄÒþh ÑCåˆJh¥»*,@|ˆ—A)ãM)BÔ"”ºM.ÉYë\KA# ñ4%ÙÊúV�CO…—ÆÞ•ˆ[E+ð( [–ß"ÞµE¹Ðq[Ðû(¤Û²”ºš xÜ•¤Ð_Úi}ûZÏ|?ñ%«zÚ?hM¯Ý N–~ýiõcÛÊÞ{RýjÝùû¦š“n®?ñ?5Œ+±�mØ cæé·-¿À®$Ò¿t`‘ù.�HZÊV¨ý¾ý-!."e%kB ïË�/òŸÕ£Â+nƒ‚JÇâ¨)}nªú˜·qñ‡ët% £�ò„‚;n7ÔåÉ Æ•«pM å°(C°ì¡4�&…º <`R·\CJméK· Ò‡ø+·%ù·?|¶EKv “ÅÅRßù�ìŸÕ OÊÙ@Ê)"šr…¯7Jh|µM¾„۸lj¸ãñ-P•¥¥´¾·å!ý!h`*àý¤ŠršàGî…¾%®1úÊ2‘û|—ÞjŒƒh}oZ⦗Ͽvëy}æ�x°꜠g·P•µ‡¿òóYFXþIYœG€€xÒ¶¶·G÷ÙM¿�ÿä ?iÊ0æK§þ$[©q”¦‡k�úM±Ã�/ø¨·à>5™Ûr-ÕŽ�ßä‹zݾ‡ôñ—åm (ÀX6 Ö7cà0þØ÷Ëo–©ó_¯Î—Kñ­¿Ê2œ¢ß€�,·‚ZõÆŠà·çµ([F{-ƒì¥Ø­1E¿=¸‹ˆ¸$tµ»ùòmôÿ>é{zE9­ŸÓÿ­çºÛ¥’þ¸ršátÿ\"Üxß¾üÝ,@â}lu¾Ý”qþéFQ‚L§šá[ZHNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚]‚ /‚ç¼ç–ÿ@ ®q~&<ñròX$é|N¶t 2æîò³²Y ÁÂ- ºfC«¶ˆIE@A &L$�"©  &`j”Š‚ªJ ()J&¤CHJ*˜�%W 2P’d B¬Ua P(!%"ªID%!ÔA0SQ2LH!-~Ij¤ƒDT‚$ƒ0t€€Â „à±*‚�,H�ÐÁ!Öš¡°Êº©-“ÈÙBvƒ2u²DÁ ­ªÐÐ –ÁÖ¤‰�jf*F¾ êR€ ™|ÊJHK* š„$Ê[Q(X„€™Z(€)% 4Š©AL Òü‘8TÓV~•‰¡@I \O€)…·š•M)JSJh¥|I¡l%ÿ²�K÷Å)ÓÇE%nÍ©%õ%&ß–)+UiK²’x’±·ÓKÿÚßõ®4¦ÞOé+o�„­H¥+gˆññCïÒü¿Ó”¥öSÄ´ý4ÓÆE4AZKôå?—Qo·%+iâ6ôÛÖÔ·å$ÒCÿ7€íëa>mk�òã[¤ÅÇú¦Šxß`.?Úk…m+x (}”->Êù­þ_¡ú|�‘*×¾œV=+’Þ¼è/²•¥¯Ù¥_¿Ï‰ÐV²•ºá[·'tÑ”?·à<§ÍþN–t¶Qù[üÕ¸¾ý!jP)G›@æíÜ·ÖúÆÊ|_’Û¥ÿ_µªhŽ*¿·e¼ß6ãæ–ü#ÇÆþÞ—ÜyM;86-SùþKtSCô¡ú_ÛŸ8†Á-›¥“oæ­Î”µÀü¦¸?Võ¾>3Oç€�›ýºYOº—Ô¿|’Œ«Š_¬kƒùçüž r„xAv_·H¤-,iª  R…¡ —Á/ÍeO¡úÀ¦š ô…ªiKòM4Û�(ª´ÑA AâKñB-ï¥ñ|$#ö¶€V¨©üÊŠj?hãýÓJRVݲÑK²ì% k@P´¶û÷ò´ŠR—A+i·­ÑžÉ¥qŸÐÊ)ÀVü÷}…” å(~•·ô~c‹=íÈ¢œ‘Xè'ŠšÆýŠ_>¬jÓ+O°ñžé 8 Š�ÿ(§Íe/Êò” QCäÒµZf‡öûwÛî,û)}û£‹õúEõ¯5\4£ŠØî/ óyGçBOço·~Yïžÿ¯ÖÊ<ÞS”þ_“ˆ¼u�XöÿÕc'‰."šÆº0ÖÊKˆ¦¸-é/³ä§=¿YJ8‘Xÿª+†ßXÔ8†¢±ø’ùmÄ7NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNbeetbox-beets-00724b7/test/rsrc/playlist_non_ext.m3u0000664000175000017500000000010215253035401022015 0ustar pieterpieter/This/is/a/path/to_a_file.mp3 /This/is/another/path/to_a_file.mp3 beetbox-beets-00724b7/test/rsrc/min.flac0000664000175000017500000005260215253035401017422 0ustar pieterpieterfLaC"÷ Ä@ð¬D!îÄvoWeƒ×l°÷�5 reference libFLAC 1.2.1 20070917 TITLE=min�óÿøÉ•@µÇ!Ì¡'†hPæhRs%… $¡aäÌ̔Ô9C9)™<¡C™”ÌÌÓ%8Y”Ÿ)…% aœ(r’‡49CL9C%RY’Ì<ž… dÓ ”)™™œÎd¦M 礧2…&yùgÐÉågÊaá94�% L³9œ(Xp¤¤¡ÃB…3™e% B‡ ˜D™¡= ¡@³ ) !ý Ì’˜s(NN’…2P¤¡åe&faʤÐå3$C'3™ g$³ 3”%8RS%™"Bœ,’” IC„By— °ˆaNˆ”„Lä‘ ”Ê”¡”’yC“2i…9ÿÿ¤¡a))™B‡ f,0©@¦„¡IÉþ†Re ¡(XS� …†Ng:OCž†s¡C™C<3Ì4ÉL(hÌ9å”)“"))(Rp¦Jg3™™˜S39òÊ�I’‡?)“)9C3'(e äžPÊI,)(S L”)'&p¦r†œ¡Ìáae ”2P)2�HD%B†”†Je2yB„ˆP‘‡‡(~y@¤¡4)“L<™2“¦K(y(”2“‡3ýPç)3™™”)<ÊaC˜R�¡g)“)3æS0¥ 䟔ÉÒ2d@°å$晡C…†s,Î�C“™ XzBœ)™’�a@Ò�¦�ÌÊÊI伡I’‡%0æRe'ÊPÉB’PÌÃI”'&RP”2yNe2 ‘ 9ILÂ$2™)"% L¡Iš”þXRe&P¦pˆ(L¤þ†r…Pæ…$ò–,2’Pˆ”2’g JÉ43š¡CL)™Ìó”3' Ðå$C„ÉMRS%330%3 p¡I”2“†�IBr’�aÿùL’™2“ 3”É)'œ¡Ì§= ’˜x|)C9'èe$Δ dæsÒ$"I…9ô” 0§2̦g4) )(J¦g p¦fs)†œ¤¡…™¤ˆLÌ“ÂPçÐ)’„@ÐäBr� D…„¡á¡’�¤¤ô<'BP,(g(aaNÌŸ)ÊC930¤“ÃÌÌÌ)(RrPå0¦L¤ô9C””9œ¡Â!™HD fJ ç ÉB r“L‘$èg= 4Í ”9ÿ<¡É™™Ê<Ì™L%”’JL9ü¤ó9™C™L硜¡IB!(D9™ä§ L¤ÒS%2RRPСáI…†i4ÌÌÊ” fr’r„§9HD93ç@Í Ê3ÐÎPÌÉ™™™ÌÌÌ‘r™% 8d¡ÏBPÉÊLó9)C9”3’S32†JdˆL¡Ê¤¤¡Lá¡Ì")Ì,™Iè””90áÉL¦O”(g e&Rt3” D99I¡IL4)(y‡(g?@§ L™I”Ÿ)œ)Î�IB’‡))(r†PáC””9Ë sL2’O)%(O<æJJJJùÌÌ,™I$C!L9B„ʦMçB…‡(e$”¡2Â…8y”“çåŸÿ‘L¤™™%0ç”)'�IáNL)3å I™’r‡™ �œÊ)“L””ádÌ”š9�'IL”””9II)3?ýœ(g…2R†fLÿô2“!(D ™C32Jaœ™L,ÊJ˜rfH„ȇ“<)™…&hfPáC…8r!9ÊJrPˆJ”Éèffd¡Iå9¡B�§ÐfxÿøÉ’@µÇh!)œ“4)2™™œ¡I™™Âœœ¡ÌæfH�¡™L3”3ŸC”ÌÊå&s9Cœ¡IB“ÊÊàS‡2D2RRP¤Êý ðÊL¤Òz:†e Ì™çÿ¡Â$Í B…�Ð"LÄ2S„I„Iœå&|ÊLå&P¡Ìœç(fdša¦M™ÊL¤Ê”(JLÌ)(S'2PÓ g!d–JfP¦ffLå$§ fL¤ÏBP¤¤¦fK3Ì¡BP¦aIÌ”)2†hg4(hD L¡œô' S% r\3„@°Ïå&PäÊ"žILå p§8D9™ÊLÊœÎffaIB’…% NPžaL”)(y(S“)0²aIÂ’…' J ™ò…&P9@ær„§ fL¦¦M… LáÈ�N(RfP¤Ï(RP¤ÿ‘& Έd"rfs9B“™“òœô(Jr™(P� Ì” J¡œ D”)™”(s'3œˆ¤§‡3ЙL)3ÌʘYœÎPæRe2JJ’På æ™4Ô)8P¤ÎfJåž’™""ÎS’’�IIB˜p§33%8\9žff4e$ÊIC„I?(RaLÃɦÉÌÌ¡IžS…9È“4Ì)Éš Nr!(RyB’xJDPÊ99”9ùe‡=0ÊLå…%™3™ÌÊ™¡œ¡Â!(S&RæaJIáœ(S'0§' 3ÉL”)̧ dó‘ žPæg0‰2PÐÊL°³B�¡’PÉ”šg>i'Bee I…8RP¤È�Nd‘ œáNLæIL(Rg æS% ”�ˆ&JLˆIC¡BPˆJhPäÌÊB”“œ¤ÏŸÐå%%% ¤ÊJaÊB„ó–r$™He$ÉB!†™?"Éʘ~s”3™LçÐ))ú(I¡ Rg(g0‰3Í’ž†s¡È�BÌ4“œáœü¦ffL¤œ¡ÉLšOIô9CÃ2|ˆ%PÎ ”Ã)%2PˆJ ”(p¡C9333š…0ÎhsC� œå Ê,ü.)=!å ¦NRg” &rPÎIfg0Ó'aš…“3æRfe B!3™)˜Pá@²J8PÉ |ôÃ(PáN†PÎJB…&PáÎae%32’~dBag2’|¦s@‰0ù™’˜S33' ” ”&D'0²M ”(P§9Cœˆ¡Ìç3œ)")’!2!ÉÐ(RPô9èd¡Â!†g(Re'ü¦JB!HS)“)’�L”)8XDe0ó ™”)2“þS'”Ÿ)2“”ÉùB“2“úfs9™C93% ™ÉÐÂÃ)2†rP¡L”?)2… æ'ÊL¡Ìå'¡ÊsÊdò˜s†JIL”Ì)™2!†“3) RLò�aILšaIɲR‡&sœæH… LÌÌ”ÉLÌÌ¡œÌÐ)(D39%'¤"‘ œŸ”2S%% 礡I”ÉL”3’™™?(S0РRgŸ”Ì”2P¡)ü¡É”„@Œ€D…„ÊM0”Ã33&“¤¡Ê™'ÊJ”™ç)™’†Éœ(2e„Ê¡ÏÊNP¤Ê)’g%„ÊJœ¡2!“™’†�IÉÈ„ÊY&’t&S$³,¤é†…'% IC% ¦™”8“ÿøÉœ@ÿÿµÆP!9BR‡™“ÎPðå”$ò…'3% ”šdˆp§&†NfaI”ÃÌág2’eB„¡’†O”)™ÌСÊ”¡œ"9’…&i)Ï"(fg?C'ÌÌ™9œü°ˆ@¤ÌÌ¡œ™C8D2p¡Îfs9œÏ$Iœ°ù”…2†s rP<“9))"˜xL¤Ì¡Ì.I¡�‰˜RR†r„ô œôÌÊ’” JH|¤ùgÓ0¤¦e áLÊI4Ÿ”Îç–ÉL,"8r™)’™œ)3I¥ ¦Â!™…“3„@°å$ÊL"ÉB’ŸB„ÒI¡BR‡�‰™“Bae2S’…2O …(M ”š™aNfe…% r“)%$¦)(ú¤)(d”™ó"y2†…'¡’†L¡“˜\žRe'”(p¡fS „¡¤ÌèfP)™(hd¤äC‡¡ÊfRdBe ”ÉòÂ’‡)4(g0ˆd§)<Â!„I<3’…&yB“œÐ¤Ê“ÉèfPç%2R�ÌòÊáBÉ™”ŸÐÂÃý&…&t�0òtÉNL¡Ì¦r‡˜RS aä:Ï¡’… Ìœ3C9C9$C…3$C”„ˆ™Ìó dÍ'L<”)2™œå$¦IB�æfrD)ffg% !JCL9”3% LÄP¦NM0òP¡IœÉfL¡Ìç9C™™C9œÉÃäÌÌ”ÌÌ”) "™™’”š™¦˜g(sò’P¤,Ê™43ŸC'™Îg3™I”™L„LŸ)™:ž, ™I¥œ3C')’s$@¤¡I)(S%2XD$Cœ"B”9œ¡œœÏ9C 9ž~Y¡C˜S… Ð3�§$¹œ)“™™œÎPÎgå2J“)(r„¡C“2e%œ2™†…%™")œ¡ÌÌÉB’g fg2’rS2�áaœårD)3‘„B„ˆPÊ™C”„Cœ2““4ÉLÌÌæyÊÉOÐááC38R†rd¡’…'8D9ÌæS!°"dèr’…&2e%PÊB‡“™2 P¤ÂžS…9ÊNPСə)˜Rf’…&Rr!C”(Rri…2s2RP¡ÌÓRtšaä¡I(p RfP"9Ì‘ ”)(RO% 2D9™ÌÌÌÌ¡L™@ç)œË3”3“™á,(hRC (žJP”¡=ÉäÓ åS3œå æe2hPç (d¡’“"�r!3ÎRg(L¤ô̦B”“ÿ)(ICý’’‡…&|¡C“™ÊÂä/”™C“(s …|ÐÉü°¤äB| (Iò…&r†�)™9™™)?”ÌÎ}“‡3”<<’…!BÉ”3Ây™”9”ÎdI'”™d¡¤¥ Ê9BrPˆ„BO’ F,ý ”ÃÌ9’Ê“2rS3%%%% IB�¥�fP,:R†B%…�JI”3%‡3(g0³3™")’™:JfP"\¡IŸ2’fs9™‡(̙ʔ"IæD) ™>P¤(RrR�¥!BÂ’…$”(JPç¡IBÌÌÌ)9™™™™)(r“Òçô'ü¦aðô%Ô̔32P)3ÏŸ(y…2p¡Ãœ)I<9”9™™™)™Âœ(S3™™™)’˜S&D&D3„I”Ÿ)9I”ÈD˜ÄÇÿøÉ‰@µÆè!339œÊað§ dóÎfaÊ!�s LÐÉB‡ N“L<”)8g?Ò…ÎP¦L¦JP”¡4(JBa&P¦Lä@Í °¦fM çÿ¡Í L¤¡”38Pæ…&RS‡˜g=De É”„I”3…0¦NJJHD)9‡’Y@¤¡™å2P¡áäœÿ)(L¤”“å9ÒzM0å Ì,Ϥ(X&xD™”4 J)9’™’„@ááe'I”” JÉå2|¤¡(p¦NP¤Â!Â’’…P¤ÊM Jfd¤äC'30§!a”Ù”8D8D)(Dœ¡)™†R NÏ)>èr„¡’�L™@ÎL¡Éæs0¦aIB‡“ˆL¤¡™™‡’áB˜hD $ð¡I”Ïœ¡™)™’ P¤ÂŸË 9ÎRg33338S3'333$C'%'IÒP¤ðä@òdC338D4(Y3”% “2D(JJBP²…&fffp³ p¦e J“2Pä@å%(OPÌÌ“ÉJ™)’™Ê̤”™IÊd‘…3 fg3™ÌÊ¡œÌÉL””ÉLɦ“å2t °”ÈDÉ32S&’†„C™ò™9L(D% ™I9„C%'(rPÎe&S'¡BR�ˆs:œ)’Xe&r’e!¦JaL™IL–g9C„C'2S dä¦yùL<…2hfp‰3IÒt(d¥ èÉÌ”'C &RM% s)2™(”<¡Î¤Ÿ 4ÉLÌ¡š<ÉÐÊLˆL¤¤¦g dÊ™“IB“†p¦N‡"8e Ì™B‡3ÿèp‰(æJB�‰“™™’!Â!Iœ¡ÌùLÌå!9ærS%2S9’’†xs¤ô32|¦NPæRz9Êdé;&ɦ¤¡LÌÏ’’�ÌÊdèr†fL¤ÊfS3™ùNÌÌÌÌç¡ÎD’RhP”ò™:Ô93™Â™9™ÊNS$ГBe$¡H_üó9CÌæ’…&)“òœé(Re0§$ D”)ÌÊÉ”332S<ò…d¡É™4ŸèäŸ)“þ’…&RzJ¡C… ‘R…PÌÉ”™Ê(SPˆÉI„”))˜RP¤¥ ä”ÉLæRIILÂ…!O¡= ý&”'˜S$òS”™Ê™(S0¤Â‡ (s,¡Ê2fr’†fs¡Iš™Â!Îd¦M0òP¡ÌФ"!JIpÊNfs<¡aš,"Ê¡“æRe‡(Nd¦fJd§ 3™C%% B‡ =%RP¦g„¡äÌÉ”‘ æOš?ô(JÄ@°ÊM0ËHD  R š™ÏI‘ Ð)HR’˜Rf“C„I…)$¡ÏI¡N¤™I”” Na¡4(9B�ˆž¡43™žyC@¤Í äˆd§Ð¡Ìÿ)“ y'3”(s39™…2s L¡”™IB…!BÎYô2r‡3”3“3%9Ÿ””2zÎ�I’�ˆd¦ˆgÿB’S!IùL9œÌÊ̤”,>�`A“)%8r!)ô2„Ê|ùBÀˆrdˆd¥$å B– J™’™™æyÊ y‡(dÐÉBLæK32P¤ç)”%�èf‡)’™))(RLçÐÉBe&†y™œÌ˜e&)2’’†‡))(sÒzaòî’ÿøÉŽ@ÿÿµÆÈ!å” 0¥ B’�IBÊÐ" XAP¡2˜y…™L””33 Re BœÉL)’”)8PáLÌÌÎdˆað§2P¡’”% Có”3™Îd¤¤¡Í'I¤–P<ÃB†…32‡(PÎå&S3<9 0ærS%0¡IB™…… Ÿ”Ì” NdÐ)�ˆd"LΔ)3Cœ¤ f†r„¡IIBÉœáá‘ 43…2JL¦OC”š2S”ÌÊdæfg8Y’!™…2Pˆg„ÐÉB“‡‡%gþ~ÿ”ÈDÌ)Ì"pÞ Y…È\’Ê… Ð)(“ÃÉ40Јp¤¡IBœ…™™Ã”2�džáe ù¡&„…�òi(Rp¤¡aNH†fNaæg”9…(pˆ…™Ìæyù¡BxPæg2…!9Ìó$C%(‘’‡&p¡I™Êœ4¡”ÉÉ32P°ˆJs3%2i…2hs>RPÏ0¤ÊJžg(y2Â!<ôš2†p¥$B‡2fJfP¤ÌÌ”,)"&fsCB“Ì‘0øP²N„¡Iša)†Re3ÿ¡…˜Sž… Ðô”šd¡Ê’‡˜y(RIr8S39ÎRr…�ä̇É&PÉáË JfPç†�áLš¤"ÃB’œÏ™”&D˜D8e&’†…% H�)I”Ìæ‡ p¦g ‡PæfPÉÔ9IL”ÉIB“)’…&zB„¦OÍ!))(Y2„È„Êfr‡(L‰2’’ Rg ¤È„ó2“’M ”<�2P¡Ì–P,2‡ fPÎsÐÎPÎe™JË…8RP¡Ì¤ˆP§(faÌ,™C˜S… 3™™(s)…(JfRfK0§„„³%)‡Â™2†s<¡ÉÌæJ9”ÌÉL“†pˆR¤ü¦N‡"(r‡‡)˜Y0ˆdÒIfrS3<å&y™…&S32†g�NICŸÈ�¡BPÊaòg2†rPÏP)’”<”)”™LÜÍ…&fPç rap’Èr‡)(hP”å2PÉåLÌÌ"L‘ @‚œ¦L¤Ë J™(™(g&e ˜s%% ÊaðÍ ÏC”ž‡(S33'% J,8RP))ž†sB�f¦ÊL°¦OžP¤”)39CC”„B“9C„C™LžS8P‰ ç(g&PæRJa̤Í™”“™˜S2P°¤³330ˆdæO…8hR9C)&p°") PÎÌÎRe3�2S2“"…&g 3Êp§'(g0ˆLÊ… C$¡C…9C”2Pç)9œÌÌÌÌÊÊaÏ)™ÊHPáNdI„IC)2’’!ÉB’g�LÉœ3’œôÂ’…3' (J3CB‡&ffe$ðÊB……”<3… È�)èdˆ%% ”$ˆdˆR) d¦H�HYœÊaÎP¦aC33…8P°Ë f!Jdˆœ“Ã9ùC8D9ÎdˆL"d”Τ",,"ÎP¤ D™�IC’!BSœ¤¡=™“% ”ÌÎr“œ¤"Lç3ÌüÐÉCš™C””ÌÌÌÌÂÂ’!(S…9™Ìå ”’�IžP¤¥ ðΤ%0”) RSúÐááC”2“(S$¡H|3IB™’™"Í æD’|¤že'ý0øhD!0‰ s™™)(Re39”ÃL§�aBÂÊ’�á¡NÌÌæp¤ÊN™6‡CÿøÉ‡@µÆØ! (e&J2„"d¤¤¡L)�Ð,Ê)�ˆXRR~RNdˆNaÏþ‡9Éœ¤že$¡IÌ”) 2RD JæRO3” dÌè™Cœ²‡™)“IÐÉóç”) PÌÎL¤’˜Rs 0³ JI„C%9O&™)48YCÉB‡'’„HP²fH‡9Ió PÒO@³4(rO”œ¤Â&O P“LùI”(RPô&˜0¦g$¥J…)%2hd Rd¡I”$¤’!2 s‡˜y‡˜xffN†J†hNRP4åŸÓ…933&˜Re!äËɤô9C”9é†hd¡…’~S'9C8D%8DÙ32RRD NL¡”™¦J B$)ÊaN‡4ÉrD) ÉB†… Jœ(s4ÉfáNs̳)HP¡CB‡(sB‡'(På d§(Sd”áfP¤)HS3%3%%P¦frJd¤¡IB’…“9C)3ÿI)BJd¥0¥ ”Ìå ÌùLžPæÉÌÌÊaNLÉþ…&S39""ÎffPùB™™2 s4'BJaIš"(dÒzJœ”¤(fPæP°¡aB“=” ̡̜Ê% NRO2‡Â™™?@§ 9”9é(PСI”<šd¦r…“)(RS3”)3”32rS&’™,ÉCIÓ ¤™Ê¡I”æy”™IÿùC™œå¦K‡ÉIL”ÌÎPСä,¤ y™:)“)˜S&e$ùȆJ|¡aÿúaL“2z8s)&PáÌ¡œ)™’!’™)™™Be'"I432� FáL™Iç"Ì¡œ¡Êd§ $ˆR"LŸ)…ÈS3%™”8\¡IL¦™)…% 8Y(pˆRNIL%RbÏœÎd°¡¡ÿ”” Nd¡C“8e2P�!BÉœ)9CÉù)<2ÎS'ô(g&sÒtš¡áœèRp§'ÊÌç(ry…’S3Ÿ?(Y3”ÉJ“˜y’!žC% ‡<¦f™Ïþ’†„Bg%2Y’™†…%39’!“™)(dùLÌŸ”ÌÎPæ‡4)0ˆp Y� áB!3'3œá¤þ�N™™˜S<� ”ÉК¡äÐå%2„æJfp§ fd¦J@°¡NtÌÊL¤”ÈD™Â™œü¤Ì””)(S“(pˆsú¡”%3"òs(d¡LÉðÒ„ÐÉL”ÌÂ!HSÿþY”ÌÉBP,™ÏÐÍ0°ˆÉB™@³'33 dÈ�Êd¥!BÂ’!(D%&IˆdÊd§0°¡ÊJf™¡ÏB|ˆL¡3%… °¤Ë%9ÎR ÊÌ)™žS'Êp¥$çü¦fLˆLÐ,(pˆrfO 3œ¤Êa̤”É(Rs)8S“9†… OCž“"a”…48S2J"™4Ìå')“”2s3ÌÌ8S” (ÊfffLÊI”˜D8s%&…&S$Bd@¤¡IL”É)(S9š¥$å&RLÎPÎd‰0²ff|Êa™œ"™3(™Éé4<„He˜S2e%2S&’… LΓ¤¡LÂÂ……39IBP, s'ò™%!æa¡’�aLÌÂÂ!ÉÌ””Ìχ fg p¡IÌ)Éže&R~hD(L¡œ))“LÌ,Â!¡šy2k»ÿøÉ€@ÿþµÆh aœœÌÉB�¡HP¡Ê¡™™œôž…9IÏ æg332R†re ”¡É"Hy™ÊOèg?¡œò“(PÐ"LÎfaL™L2Àˆh&rÂ’„ÿþe!¤-”'"9L”ÃÌÌ)‡3¡™Â’„ÊfO”“ÉNäùó9œ§)™™…8S3%2tÃ)“Ì生)‡˜e&39C3%É9”3’Y‡)(hRP¦NaB�¡I(s)œ¡C”(|4ÉI¡)ÿèaf} 礗'IICšaò†hg™ð³3P”(y9™”’…&J˜Y„L2“9fSfe ”(J™ÏIèdèN†r™œ”ÉIB!'%™2†P¡ÉÂ…$¦M’�áBPçL”Ê…0¤¡O'BP"B„C% )�‰2…P¡¡C”�0"J”3ŸB‡3C9”¡<¡Cœ(y™Ê9<šaÏùæs3(g2‡9)Ü)™œé= @¤æe$æD2P¦IC˜hD% JJ2“ ™™(P”"% ”’™)™™Â!™™(RO&’… dòg9C% N9'Ês‘&i’™)’™)(XS0°¡L”"̦Oÿþ†eaL’‡%&He$¦ffJ%&r“ç(s9CÌÎPÎS$@ˆJ,’˜PàA B™’†Oʦdä@¤¡B“"BœÊL*"B™„C<…(S!|¤ÿèPÎLÌ¡œ”2S)“úç)ÔÂy„BP „¡B“ÉL‘„ˆPòS™™"3¡HPСäåš¡�‚™áLžI2„¡aI@°ô2’„Bg ÌÌ(Ráae á™HYBS0Ò„)“IC@) dô™fR�Ì”2R†fdð²�ä’!„²hP²äÌÎe2†Jr“Ê™)% B dáfe%™ÃЙI„C…(sÊœ"œ’äˆP”Â…‡3”9™œ”)2™)™’!Â$"&LÉùL“”’P)(PæffJf¤(D†R¤ž<ÃB†˜y…s„šd³8R„Ê“B‡2…�¨‘Ì”¤žP¤ÊO9À°¡Î†sC”„C… Ê44,,"2“¡I˜„ÊJfså3 J2S39ÂÉ”9œÎg(Rs”,Ï(rs„C’^SŸ”̡ aN!@°ç(O…)33™”8Pð� ç)0¤ä¡I”<”Ìßèr’’…&hRrS&†fg(hr„¡™C)�³$C2“ ̦”&†xe!Ì)’œ"LÿȆJPÎC”””(s4ž’‡"ˆa¦JfM0”2P)Â�IO”ÃOC”)9…3$¤™“32S&!“œ„I„C38Y”"(r’…“9ÎdˆL¤é‡’™"ÊC:B‡&dœÉá<“Ñ…”2PÉC'Ê™1 ”ÌÌ)(Rs332S’!“ÃÌ)2……8S%3(s?)™Í Na¤é4(ry)’Ì<ÉLÎsœ,™™™…&Ðæ…&S0¤¡CI…“9™Â“˜y(RR�ˆX B!(D%(r�Ê% L¡)Î&%Ì“ä‰À‰(R|¤¡0‰2e!Ð"BœÌÌÌšN†só8P§ p°ˆJH„¡aNÉ”æPáœÎPó'þ†p¦OÊJ(PáB“,Îe$üüå$¡IžP¡I…3™”8D32rS$C0êàÿøÉ­@µÆà!™”’S NaLÉ”””2P¤ú愞ffJffR¡“™)’” °“C9¦M% L¤¡Êô8D4(y:”3˜D9)(… dä¡IÌ”ç,"†PÃáèffd”™ÌæÌ̤Â!Â!ÉB“?¡œÊL¤œ¤(D�¤òyI@¤"%2ä,¡Ïò“4r††S <§2”‡C9IB˜s>‡‡&PÍIÓ �L™ÌÌÉC@ˆJaN¡œ<¦OÊI"%†NJJfd¦aœÊdô J„I2„Ð)ÙÌÌÌÌ¡IÌŸ?”Ì"ÉB„ÎI RPÐÏ 2D2S$C%2D&D'2†rs9…9?”ÌŸ)…8PÌÉžg9þ‡(frP‰ áLÌšL‚H�¥&S2„¡”(i’™œÊ™C™å L̤’&INJRBÊáÏC”)2“ÐÌ¡ÉBR�²’…'0§ s“?þe$.Oò™:%<°¤¡= ó@¡"gÊdùNt8D‡¤)Ê8r’�¥%% Ì)œ(S&SR B$2!“™”9‡3LÎd¦B$ÂÊfp¡¡B™)œ¡¡9“9žP§ 38P,¡LÌœÃL”ÌÎPæg(s™ÌÿÐÉC9B…% Jaʇ †™†RIL)“™…8S…3’DÉò™3”% JJáB$2„óúJfp§&r‡% B”’˜S‡å9Ó%$@ЈJPÎ L”šLˆp¡ÊJ™C2e39IB™)™’™4ÃÉLÊÊ2f} ”3(s4ž“èd¡’„ÊO)™™œý æ… �ˆO0òNg”)0ˆP”Ï„Lœ™™™™˜P¤Ï!32Ri(Rs% !Iœ3ž„ÐÉC””)2†Ra&RRD 2S'C 3B’‡"¡9@ˆs(p‚!N¤¡L„@°§”ɔÙ̡œœ¦g†rN�Iå0Í …'(På ó”%™")™œå&s„@°¤þ†Re&…!C”�$ˆd¡Êœ)™™œ¦eæH’aá‘&s™”9ùLœË æffJp¡I™¡œ‘ žP²e2S9@²…33�2På ¡BD9L))’™‡“B‡3B“):)<§†rs"„B™É)“B‡2˜S…9™™)˜RgC”)“œ"(D%&PåÌ™gÒP¤šœ"…&†J(p¤¡2$…Ã90¦(S I¦f!JND H�CœÊaædÐÉC”)“)=0¦Iæe$󔜈J”3(p RgúJÎaL™IBÂ…’R†fJœ)&dÊ9’‡3œ¡ær‡(g Ê™“L<”ÌÉL”‘ ”„BP‰'>�IB‡’|¡¤¡aÿС–IÊS!L�‘„ˆD2R†p¦aI”ÃɦI<”,(sȆJ}’…†Y2’JP2D)2™4)(S' ¡œ=Ì"Í3™Ì‘“™Â D…„Ê“"(d¡œé‡ÉФ2Â…&e Iá9(p‰ “„C˜Y@²e9Iˆdä¦J”3Ÿ9I@#0ÿ‘LÌÌÌÌœ¤ô 3èg(Rf“"aäæs”™C”P,94�fNRP)3(O3ÊÊÊ”2R†JaäÒ„¥% Òzd¦På™ÉL–fs9)™™BdBNz"= ¡Â!'(Pžt(XpˆJ@‚¿ÿøÉ ª@µÆ� g™Âœ(Y%„BP‰% LÊ“(r’…2J™””9C”9Ièg(RP¤áI@³?ä@æNg)'œ)’hd¤þ†g�M!) RPˆ¤äBe'L‘É4𙡙@¤¡Bz¡L9šaLœÌ¡’‡†…2†pé%33„BP°¡I™B’”)™4ž“¦¡C™¤¡aO9C… Nd§™™™”<>dæffJ‡ô3’™™ä¡LÉNaЙ9††M!šäHICɦH†Jd¦fg$B“:ò™“æRg)2“9By)CÉ)’YРD™™IÓ†x !NC…$C9œÏ= IèJ%(r‡(e&P¦Ng9I”ÉÎs–9™œ¡C3d¡Ìú2’…%’…… dæ™IIINáfK33339B’‡2XrÂ…2rd@¡¡Ã””ÉL”š4(S2s s3339’!œÏ(Re ”9ILÌÌ)3ü§:9� =ÉÊœŸ>e$ó)3”œ²„¡C38P°§å8XD $ÊNPС̤¡C9ž… É”Ÿò™?СÌú"s&På ÎáNÉ”) ’t3…”8D2R�fS%32D2S9Ê™I)’„ÊB!C)3’Pæe$¡IOB„æL¦r’!ÉC“9™˜y4Îg30¦L¤¡Î˜y… ”)œÎg3) hÌ4ÃÌ”"C"I”“)&g3”)(RP9™Îá¦H�Ìô3Ô42PœÊaÊ&JIÊœ,"ÌáC…C–çùʆ’fJÊaIœ¤ÊdŸ2’�IÉý ffa†LæH†p‡<ÊI"9B™œ"„Be å IB’…$C'(d¥B!·(sB‡“"(Pæò“9Ìó™ÌÎPæPäÎffM0òS$B“ÏIé= ™C’‡3”’„@å 8yIš33&@Éažç)3”™B“%2t3”9ò˜e%! D9Êg‡' J32†Jd¦Jpˆs')'BdC'2e&$Î)’™˜D8YùÊIò™I<”Ì”ÈD˜S2”ÂY„BP¡äô…9,"…2e ¦¡BS…%3(JfdˆP”"(g&†L¦Id¡f'B�ú%?èfP”“2†…g(g&d¤¡ÊÉäÙ…9œ¤ô dÌÊI¡†” RaCœ§=30ˆd¡LÂÂ’“L>JR¡áÊåB”�³3”)œÂ$Â!œ(fRe339…2e$@¤¤ÂÂ…'% J™¡™Â!HR‡:aNe Lü¡I…3 ¡š” :4 P™@æS8SœˆPæpòP¤ÊJœÉI2RP¤æfxÐЧ'(PÍ ó”8D’†�aI8P¤ÊJÿB~faÍ !BS”Ìå% ')ÀŒ’YÊp¡¦S0¤Ì¤Êfe áùLÎhS9™”&D…)…!Jdÿ)’‡‡@³))“L)ÉLÎt(rfJ%œÌΡ’…%% L¤¡I”ÉÉáNPáær“”9™˜RaáC9”Ì� áI”)†Xf“‘ œ¦fsÿÐòPˆ)¡Cœ(J|ù”8RD%(y<¦dç30ÒP²adšaL%Ã<ŸC'å%Â…†C%))™)"™ÎPæK˜D˜YC˜D8P§B@­ýÿøy CÔ@µÇ(©i*”´¥¥-*ZUd«(´¥-IKDÊJYeDÂÒÊRË*YJ”¨µ¢©KQT¢ÒÉ•)ZXš,µ%,©(¹)QjJZ”©IjRL¨šRÒªT²¥)K(­%rWJV*X©bÊ‹R–T¢ä¢å)R‹JVT¬´¥©J–RÒKQj‹R•µ*KRZÉU%©-EI‹E­*¬©U’T¤˜š-,©Jª\²Ub¥‹KJZ-eKZJÔ––¤©¤‰ªER‹‹I”–´L´ZÊR¥©–Tµ,–RRÔ’Ò•-*²Ò–•YJ‰”¥%“%JK%T©eIeJR¥%–”\´²©,´²Ô¥%©.-,¸²Ô•”´«J\YZ¤ÑeJª¬¥JªURÕ*,¤²•,´¨µ%I2’Ô¥)--IjR’Ô–YQKR#)-U•*©2•Ee¤Ée¥+RZ¨µIJ¢eJK*Y*²ÒU%eJªªª¬¨š,–+,©)J‹TZ¥)e%”¬¨šYRËRT¤´«,¬µ*&I‰”¨¥ÉZ¢eeKRU*É+)JZJ¢Ê–TªÑk*R´²µ)R¢å*ZX¨šQ5"êT²Ê”¤ÉdÑKJYQ4¥R©eJT²¤¥¥-RZÒU(¸­JRL¤©EKK*’­,©ieRZ’Ô¥)R•-%R•*Yqbhµ”´•IZ’Õ)R¥–”¥©)2’–)&II’ɢʕ&QYKR”©U•,¥J«)j*Yh²¥V•¨µ%IeDÊRR¥JªUTµ)QiUJ¬’Ô”¥¤“IjJL¤µ¥¥¥•+)Q2”¨˜ª¢É•Y*¥e)iEÉe¢©JR¥)J‰•**R–’ªUU–\¤©eIJQieÊRÒR”¢Ô\YrTL©JRÔT¥”¨˜´²²Ò¥(™(µ\Z”¥KR©+K-%K%”–”™iIeIIeJÊ¢•)j•V¢–”µJ-J²U”©UK.)T²¥UU”–T\²´µEÄÅ¥R•,ªJÒ¬¥J´«J´¬´±kE,¥%-)UK-*IU)U*LZYUKJ”©R•JT¥)&J–*TT«QK)--QrÊ–R’–R¥,¸¥ÉU,©JZJ©eÅ‹R¤\¢âbÑ2¢eE©E¥*²’Ê•ZYRÒ¬¥”¬«,²T”¥)R‹’Z”R¨¥RZZZ”©e))UeK*Š.J-JK&’”¥¬Z¢¥¥*T\L©KR‹”Z¢eEe%KJ––-QKIU+KTªË*RËK,©JZ’Z’«)*T¥JZKRVJLZQ4YyU¥VYIjRÑe©)j,´¥JR–’–”\”¥)IjKR”¥*R¥)JR”¤µ(µEdÉdÉT¢Õ%ZJ¢–’¥–”µ%©--Dµ%©e*Qr•”¬¥K)JŠ–”¥”––\&T’«*-IR”¥JU*Yh¥¨€q¦beetbox-beets-00724b7/test/rsrc/itunes_library_windows.xml0000664000175000017500000001606715253035401023344 0ustar pieterpieter Major Version1 Minor Version1 Date2015-05-11T15:27:14Z Application Version12.1.2.27 Features5 Show Content Ratings Music Folderfile://localhost/C:/Documents%20and%20Settings/Owner/My%20Documents/My%20Music/iTunes/iTunes%20Media/ Library Persistent IDB4C9F3EE26EFAF78 Tracks 180 Track ID180 NameTessellate Artistalt-J Album Artistalt-J AlbumAn Awesome Wave GenreAlternative KindMPEG audio file Size5525212 Total Time182674 Disc Number1 Disc Count1 Track Number3 Track Count13 Year2012 Date Modified2015-02-02T15:23:08Z Date Added2014-04-24T09:28:38Z Bit Rate238 Sample Rate44100 Play Count0 Play Date3513593824 Skip Count3 Skip Date2015-02-05T15:41:04Z Rating80 Album Rating80 Album Rating Computed Artwork Count1 Sort AlbumAwesome Wave Sort Artistalt-J Persistent ID20E89D1580C31363 Track TypeFile Locationfile://localhost/G:/Music/Alt-J/An%20Awesome%20Wave/03%20Tessellate.mp3 File Folder Count-1 Library Folder Count-1 183 Track ID183 NameBreezeblocks Artistalt-J Album Artistalt-J AlbumAn Awesome Wave GenreAlternative KindMPEG audio file Size6827195 Total Time227082 Disc Number1 Disc Count1 Track Number4 Track Count13 Year2012 Date Modified2015-02-02T15:23:08Z Date Added2014-04-24T09:28:38Z Bit Rate237 Sample Rate44100 Play Count31 Play Date3513594051 Play Date UTC2015-05-04T12:20:51Z Skip Count0 Rating100 Album Rating80 Album Rating Computed Artwork Count1 Sort AlbumAwesome Wave Sort Artistalt-J Persistent IDD7017B127B983D38 Track TypeFile Locationfile://localhost/G:/Music/Alt-J/An%20Awesome%20Wave/04%20Breezeblocks.mp3 File Folder Count-1 Library Folder Count-1 638 Track ID638 Nameâ�¦ (Ripe & Ruin) Artistalt-J Album Artistalt-J AlbumAn Awesome Wave KindMPEG audio file Size2173293 Total Time72097 Disc Number1 Disc Count1 Track Number2 Track Count13 Year2012 Date Modified2015-05-09T17:04:53Z Date Added2015-02-02T15:28:39Z Bit Rate233 Sample Rate44100 Play Count8 Play Date3514109973 Play Date UTC2015-05-10T11:39:33Z Skip Count1 Skip Date2015-02-02T15:29:10Z Album Rating80 Album Rating Computed Artwork Count1 Sort AlbumAwesome Wave Sort Artistalt-J Persistent ID183699FA0554D0E6 Track TypeFile Locationfile://localhost/G:/Experiments/Alt-J/An%20Awesome%20Wave/02%20%E2%9D%A6%20(Ripe%20&%20Ruin).mp3 File Folder Count4 Library Folder Count2 Playlists NameBibliotheek Master Playlist ID72 Playlist Persistent ID728AA5B1D00ED23B Visible All Items Playlist Items Track ID180 Track ID183 Track ID638 NameMuziek Playlist ID103 Playlist Persistent ID8120A002B0486AD7 Distinguished Kind4 Music All Items Playlist Items Track ID180 Track ID183 Track ID638 beetbox-beets-00724b7/test/rsrc/mpeglayer3.wav0000664000175000017500000011676615253035401020613 0ustar pieterpieterRIFFî�WAVEfmt UD¬€ €qfact¥aLISTINFOISFTLavf62.12.100data��ÿûPÄ ,C.U”€�f#:ЪÎ3…Ódñ¡ÁX^F‰å³.Z¨;kðø`P‚D NhÑ£lx€18?ÁNtùÎ_ÎrþîŸw.ƒàø| JÁý j:{qCädh1´Ê5¸…�ÆûJvs08¢f%„Æ„‹{¯ÖÁÓà9D˜-_…¨vŒ(–ÿŽá†âDzÿ䉑x¼b]ÿòé‘x¼‰t»üDDG¿àª™ÂÚe$ÿûRÄ‚ H!!½á!ŠáQÏÔH0`˜x€ ÀðÏÝíLÆ,È"LüÀ„ @˜À¼‹5k¶\êU™§_«ù/Ê·þµÛý_«÷§ïÿûÀc¢ŸÑæø™J!å™ìα™á!æ˜K€ªÅ\ hõ�~�’È (Y/š ŸoËÊW×¹)Öé‹Ó—z:õ-«Ü¯µþã~éÓP·ºÓ·Ì_Ö„Õ€L�ŒL0. €[ÌÑ ËˆÎ ÿûRÄ  üW /ìFÁLaå¿ìHÆ1Œ@NÍ•(É MÍxå²M€Ô0Y¦Ë¬õSo¤*ډȣh“÷VгâFôä÷ëcšÎJ=·ë]V°sÜ÷<ðõFsMÐ$¨¨ÊJMqˆï÷LÀ²ŒÁÕrŒ½ ³ P>OB�Ù��m¤Ö0 À¹ ßÊ|ô׫/£./Nâýhí±¿ñ”»fý͛˰‚c;ÈêNQ›®�ÌtE2 ˆËŠ3RÑŒáÌ«—åL§üL°F€ÉDp1€ÿûRÄ‚ `W .~¢A,b¿ìH ÈKB©Ê¢`$ "tÛZ^Úæ~þî{È_Ê=]3´z{¤¿}£ï²@â>M£(/jZ¿Ëh|¥Ï Ò„™ᨧ�5±ƒ6©•°’Ù•.Ƀ<�ÚÅš«)¤-=I’“§Dn“0CVP_Ñ£ý_Eeò÷É%÷ ½_góýu²u[ÿéPAŽÈ†>2™eLiÊi‚ú ᔉ±“þ 1‚¬  §@É´£4髉:²ë=y×l 7`£»ßÿûRă ô% ®bAG„¡…¿ìHû^ؤþ+ÊH[£îWV¯îè­ú?M (g%&èÌ|ý&0]†rúÙ†p0^Fh!§ítnцÇkÝhx]·òWI\-�ÝK*vÅ*Ådƒ¾§_¹Ý3ºtîeW[wê¹ÑíewѦš0€S0@v0€Å0+Á†0g„É2Ëe_2¸±0]AX4s98Ó£¬6’ á–�µªÛ¾±L»ôpκ—"–d«¢â¬û]µâŒÝ›ÿRßGCÙÝrÿûRÄ)‚ U ìFÁ„aÕ¿ìHÀŸ«Ù÷(T`�™˜:‰å_=!7™šI‡™�¡:˜=€p¼é±¼šs�¥æ™9ª(?ô•Î=|«/¥šíÓÖïN_ôí¡ þõÿýý^ÕÕh?5‘·V*Bâ|À|& Z•8ëéC PœÉR¸²*Ã‹Š½gŒÛÌýý_ÙÿûRÄXh#nBA"¿lHöõÛ_ÿÕöêÿp ""76ÃãÕ�1þ ƒÖ_ü=! Å=‰C\z47S:Ö1£ddž%u÷VÊqù?÷÷~ÏýÕú¿wßÑs‘¡ßôzU1¡Æf£ -Lãj0Es1îbÁ1à„_0;AH9�AÁIË·ø Ð«m!¿€¯ÎúßÖä|5mNÙîñÎú?­_ÓöÓGÿ*(4X¨Î ¼äö$ �GŒö3¸ONG´È.�fLÖÞÌùØÍvÌ\ÿûRÄtô+ì{‚! „aÕ¿lHå@!¹E|w·�ý3%¾×èÿûºkÚBê¿§ü´‹ÑG§­bALB.0á4Äèc$EL ÐÜŒWÆÄ UPØŒ À>ʵˆ®’Gº9Ä< ž¼=–:V´mö~´z»¯ýþªöyd¯¾�_Þ¦Ê%%ú,8 ƒí³ `Š4ÅLcJ`Ž0¥³áã1ƒ pA`#a?+�§_·«§õêÿoÿýï¿ÿïb1¼ÃdÃ!Ì0*ƒ{1B[ÿûRÄ”‚ü% bA„¡Õ¿lHW18ƒm0"A ÛÎv‡ŸÇðXUñJùvù/oG}Úv©=]Ôþçÿ·ó¿ö�¢L `6¾b1ËÁêý;Ó³€Œ;·sIg2Æc!Á0’õÉ©_NãØb®äN©ß‘ûºÿ£ìÿEô}TÿÿB@„bqÁˆ f%O Ž`Xˆb™>Ôb…‡è`DZ`Žhm8DR{g¯Å4ý]Ÿ«ë…ïÆ5ÞŽê¿óÞŸÿü¿÷ãÿûRÄ« #.B@샣õŸdL`T `—0ˆ£0{2`#þØ?~%ð³7ÒpÌHã£ÌY0�*à º•Îß}lúºkA¼ÿ'r·¦B6}õkØû?:å]¤ØÓM”]Œg³ ˆ‰=Ç®À£*bAɇK† P˜æ�`MbP¿Nb>ú`8‚`bnæŠnçlj A¯4íð…kË tö­Ìëw£9]uX� 5ìÕíÒÊjéꋞ,i*ív¥ÀÈ€ 5 ° LÿûRÄÇ„#BA¢%¿lH€$ 2PyÍLC°MD0L1à7Ž–Ï4+Ê ×L.g/#§›¨ rÑu¤)í¥j´¤†¢n­ÊiÅ-uTVʤîÝz%æw¤£šçÚ]¥û\æ6÷šï¸ÎÅU0À`0 —0 @ü0÷03F1€/1tEü0#Õ3¬#x;PãÖO8 ±ã&+ œ¾¤fb+¯ ÖýÁ]ÞÝÄ+7ê"N—4ƒ}Åb‘î±,MûOL&í‡X§"õ V¤bÿûRÄá H#ÎbAg á‰îØ„U=x c€ˆj‘5› QមêaâûÁÑŽˆ6�ÃQ 3ûI‡b r¸DÕ=¬n¯_Cs=7KÙïÅU?º°l]v·•[ß±æ WƪÄã.ãëU0e D90¹pŠ3Ó �L6XÌ4aÌ�N ¥üÒÄAܧ@ª" {§o‚ Y½Býtª§ÕßéËÑë¨8ÊS¦þ‹X‡ÿyþº³Ë0ÀÀÝ„Á’ÐáÿûRÄí ¤#ÎbAœ áþØ<×è/ü×S´Ã–Xï.I·L˜â1nTÁ§‘@wŽMÔw]©Eëʃô±H=Ç´¡ÊÜ$Š®‹ŠCË}n¹X©v�7’zû”ŶôœyS¨uÛ‰"I *b’† ¦_s`-‰ha�I8a‰D`Ö>M—ÀJ$  €s4$¹£§èPöë«çÞõ©©ÜÚŽS­m¹ÌGé^ék�-»aè§3Cƒ!rtÛ‹RÒÿûRÄì‚ èWìFÁL"%¿lH%Ty.2£ ÂF¾|’a—j†�TjDTa’�JD]ž€c–bÀ`µcP�0:ìûõçÙuýç÷¼«É¡Œ\Ô7#ycî=ÚçÐ¥»eHºÖV°)±´ÙXݪ<¿êêu=àz€ `O0êÂMÓ ï AYL)ztÌ'�TEA¤,®@Î"ðu z‡�8J*D±]*µUtR½õ.³ûØŽ×:�Ö»2‡{ñ—½�:u­éOm1ú¦LÿûRÄí #.bA»ŠàÁþØéÈt]ã0@Úm¶ $,ä{Ùübn' „Vpnæ&@P|[™×fà‡èé—¢‡Mt±ºþî?oÏé™·×?K™>ªm¹*EU Öš£TÖ.„Çé¹(Ñ]Wù‰H6˜|Á˜â])c&¢U ¸š¥±‹ƒÑF³JœÙ=€9Ƭ­hɺ’í`ÚSXyU8²Úµ§ÂÑÐ¥¬²1oÞŽÐg"oK誚˜d�"›&e!i¡ÁÄ\ÿûRÄë‚ �W Î~¢Aˆ !ÏÔHÊ„L:`��¯ w€% 9p#Àî `4X ^ãf#ÐL+©@êlûßË…LÇ{õ­*š‚ 5Öëcí‡Päš<8ãècV=a*L~Ú¥o쀮-È6dO\Õ#Ö©±¥ÓØ•Æ"H' ¼Ld°b¨šTÀÉeŽ.z»s»çy—;%ëwö�Ó÷èÿûÿ×AC]ÙÑc—싳p´Ìp @@ÀÁ ‚a˜€,j�¤jÿûRÄæ (Y .~¢A=„"õ¯hHL€a�ÄsÕšVæa ØÆ (vl2Jø}VåàÕR²ƒݺq«U¿›íÿâ]�º—VCÿìíº˜|vw»®bŽû¿Í&º³\?ÞFØöÆ¢k“QäÔQg:ü3^žZD“�Œk¯�83˜K£VLcXJÃ|Shª6ƒc�¢f ¶i=à|¾õ—¯£¬ŸŠ�Ü‹hwêi¥*íoÕ÷ÌÎ %8p€A(Lœ¯°’òˆ±vÞ ZgÿûRÄï‚ ü# ®bAÀ ÁÏÔHpÁ°ç_ fDš£"¿š’@-˜cà%�Î@f% M‚ì@h j5‰S‡Sgkõg¯_ºhž™ç‰©ÏŽBPýóÍVøËH�¹ÙHª>ajEÜb*¢ DLâêäÚ„³…—p±D”*H°ÄEØÀ$fL/3¤ÂìdÌÀÕ¬Ó ;ÀóÉ£l×ÌÏ×¥~‰ëO{7u#+ÿ?Óÿ·{vWSÿÛ1gýb„S‰ŒÈ58XæÓ  CIàqÿûRÄå€43¬wB1׊áþÙãH  Ø@8Yô ž™)f…p¿Cä°u µ««˜­bZji%äµ¢ÍwR(ߺRµ-ËãôÜ×I)Kq~Ó-*›�åkŠA±é!9"ö¹ŒÐ `$€ þ˜ƒƒwÂ�ƒ à÷�GqË/ )íÆ ŒØä.rÙÙŸVÖ µ¦�Ž~ÁèbEòq�Eë'EO(©*ZÅ&co6òÍ\�„šó˰c¯NÚZ¯UPˆ@ÿûRÄëƒ <# NbAœ !ÏÔHȳ2‡�L!9yÂÄ4Òi$ÄÑò¬Â³, t$%5J ˜�JÁ�Fx¢qnÝÕó¢U¢\†•¹Òú4b‹/L¶ä „º»=µÌúâñzØ_u�ãïF²O0 S0@�0@ý0�ú0/F1G/U1AF0<�î;?S›g<ãÙC8Ð2#?Ÿ°�þ�›úN º¯öæÐÓLâ)—®åÕµ•÷X¥(&{öÜiO×ÜÒ‹DþpÖ}÷ÿûRÄ錭{"a¡‡áYÏÔH™EÊae4Û1á ðzý13ƒ…e8!¢±*<èÌ{2G@Ïac.”ΚgF´ýOâ¿Ùö½U}6ýù�DJh%rnCæiÞØyµïB"•L*6̺1½üÀ¦°Ä£‘ ÄŒ€ÀÏÜã. É0ãÈ΀èÙ…ÜÉ‹yë¼þ~ÿ÷ö=MÀUæžú˜ù ¨¸«O©“˜°µ¹ËEj7gJmNåš&c¬/_‡xçUJÌ =3ÈÐØÿûRÄðƒ ðU/ìFÁváEÏÔH3¬ Œ2 qÍL3­ÍCàhÌ0°ä‡`2R˜/@ÄõÀ0ɘ,Dc‰“‹v}ý”}Jý¨ÝŽL�è'$å­5µiëÇ™`lÒ¼óììI‚nAM"‰â�Ua•¼ãîrO(ÞŽÀÕ0AàÀ\ÀPÐÀá<ƤTÅóÁ ¸ëvN%„é�åTÝÂGˆ‚~Â-߯*ÿ¼~á½oÐ×Tåd§íeÔu96þŒ¿®BF¿¡T­nôÝH¢XÿûRÄì `WìFÁ.„"é¯hHËÈ |ÞJ�y|ÈDU�{,øöTOŒ€\îPL•”*èc&vœÑ×Pýë-Z²~tçÖŸ+9s(ý5ÝCégÞëò¨ ÒhÖ‡Ü�cKs$‡œ˜P™€:a`³�c¼3�`#çCp_CLÓÒþ:ƒÁG=G#ˆ/b�¹ËgeÙ¸7J×±GÝP„6ÐÜNòW• tzn‡ôç7Øj>Ö×JœuJ PbÎ ‹tK²a1ÊqÿûRÄò‚ ÈA .bA�ŠáÏÔH2ŒB �ÐÁiª•QéÿÀ- Ùýÿ Ÿ­ ’8´€bƒ  '€…ÈÁG(¢qnÞ¿œì'¢Ë�žÿFÇþ»Ë1Gû¿pïÙ�Vï«ûU"L ))U:dÊ!�¦ ‹ˆù9‹J¹�Ü ÅÒ›*i¼:y©ƒ�<ó–Â]Râµíöò]‘.{} ìUVw—›Aÿ/mú©UÉtÓ÷!ÎçØ�ʤC<Ízb:ƒ ÃÿûRÄé‚ ôY ìFÁM„aÙ¿lH ÔDQ(Óà €ÂòŒ"W¦ÀÂë@2%L XcÀ…šCŒTÉ7_]»y‹©zàjŽ+yef¶·Ü¥ Këu¢Õs®‰ì$A#Æ -Žä ¢©jT¢4Þ Ìª!VL &”L4š2­ÀæØÆK{`Æ(¸Á ä©�™@ÞLNXÔ‡‚ÞIûÂÙŒ<ÖëwU5ðçÝ ÛîØ6ý¹Š¶tÇ{ÔcR÷°+Gú�W˜…c0'4r£ÿûRÄòÓœù@ PQ.U¹>"9š‡L(ØÌÜÍãàÁ5 tÈBa\È dÁBçdÍm\×���ìÎÅÐ2–‡#ùýõ¿‹ «fÇxhº b�ûì{-ÌSy5®^ù“RóujF­ jÚ¶ ƒ‘·|c#DFg§†íbÿûRÄð‚pYðFÁ ƒâ¥¯hHV:loæ8F#@ÎFxª”̶5žLÁuÕÈíÔg-×Ü9ù l½I·Îh_¾´\nÎQm˜¤6™ùõ üß»¢F9(FX ¦€ÆH5¦€¦Ft=†q€¥ÆH8g …±PjôI­�†rØ$?,§rÊ"wà¹;ùlM�SÄ‚q Ë¢•xúëÞt°q+ê{ÀlR1¡r,•¡áC51v5!á€7¶“ȯôR¬dÿûRÄó‚ tY ¯ìFÁx„!å¿ìH&ZXhɧL`¨VdŒ¢Ödn6`ž�b:Pd‡æwdcŠ[¥={¸ß[·½ýüú»t«ÿßÿÞ®½_ô¯«/Ò�U @10€x0"Àé0Fà0¦ÅÍ4K,±41ÅË0¬�ü:¬ÔØì“c)�Ÿ4<(Zïľ�‡LèÖXZv6Qb†Öð|£–Õ-L,>“O‰­Ï(ñKÆ´ˆQ"«ØJaU=m4™T ͺõ$Z5s -M› °i‘UXÌÿûRÄð‚ D!-ÿbA6„"¥¿hHÍ ØÜŽÓ¬Á± ÐËŒ]°ËA xÁ–ìÜÁÇfz¬k¦lZ€èv˜ê“Nu�Öî—&ÞNÛ.¶ß~&Öú‰GÚÞ®›\R�]ËXáŒSo¢LtëôÞ… PÀ!ÀX@À»ÌÁÈ(ËýuèË´(ÁÙ$ø1�òÞÚÍúøÓ ƒ‚ÝI}%³“to‚Uþñ»×Ü;'÷ä/ú»ã»ÓMÕÇš=S»½‘ikÿìE¦`%ž`-€Ì`BF`ÿûRÄú‚äW¯ðfÁ"e¿ìHu‚„aþgP¾Òg Êa‚ rƒ¦ ˜kާØj¨®4¶ÖåÛøt_æ�äm‹}®RŽE¢7 tnä—޽鱛Ot ¸ÄYrh[‰‹9¦I9ÏmQ>µPªª!˜pld󹩠F ØgfVÃ%æT¸gf @"Ç‹VmmæÌ¸m5&zN_‡î’Ø ~׬¥hÈuYÉÔŸ+?¾Þ¬¬t'*³öýíŠi5½1OÐ3 ´íͼWÿ˜˜¡Œ™Yá¬ÿûRÄù´W/ðFÁ_„!Ù¿ìHD˜sŽ¡³§c%Ž1†°7šðAB&u!®²f²ihr».5|‡’ºÜ¶ë“K‘èïPWe•l Ë~k½T1 ¿ßÖ  2I¬ÓÍC›îL-ÁV�-ºM�&�VŒ/wÀì“6#H v·_N€Î…€ˆ AÉÂ}47¯ØòWekSœ0 x©Q›†ä.’g"ÂÉ<¶Þö%æDÍ8'Ñ(›êØ×¤H�]…+¨Ðl’ôD-=JD­ÂæX/™œüi&ÿûRÄð 4Y ìFÁ—ŠáEýˆØI¿ñ† ›&}̽&z€—fX)€iaølœz?�¨àf²0DìAM–ªOë¼Ù½]#�Ö(õg{žZ¢{g—Ü�ÊK‰Îb¶´]F/2®«VÇ­úF"”;NåÅ‘  1±Ï)sxPŒ#ÐþLLèÐþÌ$ X"ã4ŠtÐȃC¼Ì¢A5øÅ= e1kNÚÚŸ…{-·ïæ÷»”½ŒK+Æ!� Ù›tµ÷ºgg¨YõÜâ¶.LjŒÊcÿûRÄî Ø#ÎbA0ƒâñ¿hH1ÁމæWAr`¾†¨e"4˜dÿ†€`¯ÂjeNi©Ñ:h¢@OÍ6?úÿþsÿúÈ^‚>Jÿ][‘5é§¹†ôé ÒåÌPEŸ’õÖÔýÝ×}ê"e‹€c¤f”°s¹& RRzƒFP€R h'ak Fž®iÓÆTH•ðå8&~ÞIžýÈîíÆ%¯¬‰}»êÛÑOÞµwSþ”Dd•NÆzÞó˜3Ì £xsD ð]ÿûRÄúƒŽ¬U.~¢AŽ ¡ÏÔHSBöÕóA0[3 $ÃIÌnJ4âÙq#C“BÕ­˱2ØÛ%aOþg÷JkèdöS]:ÔËk#Öýö¾¯©�NºìG«$ªºÆoÀµÏ&YH3|ð½& �­¹¢¸‰jz^88¦©j*È×оò3ŠK)"Ö6haÌ5xˆñƒE.u§­™¼Î²gXUx(ÊÉMyxðuÌ ­ŒÄ•MŒ¿À®Œ°=OJˆÙ�e¬Õ0Œ¸Á ßÊz@|â¥wdôÈ~®øÎï§9Ò¯¹[Õk´ÔÅlŠyÕZß|n„ €1˜  DÿûRÄï P!-ÿbAÀ£`ÁþØÀo˜ Û?‚ª™±´Å™¦œ˜9à¿Y�–ƒ)ÛìÉÀa+&ŠÚâ6þëó÷ØßnñZá!%­R½VŠ�ž+·a2Š®éoÙ{G=ŽM/ŽZÞ&ÞqÕ@!Ppæ°F¨ & †_&r2äæoˆ_æP"ëvnñ¦Él<æjz]‡þQOHGûù›Vëåúûm¶õµæyöé]»kG’ãPZš^µ—iõßÖ³·F�räÿûRÄë‚ \!-ÿbAÄ áýˆØä™¤d£¹™XF°Â˜4âakR“a¢T/€ªš+!› ›úqÐX›AXpÓk³Ÿ÷ÿÿÿÿT]zŽÞÛÚ[^›ŠV'Šê攪}®×cÈ~(s«:†TçíKÖ­Ý #*úÑ Ë‹7K�ÿ³á¢8™Ñc†A¦1C †b3„ƒ-C2¨brŠà™«¸¢QÝÇ;�ÚÎÆéI…7jIÞÕѦž”×î¯ëÙœBJcÑ‹=Æ€¤€ªa€àÿûRÄç‚ ä#­ÿbA‘ ¡ýˆØ9�†1ƒ˜,I˜§Xi—ø+iƒ6 ‘¡?šHÁÌ+�þ¾˜²h¬÷MÕõ‡ú|oJ‚°ë8t¥"«»µÊÅÂD 5ÑLõ*”ºzò÷\§›JÓsa·-Î-¨á¥üÀXÈÀ§Á<pÂéÓ2lôÒ½<Âì@éoSN°Lü´3½ÈeÐ0­Æ%t„:?oêÖ³¸Íú+§ßzÁoÿúPe Lƒ�š¢�ù‡ðz¿A¶�}‚©â|h™Uæ;s·P,”«­~GÑ­ZÖž¶ö£gÿq3½ªÿFÄÞu¹›ûÓ †Ð¦¨†0#fHEF €ÕæW>xfTÀÒ& ˜?ÿûRÄõ¬Y¯ðFÁEãu¯dLkÒŽsÄC>Úƒ�(9YК>®õEº¸$f±|ÿ¢�{¦y_¥ê·ñX…­[Ö m¿ž~ý�”~GþÍã‡;ìÀu§LªÂ_o‚¿È¿ÿn‹þI¦ãøùqB FTl–r%Á…ZÙ£t’¹¢šI…T€…†}S�•”@d™(”¦ Ôr`ÌÁ÷ù}—·¦£÷\×âçë=cÈÝ3g»Hå¶ææÖ­œKWÒïd‘¡Ì_™‹9ok{R`%€Ä`ÿûPÄï‚ ,‰¯ðFÁ3„b%ÏèH!*`'�ì`AÒ`Ÿ‹Ôdf[ÐdF‹ `‚‚ ªÌ:Òã΃8aÑbåû"¢éҔ׈6ÍÙÎ8ö®Æ¹VÕ°û€zÊýíf�·YMŒÅ)b¡…ã6Z9uÕ-A[Š“È¡�@ÄÓ+‚M8@9:œÂ²˜ÑçC0ÑxØÂ±Œ@¾<)€Ê*P2  9Ù‚iµŸveÏ·«Ó?÷s»¤aÌŠ‘ú$Ö‡³_mí+^†~¹‰ØTÛfLiSŒÿûRÄñ‚ �{Baç”àÉýˆÙTñ[\ÆS› `¹2�ØÀÖTÆ'ŽÄÅöÀ©`Á`ÀÓg.sjFÆ4*ßNß-kås97b­eÈ=_Ñ9fEê×;ZœƒÃ.áÕŠèÒòh}ÔKüBoh_zìT@A ’�BÆ (¬ˆÃŒ'M“•4Øœ(Ì8€àé¯2êL2c\..¯¡c:6$êþÿÛO}¿¿M_¥?¨jý•ýrŸ eL°Œà LP6 `lÌ ±QŒdª>ŒÿûRÄî‹üY .~¢A‹ŠáýˆØa‘L @dLj€ØŽdPí•MØ4x‰ È¯g"Ùœ+&ÚÜ<¬òfì0ûZ…˜Ê�OIŠ¹æ ¾.y‚ ܹKR@-rÞÁsb–ªƒ(@ÄØ™AF¦×9j"UL€ %Ì"�Ä Ì™ÿÖö�ä@É„*Mðš38Ç(óA FNxn¦g¾‹Ö öÖî.í]¿ %(<¯Zf«q)ÄFIBdÉ•£žSòÑës}†B¼ù €1ÁÿûRÄêƒ ðY .~¢Aba…ÏìHLÅh6Ì“´0.…O1aéA1V…;0 Á–2ºse9 Ó¹F7paâ…!¿Í÷üÿç×|d�'‡Ò$Jq)JP§&r6|àyCãêºÕ_ßEç‘~’h-|RXJQ)õY}2š@EÃMÊxH:¡öx´ý§�¢c rÚhlæ@Ìb8 A©˜aë”"¾K¨Šþ­—”ÅÞšå{¤þI¬œVĈuP0ÇÝwïµC  %ÌÿûRÄ삸!­{BaÆŠ¡IýˆØð?Œ`~L Q† V+Ð Sq€ŒvM Þ‰Üõ‘N0xɊ¨³_Gö;®Ú!ã*„¾ê_U)câï&ýé©Í– ¾û•[ _È 8Ô5fµg‡�0é»ÇÙ¤Îõ*1àT¬Þkàñ×MfP.F§™h†£€1†àt† ù|Ca�‰«À`£0YxÎæ ¦Ï©L�s_¿¨÷h«•­»è žSéL2(ÁfÏãÛº²µ=ì45×¾366˜¢Y&ÿûRÄî‚ A /pFÁ”‡áIÏìHdâ1¡t¡Íu  P© ³oC—1ͳ!‘ƒa‡Cd\ƒÎ‰Í¾fÛtîÑç?_¹ §ùí~º{»î»Å ±÷Ùü—“@€š` ¦èæ � *f¿±G¦».¦°Çwmš=¶dgˆòæ=Œ™ü7PŽÕuu\埡 ƒï#QÕÏPlµkk?2#Yí+è�Õ¶B¶Këyl•L÷ï³]½iÜÈFô¢=Uø96åÊÓ4qÿûRÄé‚ H#-ûbA“ŠáýˆØ)v±`cq‡�&nkv`(ŠÄauS”afŠœ`FT[œ€µ tGˆ,&\òkRé_®q Ñõœñ¾Wkç5•1|§Ó¦›)cÃúï CùúoM:º8ûÑe2| â_¾70ÌÔ5EFt5$ö0É@—¡-€Î‹ 1› bÃ@[qxG˜&še]Ùs¿WœGB—@ÇupÐ�4Õ«­©�R3Ϫm,bŠËØ‚FG­î6ÈRÿûRÄë‚ ¤Y~¢Aƒã±¯dL1÷†uMF·¥€:aI2’ ŒN3�,,f ¶ª`Ì+‼eø:äìñ5Ÿ+æU·VížÏÔþäÖm[hïbþAþþÿVr>õPßÿ&0@*0!€ üÁ”pç,Ø4×yäÖXî,³AµÌdâ0>\TöHlrIº‚çïD«gB ±P<Šé%”}§ÚÄð–ñ¥ã¢ÌY*. Ï+iž¢”˜QÍ-r®s<Ëbåë ÿûRÄöƒO)a¯ðFÁiŠ¡EÏÔHVŒ**0!4Œ’’‡<`,8°`$‡$`‚.o¼cÁ²Èö“‘+QÞÌ•ü"Î,þ¿ì­òKgé÷³ÑÒ�‰×�©ËÝ?‹±…Êë£e eU010"@‚,X8tÃ`D3]à\Ó¶0 øÔ1KŒ-–=mŠK1³•Þ‹n?³nñßêô�=š²|Pt-s’M:£R±ÑIWÐ:ÀÎó³W!'Ó6ÁB«JÍ¢*’àæ.µ-׉”¡$+ÿûRÄê‚ ÌU~¢Aãõ¯`LI†f-¢ �€&!)�©Y�¶ ¹€ˆ ªÈš¹X À$\š¼ 1󢿀F´a¶#½Ya„)䬒ºiÏì~UËvÚÈ”¹¥m†LOlz\HU/>PH�Çå:ßùµ!$L¤PÑ�@Þ@<“!ð<>@0cÞp2ãËc3·z ç=[PMË¢ ¶Y·POKŸ§­Ò5/½S ""x²¬Gzö\ÏÜî¿�û‹æ7ù>Å·dՉЉnaóf—§½þ²ªŸv…ˆ0 ÿûRÄò‚ PŸðFÁp¡ÙÏìHU0@’�þ`ø`DŒNaà_"aÚŒ*`aÜt½ç.ºxG¶V &0cð‰û:g½ÇÛÜ-Xˆêv­di¶~xóÎ4û†ÒIac×™¨ÁÞ¹«£®ò¹˜6°�åê­ˆGp ‚(3 tÔá×L,P= &Â! �4Œ+@y2Z\¤04ÄÀEt¶‚f«èËlÃ4EF¸RÄ÷�ÈÞ3fC©ÙC®»§Ù½ ÝèëgRý6ïñ@1%UÿûRÄí L#-ûbA¸ áýˆØŒ& ÂÈ£ ÈÌÀæ ,׌,ãŒÐFÍrÓ‹�œ<Ý# áö3 ZÌ×­ÚÜöý�ðß�ýæÛ¢ÛôÕϯïU¨âËM¦>šêLAMEªª!ZL¨lÑÅ àdøÎŒ†ƒ¬ø†ÏqƒDIÏ8Ëš†]Ì�ÀOŒzfãLÔ~ŒfŽ¢ÍÝ­éŸjgÏ¡C'³Ç¢iJ>Uý)öÞÂS$ °B«À ÿûRÄê‚ $A .~¢AžŠ¡ýˆØ FTÅë1Ì]FDÀÈ ÛÍRAÞà�Fæ_ãÙXíî÷{¿%oe�w~˜«vcêÿöQ/ú:êDù€¾1�é�¾Qƒ‰‡.q¯h€®>1†üIÔÑæ]bŒ¶ŒY‘0áä*n1êf•µçp¥2/·AŠ·®uïû!ÿHóÍûNÿ0­¢™Ê»yW+cô©•æg�ù¯xŒÒÒ¡�â{æT“Rç õF÷äGâl7ï¡…ÏçÐb2p�ÿûRÄè �% .‚A?¢%ÏìHagÑ–þæÀÂ5ÜÆ4ÀF H=ç‰ôs΂z{ Ç4^Å!rÊ|ðÿçï¿Ýýϱ°PÎö?Wk—ÁœëP¦y‰ÉaɳI%µ&›˜ÑÔUdëÕU™e)JéÔ*b2€ôÏ#ƒ_β’0Ç�ó5+P5 �Ï0ÁÀ&�ÈÊ@]�‹k@aÓ XŽ(™"í~­S7íÕ0;Ç ¥K3OMÄÉÑÝÈ ZÄ1¢í€\Äô$Í¥NLÃ5íGQ£»ÿûRÄð‚ \#-ûbA „#µ¯dLÞí«0€2šL #%#%c(á�:IˆÐÝ9ˆ¦ �lÑ·Åš™Ù³™¨ <ˆ9oZÈb�ã¾äîÈÑÛ;ó»#?BZS[Ô•¿ê~©+iý5Õ€ ¦@3Àü×åCª*L1pŒ�H$z @„ /àÀãfP1ú„ ¸UÀĆPmá�&ŒUVýuÓMmGÜÁÞ„¡Ú’j¡ö–xC{ÓŸÊ“V�ŠÅdlmgܲ/k§F²—<}[�ÿûRÄÿ‚]=¯ðfɃˆ!ÏìHô€àÎ``¨1(èÆgLÀ‚Œ-ÔŒ,À� °&ÍÔcL`؉71yËøû¨©_T�Jêù[€Ë}žõêU¹U^úݦj…OpÓeËã$/¥P‚daəǢ(œ•DaVBh뢖h²aK€˜î&‹�À`ÄèÞL#*uG(™8‹³·GTúLŽªúѼbir™zo—EåøDRªV¦=,ÝÝBÃ,—R “-�·¡…“zÿûRÄë‚ pU~¢A>„¢%ÏìH¥#@±FH&�5F h¦&?Ŧ>h¤¦ p5G‡¾q­çHŒv®ææ*4@Ðäöú*|J¯÷ŽÄ$y+©Öé*•]iêîa:QܯkPôVQw¼1¥oVÅnµ×«§‘$b!QLœxΈMŒÈîœLpF ï³,ŽçÅÐÆÀNTŒÄSÌxÈ/L@½a¢5‚B3#¸¦ÛÞ‡-ÿÉjÝ’¿ßGÙÿÑÔ¶ªŽÎŽ¥�9€À$À ãüsÿûRÄï‚ W.~¢AJ„c1¿èLR#"†|!ÀQƒœ“Êà8çC¥M;(#po"ö-�:'¶ŒÞ£¾Ñbúë^Þx”«W¦ü$ˆ8¥Ž›JhKŠ1³®ZÞãmã®X}ù&„H`¡÷³Rê€ ¬I3¹8×3¥¸Œ/à¸Í>uÆM6`°L."B1BHÄË*Ó n`-+ZˆÖǸÿÿÿòúžÔR~òç5¶Ð͇YrY?ç6Æ4œ\�in©¤hÜ9Imî`ZÕîfæSÿûRÄð (W Î~¢A~ŠáEýˆØ'2]˜Üc–i¢´ ø¢fJèæHx¡& ð4‡§Æqï'D¤v1¦Þ:,8ÛÅ%ö0ßþ¿ÿÿ\RéÁ7q+ýO›×±éþ’Ä®ˆßnmŽ¥{ŽuY†S{ïñ¿¶"&¦Œ¤€Î‰Í„øí¡ÌmÇ(ŽÖFØÆ�Î,TÂRLEhÊ­Ì`µSFk“i¼"Î?pÅ{²,bƱõ&ivr�ºÔæè£í)ªƒâ´S­ìPÆ ‚š¡,ų�Œ2ÿûRÄé‚ $!-ûbA¬‹!aýˆØc Õý“¸[ƒ-ƒ,ZãD~B P’5Ù¬ÙK@ …l’/9Ožÿ¯Ïûÿ~¡¸kH¦ùÁjŒo ë’i�Ju)Ê�‹ŒPæ [gŸ7ѵ3iu5|"-´Š;…`:0G3ÃsU>8FñÄ0Ž…3ºÔ13¢‚k0‡À‚;aƒ b2GÓGò2Ô»T¡Ä@C2Î5Ýz²€÷ôÛïÒ¹ý˜û­×)»Àv³<Áèéõ{)j-@³A@¸xÿûRÄíL¬A.‚A]‡áAÏìHbS阡(iæ8S:¦7i&°!Ç&k)æÄlml¦~4Î[‹å›v‹PðÕÚ+vÚµ;å3m´¯¿ÞÚH-.œãkΕc¶©ËÜ:TÉ’ÈFb'šdðq™…q¡|Âq ¢�„ÄX4* 8��QÀeȘèš ‚…ÊM"¦®ÕõÌR]_v=Öo‹½ÕÆäÏH§–Š-@ù?M°‚E }£(®~ö¥Ç«¦ \mSzÀ ÿûRÄì‚ P!-ûbA�áÏðH <˜ @pàå˜)n“ç÷zÿÿú�ì]¨¦ñùÑkjjþʽý>ÊåËwË¥û+Iv§ÙÓ@’ÈÆ`+šM phy„Ò PÖŸ‚!„�XEì*g2Í“!AÀ'&4r\†CÛjñÝ}�ZW5µiSÓu™8ª-²Ñ%|îc¾÷úL2ƒVõUI�ÿûRÄò‚ Y ®~¢A‰ áþØ&@ÆØ7&�«n-)k ªFh9g…±Dk4¯ÆvÙ$?,—œ—¥tˆèÉ«‚³[oxäTeHœDatìõ¼3R”½ãî=bºS{ÉЗ¡ôõ0�ýs p‰F´c�©†cÆç&�†–šÃÎY«‘˜[�ÑE’AÆÙ•�aÃ8´ØïBw»«×R¯Éþý»þ�­ý²�ü^P ´À(°ÀoDÀä¸Â)ôÎVÿûRÄëÌÌW®~¢AV!AÏìH¡ÄÎäÂ@ãð³V©Í`†5ˤÎcÐ�'‡%ô€Ý}ed×ÈƒŽ–�¹(enÈ<©è°uYÆ ²‡;ÛZœÆŸ†šu¨H¢šè.aÓÊ>¸�j0@Éi¶dÉ£fÅ¡âòaþ4áZxmº2FÀ¶-ø�Ù•Ti²™",Z ß¾ªˆéпëú5Eÿ¹{uÏ_¥J²ìÃ÷XjEVóÙMï¢À€dc“Ù¢‡ò˜RBì6…ÿûRÄëË0! ®‚AŸ áþØBêU ÿ�Ô¦€l†0%JÐŒ ‰€+q“„úlíUî©eõ3kyöÒ€û\ð©'­å¶%NĨê>\¾· Â¿6|`âææ �*Á Z¦Xx´EC•">r$jL ¬ÍN Q|çqŒÀ£L£uÌŸ žLP'Ù"30K4¹Ã-$Gz”ò$8£ýé{×b®ÓöY»¶”¸ÓoÒ9-V5wÝÛ?©Š£ôûRC,¨È<ÃÿûRÄè8!�{BaŠáþØ£%ŸM= 0bCY2™š2‰ÃW0e�<³km6…ƒm¡4Q îYl4±.\ûš²„éBH^˜;Pú¤wËVö(± ›uŠÜfÖÚFöÝýì{šýƾ¶UT‘’ɆZ2š@néù„b¡�„ø¡œÂÁ„Ì‹y­»y© „5Ùu/ï\þþÿÿþÃÔ¬ž»Ù¥u}*{ŒkoîM‹¹\î7c$UQ´µÉxD­ß—/Ò]lÉ£š…ÿûRÄì‚ °­{BAÕ àÅÏÔHŒT´ÐŽ7ŒÁ` `ÉkY8É0 `ÁmÌê$�apÕÓMb8̇‘§ßW4¶kñW¦¦>Bët¶½ú>ßÕ²ªÞ%í”2@×çÜã©Õ7¸s;tªFñ�ˆfK+¹lxñƒ´™™2ᘈكvQ¼˜)á¨0›Ž1¤™»Òܜڲ¢ü³i(2¹“’uúòï5ÔŪXÕ ç‡X›u«¢Ž/cm/÷j]Èè€6`´`C�r`…ÿûRÄé \!-ÿbAyaåÏìHa<‰vh1Ih‰vaEDsXIªÖ¦¢M–fRX8(ËáÉ}‚RÛ%`Iú*› \’n¬jfmûÈ3³`’ú™„«å_ìòVØÚþ�r.þŒ’«ï_Ûå;­O¹�–ó¹6ÐDQ•LF\Dš¸mÍ™„ *Q›}J!šÂ)qƒ¬ Ù²´ÁyÇ´¶é»†2XµŸÞ·ßý÷ÿ_Z¢ÒnX«Sx 5‡”SEéKìNµ*œÖ¨~Á‹fxŒ8ƒ‰4Uäƒ Dj ÓÅ&HéLõÂêŒ82ù<× Ã®ÜÌÿûRÄê‚ Œ#bAa"%¿ìH3 �P8° H!"Œ3°i@îÒ 5ãp FËOXËÆ` ‰@�“ôÐuUo,²u}Œ�îzžP£‡�2Ñ$Œ˜©÷dG}çb �µBë!J yPðÃJJŠ©>R£©S1‰Bñ‹‡&3*!hY‚ˆù‘¾ã™‘@Y‚JðÀŠ#–‡ gT $4€£$U>Õëþ¯þ}ú{_™ÇÙ¬Š_fìvç}=w)�¼“ûz¨€À˜ÿûRÄî #.bA4„b¥¿lH€`;˜!€„Oa¦š Éš¡©˜P™u®h•)œ“m‡˜ü–ZÇ.1O�Ów|;h‡æqý}jØÿ3‘žU½6à4Xš$¬b—V† ¢„Š®Ï*¤Pb„k¬¡TÕ0Àb0€�0Àä01�Å0uE€3"*Î3 Åd0h�‘4wÃF9uƒ¾Ç7Ã0ÂfJ­›¶’ §ØòîÊY‹"§!*¦<Õô| •Œ®°›ÒñŠñA‚Ý4Ÿ_Eý«Ø"ÿûRÄù  ?®bAÈ ÅÏÔH¼�Ð23³fN<Û³¨&C3•+Ã2P&£¼ ÓÖœ6'ƒOq4Œã$4H¸bž >é (V‚~Fú{½T1I¢–îIŠ•¥Ž»ØÔ~E=qCÓÿ³�È{UŒ°ÚQ¸aB&žh;¦ ü`:‘ÈYãpeû=g¥œk¡^Ýwû7z;¾¬3¢¾ïµ6tõ»þc¶õùÄŠ •G€70€$0$@g0E€ì0¤B÷4@— 4&ÿûRÄçƒ @Y®~¢A„‹!EþØÃ0¥8ûDЪs4' Ã1©<¸ŽÜ¢ž¡;Ñ›†¥)Ü?{=”¾­õ®Ÿ¹t{!f:ÏnêŽù™UŒä^ßGZÖm§`¿?^›S\GÙksŒµ¹ªÜ�}/OÓÃ}À Td ±…a ˜Ö†‹éƒh×´mšxÓ.xU�cMÐŽˆÁÔ´)Ðå•kz»}Ÿ­ÿ¿ÿ{Ý_±j¿˜£­:ÿFÒ ¤Dq0 ¦x&@† ¸%&@tƳK…®ðÿûRÄë‚ 0Wìæ�Gaá¿ìHv†X-'~‰ÉÀh¶¹Ÿ/FF8 Ê!¹E8¹•×…!©ìÃEÅFd|ÛqŸëî_ÝïäÇÓoÿ5,à� òOsãt—Už²âß}Y¥Ã﹚—àúî�>ÏôîœÿÉßíÕ€ Lð 3̰g BÌ“¹ÑL�¡<Ì0] 2"Xã ζ(ÜG…‡[h­üRËøsÛ^ÇŽ[øÝ1ªµúW³e]oNŽÈ«F¨·Â]›´&ÿûRÄï‚ d#­û"AÙ#aYþÙ½IýbÄ#( .W8ó8£ lÑxQ,Ñ œÂ¢BÉ@©ÀËÊ2œ„ VQ r`¾`‚wª‡Û¼÷ÿR= âöýÅŸzt;®ã¾[¹5÷£U˜Ý¼íá‹•"LV:11lÆi£-OL�ú i§§Œf°õŒ @GÄ,DͦÒH$z³ Yì{"®ø¤W¿°a»k+éÕÑËÙl•j°ÎªR,¹f­í, EDZ BÚtzÏ:Â%Õ†¬zë[9âv='ÃÆ?xô5ÿûRÄèKlY /ìFÁWŠáAÏÔHŠ.|hÀÇ r’†K#âQægèãúd¬ÆûR™¥dDaŽ`&"£Ãï1\5Q]{5‹ÙÑ_Ò·RvŸÖ¬eZB‰•ÏŠiNe³r Õ >jæJÎâ·Õ0@b0•0Àø0�í0JEô2®02EÚ0;�Å0‹j:òƒÐy8�‘båû ¢Ìè­Ú˜&Z}ÁW‰œÙ-¡»h°±—³ÎeEƶ¤GÚÚåŒ/±åÒ‘lû\ÑèÇ(îÂÿûRÄí <#.bA:"e¿lHsã€0 ˜$€ „0€„)’ðáæîqûPè-…Ù¾”dGc„ˆÉ~úJêfv~Ÿ)ägÔç­ÈO} Ròô}TPÕhÿ¦Ï×ëÛb¿Ô� `̰%  >̰| �€Lw[¤ÌsÁzL ÐrŒvÜÜCNÀ|ôÚ,HXµ‹Bg°$Îëeá7JXÃò)¶$}ˆ_N·!êÓSQi ·­ˆ\$¢¬’[.Àöoc§Å³$œîûJ8`’UÿûRÄö‚ÀŸ/ìFÁX„a•¿pHd løn£ç¼Äd*+§¾Õ®{>-fB(zð¦¦òfCÂa'jÙ©_º,?c÷ã•1¯û‘êö¦ým�­ž²´½ûåR÷Ó;s;.g8òºª@€¦‘€„y€Ž €Øù‚7A�«aŽš6a�„¹�n@á莳YÑ �-ØUgJLïàŽJ|è>5ñ“’¯\8‚Ž%h™®8›æ’YÖLÒªÑG)@!¯rl•6Ò(q‘bC„ÿûRÄî ÈUìFÁ:‡á…îØêU”´hÁz(¼˜0ÀpD�üÁÐŒ8ATÈ`LƒåøöØP …B$õ  AàÊÞÌkˆÁœ@8C»{}Ëýqôw¡�éÐÿû’¿±éÑ·ñìÿ:ºLq… I³02£U0Ûƒð&3í.Ó˜%“„ Ãüü;‰Å9ZdW�:þgnÿ~¦ÿ»©ªú-ªßöÖž¤0_sN1Üžœžþ "8 ȱ…)Ì2¸œ¥…‰‹%ÿûRÄñ‚ W/ìFÁF„¡Ù¿lH:Y•¤˜‚A�È…GÝ º‚Ér²ÆWâ‹ý®t�èýü¹y7j —ŒCʸ­1´•C®÷}W÷;M0À„0€Í0AR0™04Gø1‹½~1~GÚ0‚s3„@Õƒã|�Ž@S5ð,h¤ž/t›3§3¥p‹Üã\ï{R+S_%ÕÔEä3<¬³2¡ØÈdÒÛ³³Z=å­Ç[ÖLJé;S¡\cïöcߊÞtA¨ª"¾�w¥¼O�~jûó€[£ÌP OÿûRÄòðY¯ì¦Á áÅíˆÐ0pqù„Ø� Z;ñŸŒ1„ÊÑXEŠR a(@‹3ì�«ùÇjíE«¢îOÚì×fé~÷“ÑK2e„ºº~;ÖÐØò”좋5ªP¢ c"yˆPn˜‡t`/ ÂažÓ‚a� ž` ƒDiö¦ÞR.‚wc€ï""V¥&£±‡ÿ÷ßïý|wÖî(û¡LãԌզ”ŠÛÝ~LþRJë Wy3C¨aTœ¹«”‹lу2ªpž 8ÿûRÄïƒ �!MÿBA<„"‰¿lH±cP°CÔ ˜ ,�3Í'ÁšÍ �;L+à!Ž2Ÿ3*„ÅJƒÌÁ¥tÜxæ+ëÿþÿ_úúŸc”³;‡9fòz7Wô%ÌÙ³±šP•7ãoÌG½Ïí[UÝi0À\0€—0A0ÿ0F(0¤/¬0œÆƒÊm› x6ö{B!£$ÆJzE™ÑwO‹V§Î¢ }gD1Cõimžm¼+°x«íÒ”Q`åÀ×öKjÑ}j�©éCñÿûRÄÿƒÑð¦Élˆ!…ÏÔH@² `À@a �`˜€6aeiBˆiDa_€êqdÁ˜#T˜ d",'{Ñ7Rºªi®íOç�If:ôYS¶‹§½5e/kT›íîïm̵Œ}~/WQ»ýÿj5U€ŒÀLp @7A ÞB³˜!´ô˜ª˜€ÔMù»œ‚Ñ^‡¼Š Z¼š~Â*{iôôÈñqzÓè=1{[ï)’ U¤~¥Øzꋘq0Â%RI3¿Íì¦ ÿûPÄï‚ ôA ÎbAiˆ!EÏðHµÁc 7`bÁÎH½ øyÃp+œ€™‰�öfmÈàïÒÁ—„T�§µÕ½]v}u¢üï·Mg@4­ªw[´:¾‰Š2û¯•èB@‡ãQƒÅi€)@†K0 06öd0:†ô0B3OA€ÔÅ 6è<¿ê@0B"Ä)PÝ4:WÞRA*»2Î]ï:&[‡ÔX݇¢„û'm$ñ�+0d­V¨b‰…ÝaúV'ïJÉ 4óŒN¹· ÿûRÄìŒTYìFÁn áEþØP‡ë$,j°P‡B^Eý›IÃxª‰ƒ‰‰ˆ žÅÆa°5écá ‡¦à°¹Äõý�¾†ÿFª»£÷þïÙÿ{›¶?è0{0@Ȫ` <`5�ar{Îaq�Þ`b l™©±Î§”:ƒ&(([Ùœ"Ù©JBåñŽ×Ϊc+'�ŠÚJˆ¿Añ9–fX�?½Úýè'ßJ.Ö]hñ�β§ìŽÎ—S0®ß¼Å4Õ™ÇUĉçú…©ÿûRÄê‚ ìW /ìFÁ)âé¯hHH†[N@P`Ä!Ô‚X˜t�³°ô'€‘‡Óf-‰A‘Á±ë¢¨}¯—«³Ïþ¯~7ÿû¿Ýߥñ—"†¡Kúê²+þÌX,fHÈÛ0 Â0_ÕÄ0^º0@Ó7 ¡€3¨k…ɯ€Û·ß~åû² B3µÐzË:–:î½V+2;ô7Ù KytUŽ–bA˜à2¡“G7€Óã"2 Sã6=Ø“!0ƃ@nƒÈ$9ÿûRÄó‚xY®þ¢@ùâå¯hH x°1àr™f~ãËí;Ø?Ã>eˆQá¯Íû“[ wþÒé—·k½œ$Yå^KŸ¢Üžéaµa§ys[” öo1»Ç­©×B !'ªx庞Š50 e0À¨‚J`Œ`^ŽbŠl"b€�Þ`ll˜¹¬NfÞô†jPo½“öüëHÏê;ê|^VÛ4(Ò5¢¨ñ©X|°]ÉÖH­×‹¢TņQ,—BDÔ¢f®ÿûRÄø‚<Ÿð¦É ƒãu¯hH$¨<ˆ8¦�‘y•�0™¼‹©�Øl<�îX`�`ðÔLŬQØÁ9@«Ê#@,eËFk5¿®Ÿ¶:GG÷ltæìgi.�ëőŖSèöíæÕs7ûŒ XPÌ,Èb;&`W†j³FVÆ(g¶@rC�BØÎAlœ~,Ækz¤Ê�ïÉÊäÏE‹¯b4–….oGÕ¥{�ß&îÕkµ EŽ`!^`2€L`Rb`–€Äa_ÆiÿûRÄø !-ÿBAå¦áå¿ e%—rhê†*ÑÀ FBHf—<¬�°Í;ËTðJŸÕ_ïdת§Ö·Z×fûÕ4ÿïŸïWÏGÔÙ].¨Íq«¨8[¤tùÄKHBÐ<Á¤­åŒ©Q32`áh©XÀjRŒ qLD'òÌBÑÌ €Q�æ|ØPMàpâLÀÕdA�|å°CœQ|¶Ý ³¦¤Ð§$}³®±e[­Û½ñ¨¡ÃfM¤Â5WO(3’ú ¢<3ÀÜØ$c¬"ÌÿûRÄñ$WðFÁ,„!á¿lH2w KƒØ C0n 0€Àäg02Jœ®€ÅU°0Ñœ,Æ“GRd¯]~\uUù‹vôU¡u¢žºÌ¬!dñV?ïÐ4YùèªV¬S’ê7š7J-�Ö _ÌÚëþã 0ÀN4ÀàÀeÔÁ(Ç7ºÀÇðÁ?¼ó?�ÐðPÏY â„ŒØ¤9l<ô¥8²îºX£MÍ"‹²¡íiÜ9;bú·8÷1RoR”J7K¤MÓµ%¥Ü�4S»7ÿûRÄð‚ ,!-ÿBA¹£!aþØAˈM$€Ý‹Ï}ˆÈ@YOyn¬ö(SÌÀpí� ‰�êc{Ætœ±*¢¯�Fgmn㎳;ÝãºÿúÎ2ÏÛ£­­ýеTV[OMÅ:*P( ` ~@¡€>©€Ä �‚* ŽEY�Î)©‚\ aÜîœ[IÒ»)º‡�49ý‚/¢ùžÈí݆ñ|‚m¶Ÿ!8YsŸÓ:�’LŒC­4»CÖ(ãN6ǽï½bê=ƒVtÅÆä…�’ÿûRÄîƒ (#ÎbA�‘!ÏÔJ´e䆌Jn懸âd1ǸÙÐzÚ/?@^vfæ>Â`.FAºbGj Ö2vΟguÑsÉùÔïAÖ:ßvØ©ÛÛR}µÌ_gœÒزˆŽZú$¤ÅöŽ ‡0À0ŒÀÐÀ_ÔÀü8ÆÉ�€Æ¤ÁÔé0 ápãNNq€Ø…ÛÉ‹gLßÁ?ûe¡Lgëѧ+G£èB¾±3älN{©ƒ0¡d;}JŠæžeB9žIº3ÿûRÄí‚ `YìFÁ1!å¿lH�=”a….j©¾iØêaw€Ô)Œ“@a…¨& /1`"Î!¦KvU·]S?ë¢`g´êê=¹Œ®ÚÐÒý(œ[d.+% µe*©�+r¯U4€[4„­“å+0ê ÀA€8àh˜@Ô'¢“™ ò™bŽ˜+ÀÔO ǹ�"QÚ¿›ˆ¸ÑoŸ°Ggï¼#w^áÆ�¡Xãî)io_Ö-nÛWbzkg¡w£e×|óq÷éÿûRÄó‚ „Y ÏìFÁg„!å¿lHK�Æv`j†§ fXD†{+†wøAF  çŠbcm¦+fßfDŠŠÏ¬¨$›Ÿ³C·£mL§ž¶×~˜ÏÀjyKZ.í›&üq¼Wô×C?3Œ� € 7˜Àfàј*ÂŒ!³¸B‡.àÓž‡Ç;‰ÙD€Ð°ûiœ¶r;=}Ʀú¬!»…Ëy½™»žS=Òî[hFš,“K„ëŽ[š.ñg®Áb´ZŠý4qkÖebY�ÿûRÄî‚ œW ìFÁ¢Š¡ÏÔHÊF¸<�Üa|iÞ°RižÊam�,‰bÅxn�;/fElL™/v×S*möì£üzÜ­mÞ*Š�ÚOZÖ�b†‰^¸öîJ KÚƒ¯xçT݉VXri?ÅPPm·3¯Ä"# M3*Ãd#óy³#³˜ §dÙ©7F Pu™?c0t«ïÓÔOõÓ»=Oû¿µÉîï«ö¡®ªOù*6 ÀipÀФÀÓ`ÁrÿûRÄé‚ œU /ìFÁL!¡¿ìH¤ÃYÈÖ0u0Õ¡0Ã4$ã㓨̂Æ3•ÔɆó€l5W)´¥¸ CSLÐteÚ—ty^o�´–“»…šÆBt ¨J>ÓËŠ PZ}Y¡M¬l ¾µµB‰"ãå4•›šfs Ac$V‚â“3j5sp.c=lƒ¨.#´³ñðå@:jÎÕ#h! â–ìf~®'Anür·ïЯÿ{tÓÓ—êŸOýKD]XÏF€â>ßÌ`TÉÆ�ÄÿûRÄ\U /ìFÁŸ‹!ÏÔHà[ŒP† â÷Î …ÌÄÌW€Âà =2#b2 •۪קP£XúýƒF[ïO~�ÉxŒC„Œž)/œ!Û/àtT~�ouûÞXGŽ`´éfOÕqóQ`uL<㈠\m©à4±èÜ^ƒÈµ�c¢ØÑòá× ­ïE…š\ÿûRÄè 8#-ÿBAË ÁþØ üàÔ‘N¨ú¶L"�± èe„ â�ªŒ à&άÀWL½ØÔ:ÌÈü»Oí0I.g·�SÑ{¶Qߦÿ{¯†ßÑúõûoýK–ÿÛ€  ;˜ Àn â˜>B½Ÿu*•ºB éœBj¤ñ­ÏfÂhèh'd‘ye» ¹;Ì\½“ö g�rêVÇ�Žh!Rgïm‰D.²ôë¢èe…úÐB2�½ŒTÊI­Ñ÷¹Å-Äd¢9˜ÿûRÄç‚ p%-ÿBALƒâ¥¿lHJÆ”Bœ&a6¦h!´ºgìna'�ˆ¾ @D™žd2P8åJkLÇ=EtÐK[N¡×�3 iu¥(=gêÐ1åxíÛYNƒsˆº/OòàMrÖn`ÕQ8 |ÂE$¨M=N0cD!2œ 2�D0h\=s}w8%Ã�£5RQ Ç^YnÁÆ!8q©Æ»‹?-ÉHE¯-·Ý¥vï­"›JÕ¨okмˆ²ÁQê.¿H�è 6[èÆF �„ÏÿûRÄöx‰¯ðFÁ4„!¡¿ìHÎ�â ļp޹@à96›½H Ö´µ®5‹ÝG>p“Ê=(SU:„¿O¼£.rIWîd+tÝÇIÌßÓµR%iI4_pMj™RÓié—ðÇ<âàÁÄ8ÌÚ�ÄÍ\8Ìë„Í<Ê(ËŒ¸ñ@pû$#äÚ2‚ö¥«ü¶�5 &2qÓ©s–QŒ,QM%¼ÍÌ,à\€è¯Ð5ü ¬DÌ@Ê%p  ,€ˈ;Vʮӯ}–”óØRûÒKSøäVPb÷/|’PŽUÃZx¢Ò… бóýu±Tcïe‹æùbæ¨ FÐÿûRÄë‚ %-ÿbA�ŠáýˆØfèÆ 7&¨«ÆjÕ9Ægø¨00fºÜg…'"Äw¦ðrLÉbÖzî[{$Z/ÒDÞý@-Œa\Ø£*Cx¯)!j(™Qd8[©çMÜÔM!fª]'½é¥W˜@¡œ”›£1óô˜DÁvËëfÀÁyE †ŸµÑ»F ¯t¡ávßÉ]%p¶Cu,©Û«]’o`£¯Üî™Ý:w2�+­®›}W!É¡Ã�e¨ep»ŠÜšA„ª1ÿûRÄë ø#-ÿbA7„b¥¿èH0¼Å$cLÛ0D51âYE1Ôƒ#0<Àà4Lèc˜¬òì7ä�†�zÑNöõ}È¥™.‹Š³÷>ÑÂflö¯ŒXê:Æî¸h1WŽëgÜb!iD„ÌÀpÙÔO*øÁé ¼ÌÒL<Ì… ÔÁì€õçM�äÓœ /4ÉÍQAÿ¤®.c*¾–P±CúzÜ“Ízrþéu­´ ¾‹Õzö1¦_oyþª›jÓw¹kÒ`1€è`2N`A‚`naÿûRÄö�ŒW.~¢A�‹!ýˆØŒ´fçb˜f·Œt`æ¦i3°:v¬‡½ºr‡aÊö�éÍtK¥!"¥kUA!þ1ìÇâïTðcj›$‹jr!{g RÂpI¡A2@ò«8¦-eÏ(´’.' oB�*0ÑD&P´²<e"&°|vsf6vÛûGdÄcf'qj Æ~ÂgF4T ðÅ8&Iôí“uOâŸ|¾ý¢‹›ZÜï½d¾�k¡¿(mè¾goÏ>«è0c0@Ž0íÿûRÄì h% ­ÿbAN„"%ÏèH0,ÁÒ0j§2Üëñ2È…‹0]A 2ȳQ 9äÓŲ8Àâ–mžÁ/éU„roêaîuŽ.‚ÍZȤœ•åLÙã´Ž.Ý•.ÿÂ{•qmŠ$€bŸ/T{nu5§J+00@S0<€Â0�Â}3Äo3­B‡0‘î?›q�5hcMõ2”4våøOëó·}nãº\=tÞ?#ª×EC3Ô\ÙuncUN˺Àæ*Єþ©hlÒhUŸ!¨@€†¡ÿûRÄò‚ \#-ÿbAÇ‹ Áý”Ø€€逦q� 邲(!’á8Ñ’Z'a‚T ™‰¿¤N,àë#͸|Hyµ‘Yêó"Ö‘þ‡¨�n¥ùvTò1uwÖø’ÿrå¯iï=ÞbIR tñ×­@ÖÒôÆ5G€=0À0%€Z0G@Ó0§‚ª4YÔÂ4>‚¶0¨A9(Ð c0¨L©1a@¹nÄ®’¹ÚÚ¦·÷]ã»Ú¹ åN£ÙíùÊñÕ?xË»oè¹ÈÐéT–º(�(õPGuÇÿûRÄê !ÍûbA‰‹!ýˆÚ–@æ4#˜ÌÔd©œmF Žf=ÌX&<‹æh)G1¨#x)9vã_m¤7ð´ο­ýnGÃVÑtížïïY…­K�ì§ÞÕPgóÖêÛʪs)¾Ç�–r§ÒA‰8‰œFi¾ˆŒ˜“õ–jÞ™§FW¹ƒ*Ö)ðw"Þ¿GŒÛ÷èÿûºkÚBê¿§ü´‹ÑG§¬Àk(Àb$ÀwÀ¾ üÁÁ˜Ìì°ËÅÁx ÿûRÄî‚ ØY /ìFÁ� áUýˆØ…¼-7)0âKÓ[ C‰ÊEæ�ßT[¥‘�z«Ra6ú¥5ëÖÊ]ºˆîÈC=U½ÚÎù˜ê’ºV|Ù zµÏK’%üìå>î·cWrÿRkpÅ·¼«27²¤*TxAÉ£„œ!ÑþÌ™+ñüïÒ�Q’¸eŸÕ1´Gªm¹*EU Öš£TÖ.„Çé¹(ÑX¯ó� m0*ø ƒÿûRÄó‚ „W ¯ðFÁ4„"å¿èH0ĺ0R$Æ0MDª0Aq5J#b*¢�f” 9²{r�YZÑ“u%ÚÁ´¦°òªqeµ„j5O…£¡KYdbß¼+ ÎDÞ—ÑU50ÉE6*M2�´Ðàâ. åB&0 FÀˆW†»À†¸àw0¬/q�€3‘è&‚T u6}ïå‡B¿¦c½úÖ•MAšëu±ö‹C¨rMqô±« °•& ?mR·ö@W�d2'®j‘ëÿûRÄô‚ŽøÑ¯ðFÉ\‹!AÏÔHTØÒéì�1¡lÃiC@J¿àÅ  ðLñ†L`zÐn4i$ |6áHÐ00&¤!\ѽ­]K3oèι‘Ší™Ç‹!øp§ÏîºÖzYbîJ“AC]¡ŠÑ<1z¬‹³ ¾»!!QLœHÑÃ<‡òLˆ@ùb÷¦d(šÊg®fôCÎ8z£ÑÛ›c×|£ê —B¶êM¹Fîpº½Ûj”îÕÝÖ“;ï«�¾HS0ë­»Z ÿûRÄë 4!­{BA|„a•ÏìH$˜„|`ƒX�| Á˜Â]*²c*ÂV ປEQ´h8 {0 m³Iïå÷¬½}døäTîä[C¿SM)Wk~¯¾fq)Ä @Âdå}„—�E‹¶õŒ�-3¸`Øó¯† 3"MQ‘_ÍI Ì1ðÀç  3Ð &Áö 4µĩé³µú³×¯Ý4OLóÄÔçÇ!(~ùæ«|e¤GŠ‹\ì¤U0µ"‰�î1Q¢&q urmÿûRÄðƒÎ‰~¢Ay ¡ÏÔHBYÂËÂÄePP©"Ãc‘™0¼Î“ ±“0V³L0ïÏ&�³_3?^•ú'­=ìÝÔŒ¯üÿOþÝíÙ]OÿlÅŸõªc%–Œ¤XуMä(ùL‡B@øÙ]�wAÐÈ@�lÍÛÁÎP¡êÊŽÐm†�¼ªÖ%Èji%äµ¢ÍwR(ߺRµ-ËãôÜ×I)Kq~Ó-*›�åkŠA±é!9"h’ª0@0²"ˆÀ<À\€ÂÿûRÄç ”#-ûbAg„a‰ÏìH¿€ˆÂ´PÀƒÚ& pØÞDN(`2° =ìç³öÖ�¬ÚQ¶ôºýÕ}_ûoªº­ºÿâ‚ÒI".(¢ó-Òlñfä“KyíŠr^œX²Ö¦U Pñ�fe˜Brò!…ˆi¤ÒI‰£äY…fXèHJj” 0•ƒŒñDâÝ»«çVu®…�¼Qè¹Ù½ÛªcOß=BÞ0dùé±Ëj³+YDÎ71Ø5«lZ~Š“ÒÔÝ‹™0 ÿûRÄí‚ àY.~¢Aƒãµ¯dLS0@�0@ý0�ú0/F1G/U1AF0<�î;?S›g<ãÙC8Ð2#?Ÿ°�þ�›úN º¯öæÐÓLâ)—®åÕµ•÷X¥(&{öÜiO×ÜÒ‹DþpÖ}÷™EÊöSM³Ï7¡ѳ0ˆ8VPƒ‚z+£ÎŒÇ³$t ö2éLé¦taëOÔþ+ýŸaKÕWÓoߘєD¦‚W&ä1nf�퇛^ô„ªaQ°€Î`EÑ�ïÿûRÄö‚ Ü#-ûbA¨š!Ùý”Ðæ0•†%‰$`”x.çpnI‡FtFÈD.æHì[Ï]çó÷ÿ¿±öàªóO}L|…Ô\U§�TÉÌXZÜ墵³¥6§rÍ ±Ö —¯Ã¼sª¥u2€ôÏ#C`β‚0È�Ç50η5�£0ÂÀ’€ÉJ` ½×Ã&`±Ž&N-Ù÷öQõ+ô£v927 Tœ“”n´ÖÕ§¯e�³Jóϳ±& ¹4Š'Š=U†Vó�¹É<£zÿûRÄð ÀA ®~¢AŒ áýˆØ;FÀ# < k˜ Ú"§˜ÂTŠ˜¾b ˜!@×nÉİ�1¡Üª›¸HñC�OØE»õå_÷�Ü7­ú⪜¬”ý¬ºŽ§&ßÑ—õÈH×ô*•£MÞ›©Q ,eä�>o%G¼¾d"*ǽ–|{*'Æ@.w(&JÊt1Ž ;Nh�k¨~õ–­Y?:sëO•œ¹”~šî¡ô³ïuùTPi4kCîF€±¥¹’CÎLfè …€"Ì@=ŒÿûRÄé‚ ¤!M{BA‘!¥ÏìHð|ÌA€Œ|[� yÁ} 0{OKøèõŽ Hh½ŠBç-�—dzàé_±GÝP„6ÐÜNòW•!ŸÓœßa¨û[]*qÔQ(%@U‹8(,yÑ.Èi„Ç)ÄÊ12B à´ÕJŽ(ôÿà –†ìþÿ�OÖ†„É €Ú@1AÐ ‡ÀÂä`¿£”Q8·o_Î öÑeÈO£`õW×yf!ïÿwîû3ªÝõhåL­¤¢Ñ*•BÿûPÄîƒÌìW~¢A^‹!AýˆØ0%3Èi1uóÀB8ÜðŠÂ48Eó*ú×íöò_ëïoÿb¿×ßëÿJ®K¦Ÿ¹w>ÄÕ€ °Œ àÌ0( àKÌIñ ßÇ� ÓÐäŒF€(M¡#Ì_<Ì/FŒr€ÌP(L–‹í3¦3]É&²xEˆÍ¤ú±UìE7MÊ|Ô"³™“u"þdABª:2ÜÉTR.µJôbÛBŸJ±™XÖg%RÝÍdgwiY¨8—ìµ³.ÿûRÄìƒ „#ÍûbA¶ !ýˆØ ô`B¬˜L#(˜i4eZ �̱Œ–öÁŒPq‚ ÉS2�¼˜œ"±¨¼“ö-…³y­ÖîªkáϺ·Ý°mûsléŽ÷¨Æ¥ï`V:�õ:¯000’Q¶d™ñ†àÙõˆbH!'q’oœf#`@v@†æ?¡ƒ,äÓ“Q½½ホíŠN§};ÐÑqOßµ·3GÞ+^Ôœ¾úµÀ(˜€M `‰˜A7cU™ÿûRÄé‚ ô? -ú¢Aäi¯`LoÙ±™h#O˜<�N^l5 · Æñ[šlV8Wð$¾XEʶ=áâúQ¡�¨]�¨Kµ‚õC ‘[Q¥6-FZ#cZu�1z–&hÊbÈ{F-1bLQd9+[ËÔðEè2HøÌ„3O™8É0¦Â”4Y¼4=Bv0 {o�@ÃçÐ1 X ‘A¸†Tš1²mtzë×cÝÞ†ä÷&áOÝÛ;iVä걺‘·Ð«ïû~9ûÎoijD`²�ÿûRÄÿ {/ô¦ÉV¡åÏìHÐ&Fu—º`Î ˆeeÙeG t`àƒÆöƒªÀkÓ(1P‚!XŸy8n›-”Ôüã¡_Ô£ÝAYÅÄ£îE0 ~�fÐûXÍ{ šï^kd«ÚÂ'>–Ù]šÒÊHÃ4efvLl'kcd:§rýâv”8f4 ¬qF �bKf[lc%Š U<�™/íé¢uï™û¶Ýnô”]ötSÖ©Eï{HÅ]¯e1b(§e Ds�œ« � € FÿûRÄî ä­{BAÏ‹ ÁþØ-I™ºh`�‡¢cÞ;rcȇ–`›ttufÒ¶n‡Æþâi¢cA<²Ø Ûr‡–$ÙB&KY’‰ìekêú-$º{–ä\ÃüP­±óÀ6M÷L½Ó7"ÚH‚²g¦Æ¨‚plGÝ’a… gk)(g;„ðav¢æÆdïF‘âeˆ(viŽ–2¢6‡í|wŠ ìt†ôÞ¥5ûüº¢f¦ÒEï±�¹7›¡À4±ÎqîÕ±µ]½ŠzO?ºÙ£ÍÿûRÄê‚ËY ~¢A‘ áÏÔJÝ#³08Q¸Â¡2È$Bu ¦[3? ÝÖêïU›ê!÷[k»½Ìß�¿êÿöW5o«õU"ifŒðäÔÐŽ ¤úõ " ­ÌéµlÌãÀ§Ì!0%€Õ€ 0p Xy'»Æ#ànÑÎ.¥S=ݪîëÐÖ´ ¼é(�/+eC‚cKåžAËËÆ¢TX‚ߺåbæTpö\ÈÓ¹‚›œ��½v½â÷¼�f†h &@AF˜ÉÿûRÄê |!ÍûbAv„aÉÏìHftvfqØÈf CG7š›nmDa¸Ý¦‘† »ñ/¤{U]ëúöAø±.°›mm*XŒ‡D䔤ì1m�39Y¶µ§š’õ<.Hè]ï@UV-Æå@-A—™IG×Y†›È²feƈvm«Ç�†`í„üfK'øf"„Ð`â ¥™K£d™Qš??´ÇRв÷õ;O'÷+ñ]›6{zWØ*8óŒ)Ïs¾uÛ�Ò¡Â �ÌÿûRÄï À! Íÿb@ôƒ¥½�pD@/ paL/Œ»Ù-Œ·a. �dÏ»˜ä¢Žm¬é.�˜°8m´‹Ë-œšmáTµ÷4{»›³'#ߺëg²2¹Î•ÕhÇ8Ⱥ/cP�q% GÜŸ¾×ÕØB>Å1WjƒÔÚã†SŒ|Sˆ@B€1„m ±wY{Nâ‰Gû¿úü¿ÿý_ÿþ¤j ¦`"d`U‚’`«(a”�ÎjVy>j�¾a§`{ÉÃ`ghŽºk³ÿûRÄÿpW -þ¢AÎ ÁþØ(˜šî$?±Ÿ;Ü÷Ì+/¹ç�1Ï,ŽÙOÎ%/‰’åÎXîJDpìB¥s*ÆgŠ(’2†ä’æD¦g3éš�r»Ó?23/G™.©î¼RˆPæMšL®¹[RÎð\4^D¹Ÿž‚i½½çÉ„›˜Æ�šæAƒÜøÙq*‰Ÿ·éž—IÝ•�£9mK~à‘Ä|…¶^¤Ûç4/ßZ.7g(‹6ÌRLü,0WPuœë´(ú\U lÿûRÄé‚ 0!ÍÿbA„‹!UýˆØšeÁ«hf @FYkÝÆWP Ø*§±ŒoÏGÆpÕÆ P$âKé-‡¶c™Â»ÒMÌÝ�û¬OÛIX4ç·§W­3=©,Ïj—K™þšoî@– fo8‰^rÁ…<"£ ¹¢(!„ò€ Í@f˜.@[)PDNÄTÙlÉ257š¯¶ªŽ»{ßµüø²]?¥Díe± /[Èi¢æŠ¤xêäÇHÖ†N1+b[­ÉJ5¢ÑÐ ÌÿûRÄî)ìwb/3`Aþ ðàŒp2L hŒ$QELñ ÎÌëqDL% nŽO 5Z´ÕˆãY½ÌÞA0xrž�Šš¦ËúvQ´XœŠÚ®X:}&ŸB}å*¼akcµì%0­öšMÍïRE¤Í](»o °m@€–a€¸�á�ä É„vážóQ�B„0ÙχÍ]àß<ÍA )Å—Yí/g JúToK“o'm—[o¿k}D£íoWM®)@®å®æ}ß½ÿûRÄêŠè! ­ÿbAG¡…ÏìHâ"ÒŒ™yŸ4_9‚´1’nµ¡’!‚ιÓIÒᬥšÔaš"<9N ƒ‘ÎÅ[Þíë÷äþü…ÿB×|wziº¸óG¿g²--ýˆ´Ì Ì°Œ@(̰PŒ" ÿÌêÚLäùL pAŽPtÁS qÔàû U 5Æ–ÚÜ»‹üѼ�±oµÊQÈ´Fá.�Ü’û×½"Ö3iãÃŽ�·‹.M q1g4É'9í ê'Ö(UU‚Ì8ÿûRÄó‚ÍPU®~¢A”ŠáþØ62yÜÔÐ#l3³+a’ó*\3³ cÅ«6¶óf\6š“='/Ã÷Il?kÖR´d:¬äêO•ŸßoVV:•Yû~öÅ4šÞ�˜§èÐZvæÞ0@n0‘0,@â0L»0°Å`4žª4Å>0¤�o5èðÃSD¦�m13Ñd&]0õž«•­ø¿`C]7¢’�u+ëPÌ@9ÍÍNö�KÁ—²±…Õh¢¡‰Û2aˆKÉ‘­OA›\æÿûRÄé‚ lY ¯ìFÁ:„"%¿ìH¦ÝŠBʈŒd¤ÑWdÁp ðÉËUØÉŽ ðÁ{´ë$ axÕTMRXˈΧÀùįAä3f¨kõ:›Ñ®n¿›ØQ}ßínOpÆÿ°¯ÿª@– æg?I’oüa„¨&ÉŸs/Iž %Ù„V `X~'ž�àj8¬ŒÁÑ;Seª“ªºï6oWHãõŠ=YÞç–¨žÙå÷$r’âs˜­­EQ‹Ì«ªÕ±ë~‘ˆ¥Ó¹qdf (4ÿûRÄò‚ ¼W /ìFÁXaÙÏìHÈŒ ]´ì¼Œ0ÂL·eì̳0ÂÌàB�.¤Ú\Í�ˆØmLÜ­Žü²Ý€Î-†’ÖÔü*zï·ï/›ÞîRö1,•\b[•ZEY›tµ÷ºgg¨YõÜâ¶.1™Lf81Ñ<Êè#NBÌÐÕ ¤F“ ŸðÐ à8ML Ã‰Í5 Ú'M”H ù¦Çÿ_ÿÎcÿÿY ÐGÉ_ë«r f �4÷0Þ�!Z\¹Š³ò^ºÚƒÿ»ºï¼@A‚G(šIPqÿûRÄò‚‰ðFÁ3b¿ìHÛ9…D#¢×¢#1…^ hú¦\¦T i‰h Á1:rá};²é{e}IT|Û Ìh™•} _yúôÔDP ªíe×ëxТPBóã› _½Ê ¹—Ô¯“NºÐ¢ `Š`"€¼`1:`X‚x`ÒÒe¦½^e¦`Á‚kf6Pl fÿ`j%AÁ.°Z‹gÛXÇÿxþ9VÔÝWB­;:m©ì·Ûujô]Ë_<ÃL²ÛÿûRÄò äU®~¢Af„¡É¿ìH4„êú€€Ì  ×YNó€ÁÉ LÌXT˽ \ÁÐèôiM�ÔÖš füÌKÐÑÿ¤§À#•Ãö²·öýÖ}ÅÚãu|ž†ÔB»×GÒ«“7íùæÔ·<­«À‘€®€¼9�Á�Ä i„*)ÁœAE±›‚(ÑƒÌ ™·°‘©Å¶—º„0XµœÖÛ_Ä#×Ù”}[sEqÔô8¼pqMRÔU‘®.¡}äg–RE¬>lÐØjñãÿûRÄï‚ x?.bA« áÏÔHŠ\ëO[3y�dΰ f¥æàà|?&ÀcFp †mPcÆ#'åxoFÒþlœFpt_7ò7IloCükÿ¹û4Ñпê÷³ÑÓ­ñOÙ××D€¨€ºA€üù�² ±ƒø*©›LYš`)Ƀž ñ°5™ÙaÈ2�¾Á¼œ²h­®#oDºÄüýÃÓ(ö.ÝâµÂBJZ¥z&­!bh]"a=F�žÄgâ<€þp9”ƒÊÐ6«út9búE=Fnõf2ùG#ý¿ötþ9ÝuîY †Xæ0F ˜&¦yÆÿûRÄê |? bA?„"¥¯lH±«ª†­P{F(.g~ŠÑÀhö© ®ÆJ7Ã!¹E8º²Y‰°Ê™V– 6ç s! ²,{Æ=,Ø Ìë-(_©Ää!38ÆR9JpLœºæ”Sj�BÖƒ>TjÒ´ª�1D¤a˜S)©¡ü`Ô6&j»bfx5& `Üdhãx3¦uMxÉK®§FÍ*kwëùYÊZÆýåT»b®Ç|ë&ô¤ÃCÉ�CÔíËåÍrI¾àÀ' ÀÿûRÄòMY/ìFÁž!þØà7˜(À}_¡�šx šhá–˜_Àš5Öi–�Fg¥˜ä¾Y‡•ÒÙ®«á]*Þpßò¿½6Ø 97Î=�‡ô ²Ó,ÚJªÓ:ާKÚ×µ~S�DèÄÕ"fLF.1,Ũ#)DL PÙ a&ªŒ^pÕ @=A4ª�sG²‰Â< ž¼ºÕ–_f‹¯õö,¦_þbŠ=ßgoTØÃ?lêý(2Ð &AÇÍQÆüÿûRÄè”­û"AÊ ÁþØÃø= ¿ß ÛH>Œ?ÁTñ>4LŒªóˆ9Û¨JUÖ¿#èÖ­kO[{?ѳÿ¸™ÞÕ£boºÜÍýéX¬2`ª`€ü`$¦`>ƒH`— Bd0ÏÆd `‚ü"‹+S9Ó±z71�b…!¿Â+½Qu‚FkÌ;ú)׺g•ú^«ˆQs-޳½1°¥Gé:§�`6 ^æ44m/›�7­ à H’ž§�R€p‚Q•›%ÿûRÄê p­{"a¢‘!þØœ‰paV„¶hÝ$®h¦„ÒaUà!a�ŸTàee&J%)ƒu\˜30AýßËì½½5ºæ¿?YëFé›=ÚG-·76µlâZ»0ô%l$hsæbÎ[ÚÞÔª0Àb0€•0Àö0 �é0OÅê23-è2#EÐ0AÁUfiqçAœ0è±rý‘QtéJkÄfìç{Wc\«jØ}À=e~ö³NÛ¬¦Æb”±PÂŽñ›-‡ºê– ­ÿûRÄé‚ Ì#.BAƒã1¯hLÅIäQ �‰¦Wšp€ru9…d1£Î†a¢ð±…b�|xS”T d @x¤|r ³Ók>ìËŸoW¦îçv9HÙ#ôI­f¾ÛÚ(V½ ü-s°©¶Ì˜Ò§©âµ#(jŒ@tÃM AŒÉôŒ «L9ÕKL8¨L�0°Ã£œ'E *òpȯ?ZwPúßÚ®­¿r?ômi]¬ìGVß›½?ýMÖ½ d#5Œ�OæJ{͆BÿûRÄý(§ ÏìFÁ“‹!EÏÔHbò{Év'±ãd‡³j¯fdðd¼&v¦:•Á­î–(³“ô«nW}åë–ZN£eÈhÏ5rÑh„ëz��QÚ4Dö(åg³( *9 LpŒ %Ì>Œ`|ÌÑ� rË«Œoq{ sLŠèÜŽÌpõN(Dh¹ŠÂ¨³‘]‘i²m­ÃçK_z�fµ—ál‹‹jjsõ‹*sÏö5� ¢MK&ó¼~H0iÆõ^¡Â‚±â¨ÿûRÄëƒ \WìFÁ~ !EÏÔH)$c`X®k¡ÁÖS&?F¥Éí¡ÀBè tÆ€€S`�Ž«@aƒ X1Œ!æ ¦Ï«J¹Ï¯Î»‹»Wkš‚IJ+Ö™ªÜJq’P™2ehç”ü´zÜßa„Є¯>CYe pS1ZÅ�³$í ¡SÌXzPLU¡NÌ0eŒ®œÙDÎh4îQ�Üx…¡Hoó_ßýÿ?ùõß Iô‹o¸”¥(S“9>p<¡ñõ]j¯ï¿¢óÈ¿KjÿûRÄè ,!-ÿBAy„aå¿lHùbº[Õeàd%4€‹†š ”<ð� uCìñiûOD$Ç@å´ÐÙÌ�˜Äq@&,‚?S0ÃÖ;(E|—Qý[/)‹½5Ê÷Iü“Y8­ˆ ê aŽ/ºïßj†*0@`0 —0 Àþ0�ù0-F1X¯@1MÆ0Ù4Lƒz$;pcÖE8Àqã&+ ¢Í}Øî»h‡Œªû©}T¥Œ‹¼›÷¦§6X‚ûîUl5 (ãPÕšÕž@æïf“;ÿûRÄò ¼W/ìFÁŠŠ¡ÏÔHÔ@Ùi44¬Ø+¡û2bhG èìpPÆ& v|žF%èà€ÃÇRëä7TýÜWÖßïN­_»¶ßù_½ÛõûþŠuS"‰6  NÄ`,&öŽaÜ+ Ð\ì2dm ÐõžÛæm·K¦4tœk­Ëû‘8‚ž½gª]éfëo{®Vá@Û}ˆGÉQ“ë~`&€@)�º¹ƒ$‡F ™¯ìQé®Â ©‡,1ÝÛf�m™Äb<ÿûRÄç‚ ¬? .bACb%¿lH¹�Ïc&MÔC.�;|×â,ó= ‡eÈóÿ Ê•(Jï¹hÑ S×SÍšyÒòŠG¦M¢å%žù“f±K4óߓ͢—9Úß…Ê5R~xúþ± í×þÂÝ"«1IÂÆÓ¯Œ%ƒ0D¶0£$®0œÄ¦0m#'Ë tH @†h840IsÉ­K¥Iüâ¯_¬ç�õí8ñ£GbþùNª}=7§]á‚|ý3å–”F&Äq÷ Èð3ˆÿûRÄî œWìFÁ„"é¯hH|:øÜÃ0PÕÐÔ�ØÃ%\„¶:.€Æl00uˆ mÅá`šhY•weÎý^q ]ÕÃB<ÓV®´Z¦HÏ>©´±Š+/b ·¸ØO iHÇÞuÕ5Þ–*1ÁtÄ)c @Lþ0 †)0‰oµ0‚0ä8¶ÀÑ#ð¼¶Á5 DÈx- †ÕßTÃÛ®qüI6’í´3Q|›Ù]çHÆ$ÇÔgKSÓöJ)-LälÿûRÄø‚ À­{b ¬ Õþ ÙþyË÷è¡È r¶ãNƒÇÀg©gŸ€ cPÛ ( Ä0«=Ák¾}žý*þϲ·¡”Ûý½è§Ñ)þ]Ç?ÛE…Y£ � [©*$" % â à šdqªw‘Š“V•ƒ¾Tw³%±˜³÷¯©[+BšÜ’È{P&¹K{-]Ê'\j¥ìsOË‹°‰rµ ­‚:@Ês5¸.e0 tt|&&á †‰Ÿ¸„ÊXÿûRÄî ØU ~¢A™Š¡ÏÔH¸ðJC„QàR’º?Lìú—÷öGçÞõ#¨"‡X³½NÿþCK=ÎÜûçóݾµô~/ý5»žo©÷‚ä=^Ô!îúºÓS´ažêûW]ëÔ0€k0@¬N (À3,ÁxÙŒÁƒÔÀˆÈÔp“S—M¼7è z–P@Q˜:~ÁÕ›4K¢[–Qôù™œÄ²«d²JrqîÃîˆ\·m¬‰KšVØdÄöǥąRóå‰�ÉÿûRÄé @U~¢@ꃤµžäLCq眆&À8ˆ’&R(hÀ o I�ø 1ï8  qå±™Û‰‚=sŠ­¨&åÑ[,Û¨'¥ÏÓÖé—Þ�)�í @�€X©€�„ó˜Ã$bsùÔaSã¥ï9uÓÀ"=²°XÙ1ƒ„OØ!Ó=è�6>ÞájÄGSµk#M³óÇžq§Ü6’K ¼Í@võÈ�]w•ÌÁµ„ÿûRÄð ô‰ðFÁC„aå¿lH/UlB;€(2 Ì�ÓS‡\=0±@ô4›„4~@Ò0­8IäÉipB�ÀÓÒÚ š¯£-³ ÑáKÞ?#x͘q§eºîŸfô/w£­�HkôlÛ¿Å*1%UŒ& ÂÈ£ ÈÌÀæ ,׌,ãŒÐFÍrÓ‹�œ<Ý# áö3 ZÌ×­ÚÜöý�ðß�ýæÛ¢ÛôÕϯïU¨âËM¦>šÀ„ei2¡³G7�“ã:2ÿûRÄíƒÌ´WìFÁ]ˆ!AÏÔH³â=Æ $<ã.jw0~C… žÏhñ—ž0¡k¦PmäÐú‰¥(ùWô§Û}x@Êd„BHUx¡�(ʘ½f9‹¨È˜�»yªH;ܨÜËü{+½Þïwä­ì±¢ÎïÓnÌoý_þÊ%ÿGX‰ó|c0Ó|£8 \ã^Ñ#\|c ø“©£ÌºÅm³"aÿûRÄí� U¯ìFÁO„¡EÏðHÃÈTÜcÔ:Í+kÎáJd_nƒo\ëßö"Cþ‘ç›ö�þa[D)3•vò®VÆ%éS+ÌÏ;ó^$4ñ¤9¥B-Ä÷Ì©&¥ÏAê�ïÈ�ÄØoßC ŸÏ¡¤ FN#L,ú2ßÜÀø@Æ£»˜Æ‚Á)¼ñ>ŽyÀðOOax⃋ؤ.YOžüý÷û¿¹ñCðPÊo2®×/ƒ%tB™æ'%‡&Ì$–ÔšncGQU“¯UTe”¥+§P©ƒÿûRÄì‚ (%.bAe„aå¿lH(Lò85ñ,ë)# x3RµsP˜ó `9À Œ¤…ض´2�≒.×êÕ3~ÝS¼pÊT³4ôÜL�Ü€µ¬C.ØÌOA’LÑzTäÌ1C^Ôu;½îÚ³2šL #%#%c(á�:IˆÐÝ9ˆ¦ �lÑ·Åš™Ù³™¨ <ˆ9oZÈb�ã¾äîÈÑÛ;ó»#?BZS[Ô•¿ê~©+iý5™L€g�ù¯ÊÿûRÄõ”!­{"b§ Õþ Ù‡TT˜bá�Hô€!_À!�ÆÌ cõp8«�‰  ÛÃMª­úë§^¿sz‡jIª‡Ød\fYá ïN*MZ6+�9±µŸpjȽ®�nÊ\ñõn?Òpg00T”tˆc3¦àAFêF`@†Xfê1¦0lD›ƒŽ¼åüýÔT¯ªG¥u|­ÀeŠ>Ïzõ*ŽÜª¯}€nÓ5B§¸i²åñ’Ò(A20äÌãƒÿûRÄïƒ ÐA.bAŽ ¡ÏÔHQNJ¢0«!4uÑK4Y0¥ÀLwÅÈ`0bt o&•º£”LœEÙÛ£ª} &GUýhÞ14¹L½7ŒK¢òü")U+S–nî¿¡a–K©É�–ÎÛÐÂɽR•@�p &8.¦ æ ¨[¦\4Á¦5Èå¦HNfˆ"¦h'fÈ&8 fh¨ tf$”§Ä�~×AlEä®bqwITªÛOS707J;…>Ô=¼ÇÿûRÄè‚ $%.bA— áÏÔHÕ±Sû]©y€¡p8$ ‚�!‚¿2bL $dèAšfß±LÕñdA3—Ÿ ‚@ e Âëƒ &`kF€à€€€3ÜX©Ô Rp7ªå‹‘`€"3˜Ê6}ËÚb9˜«ÿûRÄë œ#�ÿBa¢ áYÏÔHÙ4KJ€V<ÿK®ƒ€AW, DâI<å bS « ¨ðÕa¾EGª'ÿ•ÿ#Ô{úÎñ/ú|òLAME3.100ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄê ¤W µñ}žf·9@ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄŃÉI}ƒ4€ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªbeetbox-beets-00724b7/test/rsrc/no_ext_not_music0000664000175000017500000000000015253035401021270 0ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/mbpseudo/0000775000175000017500000000000015253035401017621 5ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/mbpseudo/official_release.json0000664000175000017500000015503015253035401023774 0ustar pieterpieter{ "aliases": [ { "begin": null, "end": null, "ended": false, "locale": "en", "name": "In Bloom", "primary": true, "sort_name": "In Bloom", "type": "Release name", "type_id": "df187855-059b-3514-9d5e-d240de0b4228" } ], "artist_credit": [ { "artist": { "aliases": [ { "begin": null, "end": null, "ended": false, "locale": "en", "name": "Lilas Ikuta", "primary": true, "sort_name": "Ikuta, Lilas", "type": "Artist name", "type_id": "894afba6-2816-3c24-8072-eadb66bd04bc" } ], "country": "JP", "disambiguation": "", "genres": [ { "count": 1, "disambiguation": "", "id": "eba7715e-ee26-4989-8d49-9db382955419", "name": "j-pop" }, { "count": 1, "disambiguation": "", "id": "455f264b-db00-4716-991d-fbd32dc24523", "name": "singer-songwriter" } ], "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "tags": [ { "count": 1, "name": "j-pop" }, { "count": 1, "name": "singer-songwriter" } ], "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "joinphrase": "", "name": "幾田りら" } ], "artist_relations": [ { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": "2025", "direction": "backward", "end": "2025", "ended": true, "source_credit": "", "target_credit": "Lilas Ikuta", "type": "copyright", "type_id": "730b5251-7432-4896-8fc6-e1cba943bfe1" }, { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": "2025", "direction": "backward", "end": "2025", "ended": true, "source_credit": "", "target_credit": "Lilas Ikuta", "type": "phonographic copyright", "type_id": "01d3488d-8d2a-4cff-9226-5250404db4dc" } ], "asin": "B0DR8Y2YDC", "barcode": "199066336168", "country": "XW", "cover_art_archive": { "artwork": true, "back": false, "count": 1, "darkened": false, "front": true }, "date": "2025-01-10", "disambiguation": "", "genres": [], "id": "a5ce1d11-2e32-45a4-b37f-c1589d46b103", "label_info": [ { "catalog_number": "Lilas-020", "label": { "aliases": [ { "begin": null, "end": null, "ended": false, "locale": null, "name": "2636621 Records DK", "primary": null, "sort_name": "2636621 Records DK", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Antipole", "primary": null, "sort_name": "Antipole", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Auto production", "primary": null, "sort_name": "Auto production", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Auto-Edición", "primary": null, "sort_name": "Auto-Edición", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Auto-Product", "primary": null, "sort_name": "Auto-Product", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Autoedición", "primary": null, "sort_name": "Autoedición", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Autoeditado", "primary": null, "sort_name": "Autoeditado", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Autoproduit", "primary": null, "sort_name": "Autoproduit", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Banana Skin Records", "primary": null, "sort_name": "Banana Skin Records", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Cannelle", "primary": null, "sort_name": "Cannelle", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Cece Natalie", "primary": null, "sort_name": "Cece Natalie", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Cherry X", "primary": null, "sort_name": "Cherry X", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Chung", "primary": null, "sort_name": "Chung", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Cody Johnson", "primary": null, "sort_name": "Cody Johnson", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Cowgirl Clue", "primary": null, "sort_name": "Cowgirl Clue", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "D.I.Y.", "primary": null, "sort_name": "D.I.Y.", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Damjan Mravunac Self-released)", "primary": null, "sort_name": "Damjan Mravunac Self-released)", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Demo", "primary": null, "sort_name": "Demo", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "DistroKid", "primary": null, "sort_name": "DistroKid", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Egzod", "primary": null, "sort_name": "Egzod", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Eigenverlag", "primary": null, "sort_name": "Eigenverlag", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Eigenvertrieb", "primary": null, "sort_name": "Eigenvertrieb", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "GRIND MODE", "primary": null, "sort_name": "GRIND MODE", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "INDIPENDANT", "primary": null, "sort_name": "INDIPENDANT", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Indepandant", "primary": null, "sort_name": "Indepandant", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Independant release", "primary": null, "sort_name": "Independant release", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Independent", "primary": null, "sort_name": "Independent", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Independente", "primary": null, "sort_name": "Independente", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Independiente", "primary": null, "sort_name": "Independiente", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Indie", "primary": null, "sort_name": "Indie", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Joost Klein", "primary": null, "sort_name": "Joost Klein", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Millington Records", "primary": null, "sort_name": "Millington Records", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "MoroseSound", "primary": null, "sort_name": "MoroseSound", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "N/A", "primary": null, "sort_name": "N/A", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "No Label", "primary": null, "sort_name": "No Label", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "None", "primary": null, "sort_name": "None", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "None Like Joshua", "primary": null, "sort_name": "None Like Joshua", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Not On A Lebel", "primary": null, "sort_name": "Not On A Lebel", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Not On Label", "primary": null, "sort_name": "Not On Label", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Offensively Average Productions", "primary": null, "sort_name": "Offensively Average Productions", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Ours", "primary": null, "sort_name": "Ours", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "P2019", "primary": null, "sort_name": "P2019", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "P2020", "primary": null, "sort_name": "P2020", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "P2021", "primary": null, "sort_name": "P2021", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "P2022", "primary": null, "sort_name": "P2022", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "P2023", "primary": null, "sort_name": "P2023", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "P2024", "primary": null, "sort_name": "P2024", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "P2025", "primary": null, "sort_name": "P2025", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Patriarchy", "primary": null, "sort_name": "Patriarchy", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Plini", "primary": null, "sort_name": "Plini", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Records DK", "primary": null, "sort_name": "Records DK", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Self Digital", "primary": null, "sort_name": "Self Digital", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Self Release", "primary": null, "sort_name": "Self Release", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Self Released", "primary": null, "sort_name": "Self Released", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Self-release", "primary": null, "sort_name": "Self-release", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Self-released", "primary": null, "sort_name": "Self-released", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Self-released/independent", "primary": null, "sort_name": "Self-released/independent", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Sevdaliza", "primary": null, "sort_name": "Sevdaliza", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "TOMMY CASH", "primary": null, "sort_name": "TOMMY CASH", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Take Van", "primary": null, "sort_name": "Take Van", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Talwiinder", "primary": null, "sort_name": "Talwiinder", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Unsigned", "primary": null, "sort_name": "Unsigned", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "VGR", "primary": null, "sort_name": "VGR", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "Woo Da Savage", "primary": null, "sort_name": "Woo Da Savage", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "YANAA", "primary": null, "sort_name": "YANAA", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": "fi", "name": "[ei levymerkkiä]", "primary": true, "sort_name": "ei levymerkkiä", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "nl", "name": "[geen platenmaatschappij]", "primary": true, "sort_name": "[geen platenmaatschappij]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "et", "name": "[ilma plaadifirmata]", "primary": false, "sort_name": "[ilma plaadifirmata]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "es", "name": "[nada]", "primary": true, "sort_name": "[nada]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "en", "name": "[no label]", "primary": true, "sort_name": "[no label]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "[nolabel]", "primary": null, "sort_name": "[nolabel]", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "[none]", "primary": null, "sort_name": "[none]", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": "lt", "name": "[nÄ—ra leidybinÄ—s kompanijos]", "primary": false, "sort_name": "[nÄ—ra leidybinÄ—s kompanijos]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "lt", "name": "[nÄ—ra leidyklos]", "primary": false, "sort_name": "[nÄ—ra leidyklos]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "lt", "name": "[nÄ—ra įrašų kompanijos]", "primary": true, "sort_name": "[nÄ—ra įrašų kompanijos]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "et", "name": "[puudub]", "primary": false, "sort_name": "[puudub]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "ru", "name": "[Ñ�амиздат]", "primary": false, "sort_name": "samizdat", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": "ja", "name": "[レーベルã�ªã�—]", "primary": true, "sort_name": "[レーベルã�ªã�—]", "type": "Label name", "type_id": "3a1a0c48-d885-3b89-87b2-9e8a483c5675" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "annapantsu music", "primary": null, "sort_name": "annapantsu music", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "auto-release", "primary": null, "sort_name": "auto-release", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "autoprod.", "primary": null, "sort_name": "autoprod.", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "ayesha erotica", "primary": null, "sort_name": "ayesha erotica", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "blank", "primary": null, "sort_name": "blank", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "cupcakKe", "primary": null, "sort_name": "cupcakKe", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "d.silvestre", "primary": null, "sort_name": "d.silvestre", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "dj-Jo", "primary": null, "sort_name": "dj-Jo", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "independent release", "primary": null, "sort_name": "independent release", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "lor2mg", "primary": null, "sort_name": "lor2mg", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "nyamura", "primary": null, "sort_name": "nyamura", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "pls dnt stp", "primary": null, "sort_name": "pls dnt stp", "type": null, "type_id": null }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "self", "primary": null, "sort_name": "self", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "self issued", "primary": null, "sort_name": "self issued", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "self-issued", "primary": null, "sort_name": "self-issued", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "white label", "primary": null, "sort_name": "white label", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "но лабел", "primary": null, "sort_name": "но лабел", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" }, { "begin": null, "end": null, "ended": false, "locale": null, "name": "独立å�‘行", "primary": null, "sort_name": "独立å�‘行", "type": "Search hint", "type_id": "829662f2-a781-3ec8-8b46-fbcea6196f81" } ], "disambiguation": "Special purpose label – white labels, self-published releases and other “no labelâ€� releases", "genres": [], "id": "157afde4-4bf5-4039-8ad2-5a15acc85176", "label_code": null, "name": "[no label]", "sort_name": "[no label]", "tags": [ { "count": 12, "name": "special purpose" }, { "count": 18, "name": "special purpose label" } ], "type": "Production", "type_id": "a2426aab-2dd4-339c-b47d-b4923a241678" } } ], "media": [ { "format": "Digital Media", "format_id": "907a28d9-b3b2-3ef6-89a8-7b18d91d4794", "id": "43f08d54-a896-3561-be75-b881cbc832d5", "position": 1, "title": "", "track_count": 1, "track_offset": 0, "tracks": [ { "artist_credit": [ { "artist": { "aliases": [ { "begin": null, "end": null, "ended": false, "locale": "en", "name": "Lilas Ikuta", "primary": true, "sort_name": "Ikuta, Lilas", "type": "Artist name", "type_id": "894afba6-2816-3c24-8072-eadb66bd04bc" } ], "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "joinphrase": "", "name": "幾田りら" } ], "id": "0bd01e8b-18e1-4708-b0a3-c9603b89ab97", "length": 179239, "number": "1", "position": 1, "recording": { "aliases": [], "artist_credit": [ { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "joinphrase": "", "name": "幾田りら" } ], "artist_relations": [ { "artist": { "country": "JP", "disambiguation": "Japanese composer/arranger/guitarist, agehasprings", "id": "f24241fb-4d89-4bf2-8336-3f2a7d2c0025", "name": "KOHD", "sort_name": "KOHD", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "arranger", "type_id": "22661fb8-cdb7-4f67-8385-b2a8be6c9f0d" }, { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": "2025", "direction": "backward", "end": "2025", "ended": true, "source_credit": "", "target_credit": "Lilas Ikuta", "type": "phonographic copyright", "type_id": "7fd5fbc0-fbf4-4d04-be23-417d50a4dc30" }, { "artist": { "country": "JP", "disambiguation": "", "id": "1d27ab8a-a0df-47cf-b4cc-d2d7a0712a05", "name": "山本秀哉", "sort_name": "Yamamoto, Shuya", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "producer", "type_id": "5c0ceac3-feb4-41f0-868d-dc06f6e27fc0" }, { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "vocal", "type_id": "0fdbe3c6-7700-4a31-ae54-b53f06ae1cfa" } ], "disambiguation": "", "first_release_date": "2025-01-10", "genres": [], "id": "781724c1-a039-41e6-bd9b-770c3b9d5b8e", "isrcs": [ "JPP302400868" ], "length": 179546, "tags": [], "title": "百花繚乱", "url_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "free streaming", "type_id": "7e41ef12-a124-4324-afdb-fdbae687a89c", "url": { "id": "d076eaf9-5fde-4f6e-a946-cde16b67aa3b", "resource": "https://open.spotify.com/track/782PTXsbAWB70ySDZ5NHmP" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "92777657-504c-4acb-bd33-51a201bd57e1", "url": { "id": "64879627-6eca-4755-98b5-b2234a8dbc61", "resource": "https://music.apple.com/jp/song/1857886416" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "streaming", "type_id": "b5f3058a-666c-406f-aafb-f9249fc7b122", "url": { "id": "64879627-6eca-4755-98b5-b2234a8dbc61", "resource": "https://music.apple.com/jp/song/1857886416" } } ], "video": false, "work_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "performance", "type_id": "a3005666-a872-32c3-ad06-98af558e99b0", "work": { "artist_relations": [ { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "composer", "type_id": "d59d99ea-23d4-4a80-b066-edca32ee158f" }, { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "lyricist", "type_id": "3e48faba-ec01-47fd-8e89-30e81161661c" } ], "attributes": [], "disambiguation": "", "id": "9e14d6b2-ac7d-43e9-82a9-561bc76ce2ed", "iswcs": [], "language": "jpn", "languages": [ "jpn" ], "title": "百花繚乱", "type": "Song", "type_id": "f061270a-2fd6-32f1-a641-f0f8676d14e6", "url_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "lyrics", "type_id": "e38e65aa-75e0-42ba-ace0-072aeb91a538", "url": { "id": "dfac3640-6b23-4991-a59c-7cb80e8eb950", "resource": "https://utaten.com/lyric/tt24121002/" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "lyrics", "type_id": "e38e65aa-75e0-42ba-ace0-072aeb91a538", "url": { "id": "b1b5d5df-e79d-4cda-bb2a-8014e5505415", "resource": "https://www.uta-net.com/song/366579/" } } ] } } ] }, "title": "百花繚乱" } ] } ], "packaging": "None", "packaging_id": "119eba76-b343-3e02-a292-f0f00644bb9b", "quality": "normal", "release_events": [ { "area": { "disambiguation": "", "id": "525d4e18-3d00-31b9-a58b-a146a916de8f", "iso_3166_1_codes": [ "XW" ], "name": "[Worldwide]", "sort_name": "[Worldwide]", "type": null, "type_id": null }, "date": "2025-01-10" } ], "release_group": { "aliases": [], "artist_credit": [ { "artist": { "aliases": [ { "begin": null, "end": null, "ended": false, "locale": "en", "name": "Lilas Ikuta", "primary": true, "sort_name": "Ikuta, Lilas", "type": "Artist name", "type_id": "894afba6-2816-3c24-8072-eadb66bd04bc" } ], "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "joinphrase": "", "name": "幾田りら" } ], "disambiguation": "", "first_release_date": "2025-01-10", "genres": [], "id": "da0d6bbb-f44b-4fff-8739-9d72db0402a1", "primary_type": "Single", "primary_type_id": "d6038452-8ee0-3f68-affc-2de9a1ede0b9", "secondary_type_ids": [], "secondary_types": [], "tags": [], "title": "百花繚乱" }, "release_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "release": { "artist_credit": [ { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": null, "type_id": null }, "joinphrase": "", "name": "Lilas Ikuta" } ], "barcode": null, "disambiguation": "", "id": "dc3ee2df-0bc1-49eb-b8c4-34473d279a43", "media": [], "packaging": null, "packaging_id": null, "quality": "normal", "release_group": null, "status": null, "status_id": null, "text_representation": { "language": "eng", "script": "Latn" }, "title": "In Bloom" }, "source_credit": "", "target_credit": "", "type": "transl-tracklisting", "type_id": "fc399d47-23a7-4c28-bfcf-0607a562b644" } ], "status": "Official", "status_id": "4e304316-386d-3409-af2e-78857eec5cfe", "tags": [], "text_representation": { "language": "jpn", "script": "Jpan" }, "title": "百花繚乱", "url_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "amazon asin", "type_id": "4f2e710d-166c-480c-a293-2e2c8d658d87", "url": { "id": "b50c7fb8-2327-4a05-b989-f2211a41afee", "resource": "https://www.amazon.co.jp/gp/product/B0DR8Y2YDC" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "free streaming", "type_id": "08445ccf-7b99-4438-9f9a-fb9ac18099ee", "url": { "id": "5106a7b0-1443-4803-91a2-28cac2cfb5e0", "resource": "https://open.spotify.com/album/3LDV2xGL9HiqCsQujEPQLb" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "free streaming", "type_id": "08445ccf-7b99-4438-9f9a-fb9ac18099ee", "url": { "id": "d481d94b-a7bf-4e82-8da0-1757fedcda62", "resource": "https://www.deezer.com/album/687686261" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "98e08c20-8402-4163-8970-53504bb6a1e4", "url": { "id": "6156d2e4-d107-43f9-8f44-52f04d39c78e", "resource": "https://mora.jp/package/43000011/199066336168/" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "98e08c20-8402-4163-8970-53504bb6a1e4", "url": { "id": "a4eabb88-1746-4aa2-ab09-c28cfbe65efb", "resource": "https://mora.jp/package/43000011/199066336168_HD/" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "98e08c20-8402-4163-8970-53504bb6a1e4", "url": { "id": "ab8440f0-3b13-4436-b3ad-f4695c9d8875", "resource": "https://mora.jp/package/43000011/199066336168_LL/" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "98e08c20-8402-4163-8970-53504bb6a1e4", "url": { "id": "9a8ee8d1-f946-44a1-be16-8f7a77c951e9", "resource": "https://music.apple.com/jp/album/1786972161" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "98e08c20-8402-4163-8970-53504bb6a1e4", "url": { "id": "c6faaa80-38fb-46a4-aa2b-78cddc5cbe70", "resource": "https://ototoy.jp/_/default/p/2501951" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "98e08c20-8402-4163-8970-53504bb6a1e4", "url": { "id": "0e7e8bc5-0779-492d-a9db-9ab58f96d23b", "resource": "https://www.qobuz.com/jp-ja/album/lilas-ikuta-/fl9tx2j78reza" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "98e08c20-8402-4163-8970-53504bb6a1e4", "url": { "id": "c0cf8fe0-3413-4544-a026-37d346a59a77", "resource": "https://www.qobuz.com/jp-ja/album/lilas-ikuta-/l1dnc4xoi6l7a" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "streaming", "type_id": "320adf26-96fa-4183-9045-1f5f32f833cb", "url": { "id": "e4ce55a9-a5e1-4842-b42d-11be6a31fdab", "resource": "https://music.amazon.co.jp/albums/B0DR8Y2YDC" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "streaming", "type_id": "320adf26-96fa-4183-9045-1f5f32f833cb", "url": { "id": "9a8ee8d1-f946-44a1-be16-8f7a77c951e9", "resource": "https://music.apple.com/jp/album/1786972161" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "vgmdb", "type_id": "6af0134a-df6a-425a-96e2-895f9cd342ba", "url": { "id": "1885772a-4004-4d45-9512-d0c8822506c9", "resource": "https://vgmdb.net/album/145936" } } ] } beetbox-beets-00724b7/test/rsrc/mbpseudo/pseudo_release.json0000664000175000017500000004131515253035401023517 0ustar pieterpieter{ "aliases": [], "artist_credit": [ { "artist": { "aliases": [ { "begin": null, "end": null, "ended": false, "locale": "en", "name": "Lilas Ikuta", "primary": true, "sort_name": "Ikuta, Lilas", "type": "Artist name", "type_id": "894afba6-2816-3c24-8072-eadb66bd04bc" } ], "country": "JP", "disambiguation": "", "genres": [ { "count": 1, "disambiguation": "", "id": "eba7715e-ee26-4989-8d49-9db382955419", "name": "j-pop" }, { "count": 1, "disambiguation": "", "id": "455f264b-db00-4716-991d-fbd32dc24523", "name": "singer-songwriter" } ], "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "tags": [ { "count": 1, "name": "j-pop" }, { "count": 1, "name": "singer-songwriter" } ], "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "joinphrase": "", "name": "Lilas Ikuta" } ], "asin": null, "barcode": null, "cover_art_archive": { "artwork": false, "back": false, "count": 0, "darkened": false, "front": false }, "disambiguation": "", "genres": [], "id": "dc3ee2df-0bc1-49eb-b8c4-34473d279a43", "label_info": [], "media": [ { "format": "Digital Media", "format_id": "907a28d9-b3b2-3ef6-89a8-7b18d91d4794", "id": "606faab7-60fa-3a8b-a40f-2c66150cce81", "position": 1, "title": "", "track_count": 1, "track_offset": 0, "tracks": [ { "artist_credit": [ { "artist": { "aliases": [ { "begin": null, "end": null, "ended": false, "locale": "en", "name": "Lilas Ikuta", "primary": true, "sort_name": "Ikuta, Lilas", "type": "Artist name", "type_id": "894afba6-2816-3c24-8072-eadb66bd04bc" } ], "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "joinphrase": "", "name": "Lilas Ikuta" } ], "id": "2018b012-a184-49a2-a464-fb4628a89588", "length": 179239, "number": "1", "position": 1, "recording": { "aliases": [], "artist_credit": [ { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "joinphrase": "", "name": "幾田りら" } ], "artist_relations": [ { "artist": { "country": "JP", "disambiguation": "Japanese composer/arranger/guitarist, agehasprings", "id": "f24241fb-4d89-4bf2-8336-3f2a7d2c0025", "name": "KOHD", "sort_name": "KOHD", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "arranger", "type_id": "22661fb8-cdb7-4f67-8385-b2a8be6c9f0d" }, { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": "2025", "direction": "backward", "end": "2025", "ended": true, "source_credit": "", "target_credit": "Lilas Ikuta", "type": "phonographic copyright", "type_id": "7fd5fbc0-fbf4-4d04-be23-417d50a4dc30" }, { "artist": { "country": "JP", "disambiguation": "", "id": "1d27ab8a-a0df-47cf-b4cc-d2d7a0712a05", "name": "山本秀哉", "sort_name": "Yamamoto, Shuya", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "producer", "type_id": "5c0ceac3-feb4-41f0-868d-dc06f6e27fc0" }, { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "vocal", "type_id": "0fdbe3c6-7700-4a31-ae54-b53f06ae1cfa" } ], "disambiguation": "", "first_release_date": "2025-01-10", "genres": [], "id": "781724c1-a039-41e6-bd9b-770c3b9d5b8e", "isrcs": [ "JPP302400868" ], "length": 179546, "tags": [], "title": "百花繚乱", "url_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "free streaming", "type_id": "7e41ef12-a124-4324-afdb-fdbae687a89c", "url": { "id": "d076eaf9-5fde-4f6e-a946-cde16b67aa3b", "resource": "https://open.spotify.com/track/782PTXsbAWB70ySDZ5NHmP" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "purchase for download", "type_id": "92777657-504c-4acb-bd33-51a201bd57e1", "url": { "id": "64879627-6eca-4755-98b5-b2234a8dbc61", "resource": "https://music.apple.com/jp/song/1857886416" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "streaming", "type_id": "b5f3058a-666c-406f-aafb-f9249fc7b122", "url": { "id": "64879627-6eca-4755-98b5-b2234a8dbc61", "resource": "https://music.apple.com/jp/song/1857886416" } } ], "video": false, "work_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "forward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "performance", "type_id": "a3005666-a872-32c3-ad06-98af558e99b0", "work": { "artist_relations": [ { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "composer", "type_id": "d59d99ea-23d4-4a80-b066-edca32ee158f" }, { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "lyricist", "type_id": "3e48faba-ec01-47fd-8e89-30e81161661c" } ], "attributes": [], "disambiguation": "", "id": "9e14d6b2-ac7d-43e9-82a9-561bc76ce2ed", "iswcs": [], "language": "jpn", "languages": [ "jpn" ], "title": "百花繚乱", "type": "Song", "type_id": "f061270a-2fd6-32f1-a641-f0f8676d14e6", "url_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "lyrics", "type_id": "e38e65aa-75e0-42ba-ace0-072aeb91a538", "url": { "id": "dfac3640-6b23-4991-a59c-7cb80e8eb950", "resource": "https://utaten.com/lyric/tt24121002/" } }, { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "source_credit": "", "target_credit": "", "type": "lyrics", "type_id": "e38e65aa-75e0-42ba-ace0-072aeb91a538", "url": { "id": "b1b5d5df-e79d-4cda-bb2a-8014e5505415", "resource": "https://www.uta-net.com/song/366579/" } } ] } } ] }, "title": "In Bloom" } ] } ], "packaging": null, "packaging_id": null, "quality": "normal", "release_group": { "aliases": [], "artist_credit": [ { "artist": { "aliases": [ { "begin": null, "end": null, "ended": false, "locale": "en", "name": "Lilas Ikuta", "primary": true, "sort_name": "Ikuta, Lilas", "type": "Artist name", "type_id": "894afba6-2816-3c24-8072-eadb66bd04bc" } ], "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": "Person", "type_id": "b6e035f4-3ce9-331c-97df-83397230b0df" }, "joinphrase": "", "name": "幾田りら" } ], "disambiguation": "", "first_release_date": "2025-01-10", "genres": [], "id": "da0d6bbb-f44b-4fff-8739-9d72db0402a1", "primary_type": "Single", "primary_type_id": "d6038452-8ee0-3f68-affc-2de9a1ede0b9", "secondary_type_ids": [], "secondary_types": [], "tags": [], "title": "百花繚乱" }, "release_relations": [ { "attribute_ids": {}, "attribute_values": {}, "attributes": [], "begin": null, "direction": "backward", "end": null, "ended": false, "release": { "artist_credit": [ { "artist": { "country": "JP", "disambiguation": "", "id": "55e42264-ef27-49d8-93fd-29f930dc96e4", "name": "幾田りら", "sort_name": "Ikuta, Lilas", "type": null, "type_id": null }, "joinphrase": "", "name": "幾田りら" } ], "barcode": "199066336168", "country": "XW", "date": "2025-01-10", "disambiguation": "", "id": "a5ce1d11-2e32-45a4-b37f-c1589d46b103", "media": [], "packaging": null, "packaging_id": null, "quality": "normal", "release_events": [ { "area": { "disambiguation": "", "id": "525d4e18-3d00-31b9-a58b-a146a916de8f", "iso_3166_1_codes": [ "XW" ], "name": "[Worldwide]", "sort_name": "[Worldwide]", "type": null, "type_id": null }, "date": "2025-01-10" } ], "release_group": null, "status": null, "status_id": null, "text_representation": { "language": "jpn", "script": "Jpan" }, "title": "百花繚乱" }, "source_credit": "", "target_credit": "", "type": "transl-tracklisting", "type_id": "fc399d47-23a7-4c28-bfcf-0607a562b644" } ], "status": "Pseudo-Release", "status_id": "41121bb9-3413-3818-8a9a-9742318349aa", "tags": [], "text_representation": { "language": "eng", "script": "Latn" }, "title": "In Bloom" } beetbox-beets-00724b7/test/rsrc/playlist.m3u80000664000175000017500000000011415253035401020356 0ustar pieterpieter#EXTM3U /This/is/Ã¥/path/to_a_file.mp3 /This/is/another/path/tö_a_file.mp3 beetbox-beets-00724b7/test/rsrc/date_with_slashes.ogg0000664000175000017500000002056215253035401022200 0ustar pieterpieterOggSþ–ç=݃[vorbisD¬€»€»€»¸OggSþ–ç=­9s„@ÿÿÿÿÿÿÿÿÿÿÿÿÿ2vorbisXiph.Org libVorbis I 20050304date=2005/06/05vorbisBCVcT)F™RÒJ‰s”1F™b’J‰¥„BH�sS©9לk¬¹µ „SP)™RŽRic�)™RKI%t:'�c[IÁÖ˜k‹A¶„ šRL)Ä”RŠBSŒ)Å”RJB%t:æSŽJ(A¸œs«µ––c‹©t’Jç$dLBH)…’J¥SNBH5–ÖR)sRRjAè „B¶ „ ‚Ð�UÀ@² PСЄ†¬2 (Žâ(Ž#9’cI² ÀpI‘ɱ$KÒ,KÓDQU}Õ6UUöu]×u]×u 4d@H§™¥  d Y F(ÂBCVb(9ˆ&´æ|sŽƒf9h*Åætp"ÕæIn*ææœsÎ9'›sÆ8çœsŠrf1h&´æœsƒf)h&´æœsžÄæAkª´æœsÆ9§ƒqFçœsš´æAj6Öæœs´¦9j.Åæœs"åæIm.ÕæœsÎ9çœsÎ9çœsª§spN8çœs¢öæZnBçœs>§{sB8çœsÎ9çœsÎ9çœs‚Ð�UA6†q§ HŸ£�EˆiȤÝ£Ã$h r ©G££‘Rê ”TÆI)� 4d!„RH!…RH!…Rˆ!†bÈ)§œ‚ *©¤¢Š2Ê,³Ì2Ë,³Ì2ë°³Î:ì0ÄC ­´KMµÕXc­¹çœkÒZi­µÖJ)¥”RJ) Y€d�AF!…Rˆ!¦œrÊ)¨ BCV€<ÉsDGtDGtDGtDGtDÇsUõ}Sv…áteß×…ßYn]8–Ñu}a•máXeY9~áX–Ý÷•et]_XmÙVY†_ø�åö}ãxu]nÝç̺ï Çï¤ûÊÓÕmc™}ÝYf_wŽá:¿ð㩪¯›®+ §, ¿íëÆ³û¾²Œ®ëûª, ¿*Û±ë¾óü¾°,£ìúÂj˰ڶ1ܾn,¿pËkëÊ1ë¾Q¶u|_x Ãótu]yf]ÇöutãG8~Ê€€Ê@¡!+€8�$‰¢dY¢(Y–(Š¦èº¢hº®¤i¦©ižiZšgš¦iª²)š®,išiZžfšš§™¦hš®kš¦¬Š¦)˦jʲiš²ìº²m»®lÛ¢iʲiš²lš¦,»²«Û®ì꺤Y¦©yžijžgš¦jʲiš®«yžjzžhªž(ªªjªª­ªª,[žgššè©¦'Šªjª¦­šª*˦ªÚ²iª¶lªªm»ªìú²mëºiª²mª¦-›ªjÛ®ìê²,Ûº/išijžgššç™¦iš²lšª+[ž§šž(ªªæ‰¦jªª,›¦ªÊ–癪'Šªê‰žkšª*˦jÚªiš¶lªª-›¦*Ë®mû¾ëʲnªªl›ªjë¦jʲl˾ïʪ)˦ªÚ²iª²-Û²ï˲¬û¢iʲiª²mªª.˲m³lûºhš²mª¦-›ª*Û²-ûº,ÛºïÊ®o«ª¬ë²-ûºîú®pëº0¼²lûª¬úº+Ûºoë2Ûö}DÓ”eS5mÛTUYveÙöeÛö}Ñ4m[UU[6MÕ¶eYö}Y¶ma4MÙ6UUÖMÕ´mY–ma¶eáveÙ·e[öuוu_×}ã×eÝæº²í˲­ûª«ú¶îûÂpë®ð p0¡ ²ˆŒaŒ1�RÎ9¡QÊ9ç dÎA!•Ì9!”’9¡””2ç ”’R¡””Z !””Rk8Ø )±8@¡!+€TƒãX–癢jÚ²cIž'Šª©ª¶íH–牢iªªm[ž'Ц©ª®ëëšç‰¢iªªëêºhš¦©ª®ëºº.š¢©ªªëº²®›¦ªª®+»²ì릪ªªëÊ®,ûªº®+˲më°ª®ëʲlÛ¶oܺ®ë¾ïû‘­ëº.üÂ1 Gà @6¬ŽpR4XhÈJ €0!ƒB!„�RJ!¥”0à`B(4dE'C)¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RH)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ©¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)•RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”R �Šp�z0¡ ²HŒQJ)Æœƒ1æcÐI()bÌ9Æ”’Rå„Ri-·Ê9!¤ÔRm™sRZ‹1æ3礤[Í9‡RR‹±æškVk®5çZZ«5לs͹´k®9לsË1לsÎ9çsÎ9çœsÎà48€ذ:ÂIÑX`¡!+€T¥sÎ9èRŒ9ç„"…sÎ9!TŒ9çtB¨sÌ9!„�9ç„B!s:è „B„B¡”ÎA!„J(!„B!„:!„B!„B!„RJ!„B ¡”P`�@€ «#œ�²€– R΄AŽA� AÊQ3 BL9Ñ™bNj3S�9�tjAÙ^2 € À (øBˆ1AˆÌ …U°À  æÀD„D�˜ H»¸€.\ÐÅ]BB‚X@ 88á†'Þð„œ STê àà ""š«°¸ÀÈÐØàèðø8>€ˆˆæ*,.02468:<€€€@€€OggS@–þ–ç=ý‚å'02310276;:?CCBl…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹¬Ø%ô B8FkF#ëœzÊýýžåJI`Ÿ76BU5À: š†îK.Þ[/IÀ´˜˜€Ž€ ~ÊýýžåJ¼çÛJÙ@!TÕ€ €z wPˆ{@Û‚š_,ß5ðè@ 4>ªýÿüå žík¥°@!TUè40ÑMtô™àÉÆ+ÚÙÁ…WÇуàÐ>ªýÿüšäâvy¨…PU¡ô…|G×�OӱЂ††�ÊpBÀ&€>ªýÿüšäîô4ª…PU'Ð@$¸O}�Ç%åMÒ;†:€ žä>ªýÿüšäÒ´ð&”ªÊ* @t𨴯ùçaï¥)t (4 ƒ˜šýÿOre1éM0BU 1>ÞY(¥ÚsYÀ&-RJgè¡ÕMkòØÀ‚VšýÿOr¥2ØåIØUUÅ@EO5š‚nE~IôÆÓ´JÊqØ)d¢U)°$ @šýÿOr¥28åMèªÊj ÌY�¬"æeç…d×Ôdþ‘òcw¢ ±“¦‘€d :šýÿOr¥`°Û›¸TU:Ì]¹¤¿\Ïô³\ÏÒ{QFH4¬T05Þyýök”‹2¸ÛÛXaE…P + &EÒæ^ ô#©”¶&Ú!ir}Ï””Ωaku¨“)lY �‚&˜ HÞyýök”‹2˜íMP*jT¦Þ1{Ã�1^_Y•¢~vçt×ZŸ}¹.ó­¡£ª9“5\1á)èàÁ_#ÞyýÿþåR Ny“B1ê,˜r(¶Øò³4ptmp sR›¦£L/g9‚èÞ?®Í0—M)°”,ZýÎu¹ƒ‘Þ8 4´X‰ h©u À÷ßÒ‹ö~>S£Èü†ý$=cr¦Èß7²ü¼öŽ¥ÏÃŒóù0ƒÊ«®b¥*¯ß·þQ�ÿŠá¨Y4®#öO¤Å± Š«=¡ P{údX]ÎÔýÎ59 £¼ „f)6ðÖ”³A`fœ“€½^�Ä!ƒ<©¬˜i0/d¥·?/Ôh³=é«m¤ò¶Þ­™ž��wÛÕZ:Ý–ÿ‰�^®¦×Ö‘&uVwû’CÅ_Åjð-˜mŒýÎu9 %½ Ð"++IÀ@âÊAGÕ�rý5]óo”X€¯/sãÎ�\ú çHÇ‘ÙqoÅóÈÐ3ú.+¼ð¬qÖ\E�¬SF’¿1R-à"ç ÜI¦ÏlÂjÂɘÌìæˆýÎwÙ4-= Ĥ¼ÌdÀ¢ÐIà,1æ8‘qü]âj­_è÷⥧Թéô''ïsçõu|‰ìwûæ¹ÅÇë�³Îå‹�/ó¡<:�0ÑÛå$¡Í½'—3Œˆí®�ý ýÎu9q­< B¡¡ËÂÉg�Pà€~57kg§P¿d´]�ÙÛü¹œÎo¿’_Ú¹Js)êã5÷Òä¤Åp–ô•õÚc\^;Ç¥QåtFôbˆ[D®áì §­“ýÎ5¹ƒVÞh’ʦ¡°@vv¿´ÄN˜¾d ¦²²Ki*¯u67[˜`&· 'nV‡§¯‹“ËÈcºt“Ÿq’C>-VþFŸÄ¼VÙ ]êïtGNÊy49ªéaœÙMãýÎ5¹ƒä�¡Xd‰‘\%`8�'\àÁÁû5ô�7‰M?/'x‘,ׯ×}Y¿Ž½nmcfFU)¸¸ð“‡0ÙëÞ¾ÕÑøÚ��·•êP[©+T²ûë¼ý2š\ÍüÓSœ ÂG.W¹èX©;·åUFÀhkôo†FØ/÷àÂu cÊ:ýÎ7Ùƒ–Þ8€˜š• ›0Ød7•\´×vÎ}ií½E«MÝ M3‹Š"äðºÏ~µ½b³¶#Ah©'òR‚ÑÖ&y,]~�MG“-9¶#8…þùäë¼�#s/yýÎ7Ù8ƒQ¾1ˆ•Ö%ˆ8€iup;š¤_I5…ÀÖÿ?»ØÄ&òÒµädu¡n±{½ï…é!‰Ÿ»:•¬Ï…úzÅU.25žBÉ–+Êèq0ïîQ®*/CUë&^ܱé-ýÎ59q#} „&å68ZÀ€ôлt3ü´WÜ™ohm™äP»-¨Y?Ç{ž°êŽLXø8&MöØ f%ªO©›÷NÉ”‰Íͯ®b¢ì½›ìÎÈPw¡ëWI;–ýÎwÙ(ƒ–ž„*hRdÁPL�Kºá?7œ�I—»B��Á¦Ñ|_O&±arúäºvQà$¹k×°d­Áå²l­Lc/["°R#lcú,èVÀÝ�Š…«äàHïbz¬Û{8˜TýÎ7Ù8ƒQÞ1ˆÉJQ3=HÐi—� ‚©æÊì•ä¸óM6¿ÝRmöµ|fê «ö’ôÑZ*Ìü(NbÎÑÙ&ç²ýÎu¹ƒ–ž@-jIÁ…&&èh‹o\ˆœ‰[¢ÆüJx2ÝÏÚ ^Cí7^:«YGcF¦òO}žÝºž‡ƒž�™‰°±<É~¾¬2Pâü"SÔÞ‰íõªÀö™!Gæ&ÛóS’‰�ÎI…¨ýÎu¹8ƒQÞ(BÌR¬H¦Ð‡YB,ƒ’²-oÅx3CT§XÈèòßÑ| éÈÓùÆûѳ^^ª„^‰)5=‚%G½pïb€{fy](€>(Ö÷:;ubjÙ:kGG:OggSD¬þ–ç=‡¿²¬‹‹‹‹‹‹ýÎ59 %½ ‚”. :>�þè]µ¤?÷TãÌxL€çsÔ˜žM›PÏXšÁ„—+q!^#§ÃaâèÑ|S«ã.�„™ãµ•«Q®%(Îsnå¶©lõ]”N-{~ýÎwÙ8ƒ™ž0B“b…qÄñ–X9vñ)l}¬Å¼�b‘Id=!û…t,W¢7Åæÿ9±¸õñ­Ûÿâ® Rñˆçƒfƒ©ÄÀoé<ïËÓ—·§¾UÚe±”׫üpõ0Úé[(wÉÎ"…ýÎu¹8ƒ–Þ„2h–¢"hrðÈ)=|éP›Û"ýr:Iò"q�ö°Ì˜è¹¨š¯à޾Rß"à€"«•uÞ½‰ þ¹Ú‡¿š.øAsñ©Ïˆnµïn7…£'òèeŽ~ ýÎu¹ƒÞ0B Í c@2 °8èä>h»ï_6ƒzyu—YÆü|$Ô•»¹Žëö¬ÊÀÅ…÷ñSìÙ n'E²0!¸¶²ö>~v3üayè™zŸ›9óMÔk ¦1×5„éW7ñ#ÞežÈiýÎwÙ8ƒ‘ž1h–bÞFh‚¦zmœòp4<¯å²é*é´ ´ÚäœÉ"N¨„ªñ|oâSðjl’ÌôøœxŽMqIß–Š'S´Î—WøKw®²:&U0TÌn;�‘bbž ÆPÈeýί² 8P‹<Üà0P8�Ó¹­j xz}]�Übeetbox-beets-00724b7/test/rsrc/empty.ogg0000664000175000017500000002053715253035401017646 0ustar pieterpieterOggSþ–ç=݃[vorbisD¬€»€»€»¸OggSþ–ç=8/Ï-ÿÿÿÿÿÿÿÿÿÿÿÿÿ2vorbisXiph.Org libVorbis I 20050304vorbisBCVcT)F™RÒJ‰s”1F™b’J‰¥„BH�sS©9לk¬¹µ „SP)™RŽRic�)™RKI%t:'�c[IÁÖ˜k‹A¶„ šRL)Ä”RŠBSŒ)Å”RJB%t:æSŽJ(A¸œs«µ––c‹©t’Jç$dLBH)…’J¥SNBH5–ÖR)sRRjAè „B¶ „ ‚Ð�UÀ@² PСЄ†¬2 (Žâ(Ž#9’cI² ÀpI‘ɱ$KÒ,KÓDQU}Õ6UUöu]×u]×u 4d@H§™¥  d Y F(ÂBCVb(9ˆ&´æ|sŽƒf9h*Åætp"ÕæIn*ææœsÎ9'›sÆ8çœsŠrf1h&´æœsƒf)h&´æœsžÄæAkª´æœsÆ9§ƒqFçœsš´æAj6Öæœs´¦9j.Åæœs"åæIm.ÕæœsÎ9çœsÎ9çœsª§spN8çœs¢öæZnBçœs>§{sB8çœsÎ9çœsÎ9çœs‚Ð�UA6†q§ HŸ£�EˆiȤÝ£Ã$h r ©G££‘Rê ”TÆI)� 4d!„RH!…RH!…Rˆ!†bÈ)§œ‚ *©¤¢Š2Ê,³Ì2Ë,³Ì2ë°³Î:ì0ÄC ­´KMµÕXc­¹çœkÒZi­µÖJ)¥”RJ) Y€d�AF!…Rˆ!¦œrÊ)¨ BCV€<ÉsDGtDGtDGtDGtDÇsUõ}Sv…áteß×…ßYn]8–Ñu}a•máXeY9~áX–Ý÷•et]_XmÙVY†_ø�åö}ãxu]nÝç̺ï Çï¤ûÊÓÕmc™}ÝYf_wŽá:¿ð㩪¯›®+ §, ¿íëÆ³û¾²Œ®ëûª, ¿*Û±ë¾óü¾°,£ìúÂj˰ڶ1ܾn,¿pËkëÊ1ë¾Q¶u|_x Ãótu]yf]ÇöutãG8~Ê€€Ê@¡!+€8�$‰¢dY¢(Y–(Š¦èº¢hº®¤i¦©ižiZšgš¦iª²)š®,išiZžfšš§™¦hš®kš¦¬Š¦)˦jʲiš²ìº²m»®lÛ¢iʲiš²lš¦,»²«Û®ì꺤Y¦©yžijžgš¦jʲiš®«yžjzžhªž(ªªjªª­ªª,[žgššè©¦'Šªjª¦­šª*˦ªÚ²iª¶lªªm»ªìú²mëºiª²mª¦-›ªjÛ®ìê²,Ûº/išijžgššç™¦iš²lšª+[ž§šž(ªªæ‰¦jªª,›¦ªÊ–癪'Šªê‰žkšª*˦jÚªiš¶lªª-›¦*Ë®mû¾ëʲnªªl›ªjë¦jʲl˾ïʪ)˦ªÚ²iª²-Û²ï˲¬û¢iʲiª²mªª.˲m³lûºhš²mª¦-›ª*Û²-ûº,ÛºïÊ®o«ª¬ë²-ûºîú®pëº0¼²lûª¬úº+Ûºoë2Ûö}DÓ”eS5mÛTUYveÙöeÛö}Ñ4m[UU[6MÕ¶eYö}Y¶ma4MÙ6UUÖMÕ´mY–ma¶eáveÙ·e[öuוu_×}ã×eÝæº²í˲­ûª«ú¶îûÂpë®ð p0¡ ²ˆŒaŒ1�RÎ9¡QÊ9ç dÎA!•Ì9!”’9¡””2ç ”’R¡””Z !””Rk8Ø )±8@¡!+€TƒãX–癢jÚ²cIž'Šª©ª¶íH–牢iªªm[ž'Ц©ª®ëëšç‰¢iªªëêºhš¦©ª®ëºº.š¢©ªªëº²®›¦ªª®+»²ì릪ªªëÊ®,ûªº®+˲më°ª®ëʲlÛ¶oܺ®ë¾ïû‘­ëº.üÂ1 Gà @6¬ŽpR4XhÈJ €0!ƒB!„�RJ!¥”0à`B(4dE'C)¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RH)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ©¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)•RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”R �Šp�z0¡ ²HŒQJ)Æœƒ1æcÐI()bÌ9Æ”’Rå„Ri-·Ê9!¤ÔRm™sRZ‹1æ3礤[Í9‡RR‹±æškVk®5çZZ«5לs͹´k®9לsË1לsÎ9çsÎ9çœsÎà48€ذ:ÂIÑX`¡!+€T¥sÎ9èRŒ9ç„"…sÎ9!TŒ9çtB¨sÌ9!„�9ç„B!s:è „B„B¡”ÎA!„J(!„B!„:!„B!„B!„RJ!„B ¡”P`�@€ «#œ�²€– R΄AŽA� AÊQ3 BL9Ñ™bNj3S�9�tjAÙ^2 € À (øBˆ1AˆÌ …U°À  æÀD„D�˜ H»¸€.\ÐÅ]BB‚X@ 88á†'Þð„œ STê àà ""š«°¸ÀÈÐØàèðø8>€ˆˆæ*,.02468:<€€€@€€OggS@–þ–ç=ý‚å'02310276;:?CCBl…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹¬Ø%ô B8FkF#ëœzÊýýžåJI`Ÿ76BU5À: š†îK.Þ[/IÀ´˜˜€Ž€ ~ÊýýžåJ¼çÛJÙ@!TÕ€ €z wPˆ{@Û‚š_,ß5ðè@ 4>ªýÿüå žík¥°@!TUè40ÑMtô™àÉÆ+ÚÙÁ…WÇуàÐ>ªýÿüšäâvy¨…PU¡ô…|G×�OӱЂ††�ÊpBÀ&€>ªýÿüšäîô4ª…PU'Ð@$¸O}�Ç%åMÒ;†:€ žä>ªýÿüšäÒ´ð&”ªÊ* @t𨴯ùçaï¥)t (4 ƒ˜šýÿOre1éM0BU 1>ÞY(¥ÚsYÀ&-RJgè¡ÕMkòØÀ‚VšýÿOr¥2ØåIØUUÅ@EO5š‚nE~IôÆÓ´JÊqØ)d¢U)°$ @šýÿOr¥28åMèªÊj ÌY�¬"æeç…d×Ôdþ‘òcw¢ ±“¦‘€d :šýÿOr¥`°Û›¸TU:Ì]¹¤¿\Ïô³\ÏÒ{QFH4¬T05Þyýök”‹2¸ÛÛXaE…P + &EÒæ^ ô#©”¶&Ú!ir}Ï””Ωaku¨“)lY �‚&˜ HÞyýök”‹2˜íMP*jT¦Þ1{Ã�1^_Y•¢~vçt×ZŸ}¹.ó­¡£ª9“5\1á)èàÁ_#ÞyýÿþåR Ny“B1ê,˜r(¶Øò³4ptmp sR›¦£L/g9‚èÞ?®Í0—M)°”,ZýÎu¹ƒ‘Þ8 4´X‰ h©u À÷ßÒ‹ö~>S£Èü†ý$=cr¦Èß7²ü¼öŽ¥ÏÃŒóù0ƒÊ«®b¥*¯ß·þQ�ÿŠá¨Y4®#öO¤Å± Š«=¡ P{údX]ÎÔýÎ59 £¼ „f)6ðÖ”³A`fœ“€½^�Ä!ƒ<©¬˜i0/d¥·?/Ôh³=é«m¤ò¶Þ­™ž��wÛÕZ:Ý–ÿ‰�^®¦×Ö‘&uVwû’CÅ_Åjð-˜mŒýÎu9 %½ Ð"++IÀ@âÊAGÕ�rý5]óo”X€¯/sãÎ�\ú çHÇ‘ÙqoÅóÈÐ3ú.+¼ð¬qÖ\E�¬SF’¿1R-à"ç ÜI¦ÏlÂjÂɘÌìæˆýÎwÙ4-= Ĥ¼ÌdÀ¢ÐIà,1æ8‘qü]âj­_è÷⥧Թéô''ïsçõu|‰ìwûæ¹ÅÇë�³Îå‹�/ó¡<:�0ÑÛå$¡Í½'—3Œˆí®�ý ýÎu9q­< B¡¡ËÂÉg�Pà€~57kg§P¿d´]�ÙÛü¹œÎo¿’_Ú¹Js)êã5÷Òä¤Åp–ô•õÚc\^;Ç¥QåtFôbˆ[D®áì §­“ýÎ5¹ƒVÞh’ʦ¡°@vv¿´ÄN˜¾d ¦²²Ki*¯u67[˜`&· 'nV‡§¯‹“ËÈcºt“Ÿq’C>-VþFŸÄ¼VÙ ]êïtGNÊy49ªéaœÙMãýÎ5¹ƒä�¡Xd‰‘\%`8�'\àÁÁû5ô�7‰M?/'x‘,ׯ×}Y¿Ž½nmcfFU)¸¸ð“‡0ÙëÞ¾ÕÑøÚ��·•êP[©+T²ûë¼ý2š\ÍüÓSœ ÂG.W¹èX©;·åUFÀhkôo†FØ/÷àÂu cÊ:ýÎ7Ùƒ–Þ8€˜š• ›0Ød7•\´×vÎ}ií½E«MÝ M3‹Š"äðºÏ~µ½b³¶#Ah©'òR‚ÑÖ&y,]~�MG“-9¶#8…þùäë¼�#s/yýÎ7Ù8ƒQ¾1ˆ•Ö%ˆ8€iup;š¤_I5…ÀÖÿ?»ØÄ&òÒµädu¡n±{½ï…é!‰Ÿ»:•¬Ï…úzÅU.25žBÉ–+Êèq0ïîQ®*/CUë&^ܱé-ýÎ59q#} „&å68ZÀ€ôлt3ü´WÜ™ohm™äP»-¨Y?Ç{ž°êŽLXø8&MöØ f%ªO©›÷NÉ”‰Íͯ®b¢ì½›ìÎÈPw¡ëWI;–ýÎwÙ(ƒ–ž„*hRdÁPL�Kºá?7œ�I—»B��Á¦Ñ|_O&±arúäºvQà$¹k×°d­Áå²l­Lc/["°R#lcú,èVÀÝ�Š…«äàHïbz¬Û{8˜TýÎ7Ù8ƒQÞ1ˆÉJQ3=HÐi—� ‚©æÊì•ä¸óM6¿ÝRmöµ|fê «ö’ôÑZ*Ìü(NbÎÑÙ&ç²ýÎu¹ƒ–ž@-jIÁ…&&èh‹o\ˆœ‰[¢ÆüJx2ÝÏÚ ^Cí7^:«YGcF¦òO}žÝºž‡ƒž�™‰°±<É~¾¬2Pâü"SÔÞ‰íõªÀö™!Gæ&ÛóS’‰�ÎI…¨ýÎu¹8ƒQÞ(BÌR¬H¦Ð‡YB,ƒ’²-oÅx3CT§XÈèòßÑ| éÈÓùÆûѳ^^ª„^‰)5=‚%G½pïb€{fy](€>(Ö÷:;ubjÙ:kGG:OggSD¬þ–ç=‡¿²¬‹‹‹‹‹‹ýÎ59 %½ ‚”. :>�þè]µ¤?÷TãÌxL€çsÔ˜žM›PÏXšÁ„—+q!^#§ÃaâèÑ|S«ã.�„™ãµ•«Q®%(Îsnå¶©lõ]”N-{~ýÎwÙ8ƒ™ž0B“b…qÄñ–X9vñ)l}¬Å¼�b‘Id=!û…t,W¢7Åæÿ9±¸õñ­Ûÿâ® Rñˆçƒfƒ©ÄÀoé<ïËÓ—·§¾UÚe±”׫üpõ0Úé[(wÉÎ"…ýÎu¹8ƒ–Þ„2h–¢"hrðÈ)=|éP›Û"ýr:Iò"q�ö°Ì˜è¹¨š¯à޾Rß"à€"«•uÞ½‰ þ¹Ú‡¿š.øAsñ©Ïˆnµïn7…£'òèeŽ~ ýÎu¹ƒÞ0B Í c@2 °8èä>h»ï_6ƒzyu—YÆü|$Ô•»¹Žëö¬ÊÀÅ…÷ñSìÙ n'E²0!¸¶²ö>~v3üayè™zŸ›9óMÔk ¦1×5„éW7ñ#ÞežÈiýÎwÙ8ƒ‘ž1h–bÞFh‚¦zmœòp4<¯å²é*é´ ´ÚäœÉ"N¨„ªñ|oâSðjl’ÌôøœxŽMqIß–Š'S´Î—WøKw®²:&U0TÌn;�‘bbž ÆPÈeýί² 8P‹<Üà0P8�Ó¹­j xz}]�Übeetbox-beets-00724b7/test/rsrc/abbey-different.jpg0000664000175000017500000011011315253035401021530 0ustar pieterpieterÿØÿàJFIFHHÿÛC  !"$"$ÿÛCÿÂ\\"ÿÄ ÿÚëœ6 D0tz‡�š1—EvZ­ªN´Žä§ho\f`fC`”p¦(ä“7w[®ÄàyuwÔù{Ñòn´á;æƒé{«3s00DpJQ.fs¹dPw�%Éò(u�“3¤ŽÙp[áÌÌÌ0æ1ÄÈb¦¡ÀÜÚï@§0‘@2X¸ -qeý "&Ì/Ö…rãQ‚wÛŠfŠ¢’ØfÅW<4b¥§Ý¢"a)x°¸)“{Yå©7U,À*Ä* ékŠ-ÓEí>é0aÌRð%`mÙ%eJ-‚ªRaLb4Õó´,æÍî“WÀ/չлx›]úl9–ÂQ¼ÀLE1À�iªJÜÆb¢6ßs¸‚| WaÔ|ݱ9vòAщã8þÄÌ«ÝûžÈ;¨Âö÷q °�8®+�Û%•ÖÅ»2’ÏX…}OCv/·1ç ÁR]Θö¿sâàJ¼Øëˆ¾È®Wë™À4†ó,Mx 9š¸A[Â"a0€ªðD»mvç ¯ÄÑcÏt{G$~®©†9Øê°îíNä0¨‰ð%b‘³öÍ«=¿JÜ¢SUÇPr;Ý6×±neHPp­µÜÇÅ0q??ëÛ‰Lr<.â}Ô24”BÇl;1™ëóq@qmwI„ØO?«&s¤²û»s£6É™—ËRk5«ÞL›Ú}: WRùù]Ìí«}@WÚv¯$ÏØm¶ð­îâ 2-úÍvÀõq ]Õû× TÀ_?«›ƒwml¨«Cš#Ûâ÷w-­Ãa½pβ[TÐtí¢.]]º`Å„¥àÙÛùú/Qò½¶y·o]Í}³­‹>– «§Í˸Ëk§· PJ^®I˜ç½ìÊ/˜ÒdmƒŠñ+$#ºÕ§Ó£k¹c4áÞšÉëC”—€+Å1YGY\tŸ,°Þ#°“¸—XOÚm5È;KŽÔÚI,1ØÅ/Ö»4Ÿ›©î¿ +¼øÓ—:ˆ²Ž6ÒÅß)"�ÀXÒE-k˜Ø* È0b¶L{ªSSqIT]â0bÉ·íué.–Hãa°w€Ú¢ËÛÝ8|LPãhc�jtõ¤¤1e6•U®%ȵ�mWYW޶�ëN–n¼aÕFÃ( ^-¯ÛãžÄ‹Àú‚\gZÈ®úPÌÙÍú¸»­‚uý•'Ø9ŸÞ"&P@¼aX-Õ·ˆ'9ö¿ž�v™74gëkV)'á6;~§œjµüšÍ^�œ–¸‘_£‚ €q7¯,±W�"‘Q×sÓÁ<ûk¶FèŸjkŠ·g-ïZî4Ë—ô’¾½º ‘æÙÇ 6�ðrÝ¡o·t—²ys>ë^U‡Ô÷UiÐ�W¥ö\ÄÙNèµQ׿㙨yŒ’çy–u ‘¸8ó1¶’Oïû›ONseùÌYÝÖ w¨`››‡{Ь0AÌnTižNQ7}krfŠ«y·(ôÇOC”¹Ô·Ga‰ÄŽ«ˆáØ/:Âë0 [�Œ¦m½ fq­&`S½ç˜ãšFâìSÌ8:þ>§ “w«Ò”Ç%†ôKa�•o”ÉÏ»Øá�¸Ðýˆ`1‡J8ói˜®×€÷Êáp‘¼ ù‚ßW» áp9œ�ë*o_Ú4ä?«ß½ÜF¥79ÇK$…ØÖo5O¤‘MÜ®ÎÀ`†dÚª¼ap{–;”á·}0B¸m§’7žYœîý³g3ë300HbáŠ!…ÁC030D¦ ÿÄÿÚÀò+be‰4�-•œ¼N±z)Íd,Ds GŠÚö›·'kК)¨¼¨­ÎׯÂ0Ý»3Fe³™1Ü©Œ$‹‚i»vp)Q×ÇtIL³[„]ÙÚ­KyN‹QÁ#Úè˜T#·GNcåKèŽãò¤L"·G^ä)Ad*¯t\MÛ³÷3•‘¥¤^î‹‚i»v~dEâE“#»—¡áuÝ™ ƒ.¬�d«®±t@bšUÞ,x“Б¤–U5ÙV·�Žâ5aXEd¸-“à`šeÝœqÆD{Ç(9âËÑTÑÐ4Ë­‘Î爯±ÃŠÛ¨•Ù†µ’�1§– @ê·çXn×ÕÇ»>%wᢕu�eÔøÕyF§WßßQeìvñh >~f]ücZnž¤x¨÷×ÝBK˜”)¡LK�Ù�,ºËD¦ˆ}7UT–ãÓs¥ÉˆÉkbÉW�‰�l”iN7#¹¡–£– šßÿÄÿÚíì£26dÔ;b¡pÛ@©ØjQÅBž5(_Ï‘Ø{*ýá„fÇ—�1Æþ—:¿~›p‡LóàÖb~p~쇅pvà–¯x`Œ”îUn5w?>ìzkޠ𦳛ô4æƒjz9 bºò¤¦¸jzBg‰VÏ+AÆJ©¯y‘âÝQôÌü¶ô¼äé=G�kíùÔÖBxtô9;#¦ys]ˆêä«óÙ$9w¡¤ÜÁ›¤NÜ—õ'ÏÇÓEj7%KÁz9kÑJùtz ¢W�©¡hœöKò¸ž¡Q.�Æ×YÑL5zjÒ\Ö/ÅÑ� ¥kÏדZ¼¡ƒºòˆmYŽ€£«�hvÛ�ºt ‘ŠœJlJ±Ç”ƒ¶t T9ÛÿÄF !1AQ "0aq�24R±#35BS‚‘’¡$@rÁCTbÑðDPsñ¢²áÿÚ?í$–(þ’F²üÊôªoó~¤éàm±LÁqqÖRIHö³Ä§Ï @.•€;1s½zM7ùˆ¿V£SN xÁêQËŸG#_àW¤Ó˜‹õ(åŠO£‘�·"¤šÍŸ+{Ê’HãÎGµž%zU7ùˆ¿XFxCŒÑØî8·ê5àØÏ#ýI“BófJÇç'Ï…ÓF"äÒ.Ò?ÌÔÒÅPA’ùr+F@ʉ\Ù/`ÛäV˜hŽX˜ÝÍŽÁWÖ–´vv<Ö‘öz?ü_ì¢X>N‘·pϲÔíŸÊíct�Æî«V‰Ât� ìÆvaÞ{”XvïÇ ¦ä Ñ{>¾ gC»y9©qUKS8ÜÑ/ý*fG[C’ýL²Tð1úAÐàËKÆØb§�—°Å¿ÉGômðRaôùqÆdÝÕhÝ‘‘û:gÂì;É%š|m©§.¿Ú½¿"´FÇ`á Ÿ¿0îÍhºY ™Î� m½iJY§�®� €ÞkJÁ-C#±æ«(ç’vµ£©f­¥ýáÿÇQ¥­e\“BÑ›�³T´•™é5_⣥®†W> =á¤LR¶K[fîTú,^r滓l´\ï{dhÀxߊ¦¦™šIÓ9½B]�Ö–§–}–É·µïŸ‚Œi@æÜõoŸ«¹:šµ•�š�w…L+œç6¨üÙm²²lZF q¶ÒµÜIÿu£)]LÇc=g#Y¤&†¥ñ5±Ù¼üʳû‘þE|«?¹äWʳû‘~ëåYýÈ¿uò¬þä_ºùVr/Ý|«7¹î¾UŸîãý×ʳû‘þèiIýÈÿtÍ#3Üdy”*s³VÝ܂ۻ�[wr nîAmÝÈ-»¹·w ¶îäÝ܂ۻ�[wr nîAmÝÈ-»¹·wºÝÜ‚ô‡{¡—·pnÊ2Z匂ùNOºjùVO¹gæ¾V“î™ùª= ùª‰ 7ìt§Öù|® ª²¶þˆæ®A4†ÿ,©Üâ,c#¿‡òU€ì�Ÿ„qËz»�Êþ:ôYþ>??‡c¥}¾_/€è«$5a<“ZC»Ô¡’äðN•̵ÃM÷f†ïä$`ظ«f04ƒ}ê뫇v|õpZ.Þ�ŸÃ±Ò¿XKåð ÒPÿÔz£Å1·f<[·«‹kªaõËœ8LKåêõ@îßÛ›,l÷Çæ§u¤“¼œOmYÙ E{s<þŽ•úÂ_/€èÙuw‹®sX�¬£•Í�Ìëdƒ½âSñ棟fÒ[šeMîz¹oÌMŒv·‚„:ÁϾ.]›±:ay\ª–�„�x¯mØ”Ù3$ß{€X®ìNC7[}Ñ+ËV‰öæyü;+õ„¾_ÐîXr<D;’·o[÷+¸îM'r³œ-ƒTÐúÍsúÃ�MÄ4\îL—˜n‹Àaw$ÉâmÁmAqîNn:æµ÷#‘ʱ¡Ž{Cp…xÆm»ëœÑÉ9FÜN²—3~·žzôW¶³ÏáØé_¬%òø a· ‰ßp±•´¹�ˆ´û¤+ß%�¬©ª-a–-X)Ý%öFç­ä¢Š#sñ5¡»·t§”µÎß»/*.,ìüV+n)ó».j°¦LøãsD¥�mÁ6WºLEî¿;§»]�ÔǪ¯rŽôÌ;Ýù)ˆëÑ>ÜÏ?‡c¥~°—Ëà: Ãö‘ߪæÖBKpuIä€È‹¦ïmÆåM`5Âý×áÒ*i[Ô’—<;ˆÔuouÑLpk®E÷«õV#eÅ:#ÛYà{+õ„¾_ÅÍ :þHoVTÕm°ŒGŸw“ΗrUîcÛµo�è û��®ù«‹nÖ5hŸog�ìt¯Öù|:l6]Rm{#{jh¿qïTLt_à¾ç‰²òèÈæ°]Ù?Ò¼3q;µ�e˜Õ¢}½¾±Ò¿XKåðÕçÓ½X¡û(v®³Cœæî¶%NÌ,õsè8Ûz­Æ!.g ã˜X[|Èݹ ·+ê=ˆZ#Û›à{)õ„¾#áÓâ¿ÉCQlŸˆÇ+�ÉDìmÜ+#­íik·*Ý â�[+ÝMP–Å€ó åÉJÜ29º¬¯Ùèno�ìt§·Ëâ>1®æÈ*cf=˜xZù¦ …µºV4ظ%cCœžYõ4¦Gâw+#ªsóηm¡ý¹¾±ÒŸXKâ>€#¼£’îø”ÛqTŒap’ºÇ{ ±\5U<Ç œjIóˆœG½xÜ-æÙ#–KÇršåæã;£Úèno�ìt§·Ëãýºa[-QYä�®©&`°™··ªyj+IN/²üò^(­û£ÞZ¤?8îwYYní4?¶�é=Ž“öù|·an¦ ue©¹-!s ÙN­vÔØ ÏZëx;ʲ}¹ý‘«yDõlIß�èÛ±ÐÞÚ?¤ö:OÛåñþÝw¦ÑüÎÐ’xVÎɹƒ\íÖÔ7¬. ÅÂöPºHØpß¿%Ïš �íß¹4zÞ6û¬›qò/,q‹Yœ“�Äü ‰n� ¢…ÁÉ8’nwô´7µþØé?o—Çût©ë$‰˜3pñR¼>BàÌà#À8\Ð|”‘68#wfdÍþJF_ ˆ!¸zª‘`ÀßÅ6hñ±Å�sNnÌ*‰i_€€z©£k²alÁ·çu,„œ"âÜÖ <‘êðNÅ}üÁuÁÏ�ó(ãϪ;Ô�-vd¤e‰¶á¨ZC°¢ïE¼PÍéí±²"Ý í¿„ö:OÛåñþÚ¸ ¶2[Ô+fáöJÃÌ£ny)ð¾C3ÿÒ¤¦{ª×3"¶$†ÄÇî·_k2Þa8Ü&ßp[²9·‘PÈö_ggŽNÞ�9ØæHw+) ;=¡�înâÚÁ Yç¶6_[÷;*"}¿0œMÓœNó¨e¹_­tƇÆKJâ8"ïäù¹sÞ9)sv¸›‰ö½�¤Ë×>ÅᤜÆVZ øOc¤ý¾_í¬<ÃÕnþ)µrqk ¢ž ž#{\×Éi6¼[ ¶{²æ­’k­Äy¦T•ã?²tò„àÓÜ…mw�X‰õ€¹šž[€fƒ‘cd¹×ñN‘ìh²,¸¨ÍSOR'矨«¤x�­Ïí¸/G-AˆlK0ç{ÞêùÝ8ÝzSloʹͬ6Ñ¿4Áóƒ=èâ¶Rø-¡ÆÇÝÖµ÷-ÓéL…ÁìtŸ·ËãýµC pÇÁ2&;7 é´1â/$täÏ|Ú ¹*Š­¤{ Ë\ßQšHM5ŒsWA:�Û&9±’ì7}Ðv{¬˜äïœf�;‡ÚjvÛŒ¼áà. ¥Ú’üŠ"JyKd`üAmáu�Ùo�XG4z1Ä1ÍF3ÜæÝUÄ#™Á¹·† O5|îsZ*g¾« ݇—c¤½¾_íª . ÖLל;=ÜÁTÎ{)Æ2oÆèÕb›`X=^²תp‡ìg½7D�µ5ü•Dn‰æ7udÜUµ7(ÌÒ�Ga69¹Äî ØÎ ~6ðv ä°Ý1í§–îÏ+�Þœ÷=øÜ븡„‹¹£Ä##HÆîHFâlº0Éî;òE¥y&»$󈎆†ößÂ{%íÒøÿm@Ž-M-õ�^”ëzâþ Òæ¾reà´8.’I�¿çí«L´cüº#T²9‘ìÚï_ÖV;fœâçPÞ©Îõ†ç6w5r>�~&ÿ²¾Wµ’Ü‘‡Öh¿4æÆãën·rÜœ1"ÓËV†ößÂ{%íÒøôBÑ­�–ã½ ù-1ê0÷ôB&À”ãs}CÕÞëê¦õÏ‚‹,q2í<Âq?â³ñ5lÛvXŽaÀmî·4"Tq—Ü bÿt§Fqf,{ÖŠŒ¶®ÿé=Ž’öé|zîMÃÅ«D8lÝnœCsZS:F›[¯Ñ OW_�%¬SJ¿+ Jºt"ø˜Lg˜U.— 4PYX[Íq •å¥ÖB`}`°ÆíÀy*f»-ÝŽ�ŒšÙOzÂV ·¬VïAh¦�‘p¶g5³ÝÙªÖm)+ŽˆNõ¶°j“wB?Y±k9 ñÍbiûJªî!�VC×QXq êêŠG:L'—c\ŠŠßªúé"ØÂÇŠ7à«æÁL휭ÇÜzOú=p�ãU¯½9¢Ú„_1´Ï-ê?[UÇ%Õ䙇�üµôÒÐá¸êÁÖ.)ñbÿÃÁi:Y0íqc å¹SÊè$ÄÐ Ô’:GcvdêÑUs¶Ì[.îȪ™Û XÏ�æ¤{žò÷›“Ф‹k3cüÐä:/8Þ\wœõæ¨}®/êèÔF%…Ñž!gYÃ1ÐÑ?ôîü=%E‡çboSˆå¯Cû_á=‰Opcq8Ù¡UNéåÄwp‘èh˜°Äd?oáÑ«~ΖGwjòEw(N˜O–—Œ²§ŽƒIáPÔzD7ûcÖèéM‰Ú3èÏí«Cûgá=�¤ªv¯Ù³ÔoïÑ‚3,­Œq(Ña¸ttíLÍÚ³^z¸(�âiì/‰Gž°BãQ¾¹c‘c°nƒOÏþbª�ÞCÌûðÞ|c÷øßÔçSüïê•ýBüüÞsäÿPOçýE?¯úšre¶xF…ª¨z¼ ÅsïSîPèJtûTû Öñåg´"e`«¸fÜÕÖÙ¥}ü±ÿ±Ÿé%Ÿ—Âý)³Ì¼Š††ÞåBôj÷4ï‡GO- àŒÝßÑ—‡öoë+óBTþOçNc?³û+­ØÁ´UÊÂŒAf²ÖeÒV½£?¯ãÉסO,Ƹ©–)Ù‚ÃV7�µÞVÓz��,Ï⦠>÷ÒdTG‡iP;ÊÒTâ:3™Sû?³1Ú¦Þ‘YÇy† È‹òšAß_¹´Óý¾ƒ=ǃ3[3,Ò^2Vœ±QkGäAuó{JXnSíX„�koÏXÔ•¤âúm+5‰='öã¢mc6ËKòÕÕKœâ�Ÿ´¼TÙn<ãÝø^Àï=ç�zCžwíSZ¯ÌÏóqG{.ó.@dÆjYffžqêÅ®^’Œ‰­Jo産esÌ=ê.”µ»S˜�.ogM£åÕ5óŸÞ¦¤ª—¦þÂãÎ ßâ+Ý^RÆ‘MÙD ‰Ã¶JM—ô<àwžçª¬°á«ˆ[`ïY>Y”󆲎sÕ+»(kËRæAÏ  G¼»`°5‡~ðýJŸÈ‘Œs¤sÚ�TÞZ@¦û@ l¶öÞm•Y4"¶ÀbS9¡Â´½ø™ƒAÍF:1 µëR–ñk*ЛOoù>ƒ¼÷½VXæ!³.ZÚXžb¾oyK»UÂÚƒËHÐ+Æ[‡ñ…ëŸëßç C?Äg#¦Ë]Mf3ŠâyÄ}º0œÕš¹i—{±.2ñ.P_Þ%´Òë–_"µ:ë‚sÈo}剻¹‚QÕŽUVÐPÀö‚×!Ãw‰Ùl ØÚ¼º`…ËÇÐîú¢2â§tò›¹rÒpùË%ÙL¤&®Âñ‹í#Ë&—-†®GÎz³ïÓt1gŒs´ÏžKÚ^{ÎR¹f÷œErœ1 ùFôÁ˜½Vî»æ>5½IJm–é9ŠOˆâCÝþÌMc’'S ƒôͰŽJí»>ý)×´®€°Ð¼B‹ªw?ì×?lÇ´1 °a’€ÖVè¾­­ˆâ¬ÚPË1†±OÓà<>çðø^�yoiÙÛMÆÐÈ.±ÜUÃ�1º«ô…Ñtj:uw—»-/ìù•˜Ï<(šŽ=b™=/¦ÝyBÍæõÿá÷?ƒ¥g„×¢râ:•,g—3(&�GÈ©½ubDí= Ã$«—¯î¬¢Ñ”- É5RÑ(Ý+¦ÐóJŽß °OœãÀx~S„zîfºÚñÖñ¯¤�]ŠCNQx¿ûƒ`4VgW0 ¼ 6àMÏ´¢7ÿ)�àò18peŸb¢5ÞhÚ=¡ñ\}ŒáÔ�V�’ñÐÁ¼q5lË%š<Ùÿ𰲏éÄ}eË‹jéJèE‘m µA¾ÑûËÓ#þEûKtêx6ð%nO‚ãèü'+–3Eäve�Žø&bÕÜ'Ì!A¯Ú¡ËZŽò� D.‚¯#È€Ž·v¡Z«Ñ¹I�å<ÒsONÞ-¼?ÇÑöoÃÇIž•›Ê0ó›¡Lby†|½¥ïx¬E¬ÀL«± ¸16ùä̃ÂàÄ–lK4E¿üœöïã;éÛ‡á cm1 jrJ®­œ*£E¿2Ôœ¬nõ!­ÃÈDkÍ£‰‰�楷*¶ÁÏê0›Ñ6š5ëU‰·„xðûWáálc¼W¸´±FiÚZ‹Ï–Šô6 ûÊ�wZæ³Ø”óì%Uç1¯”Ð.›fõn!ÞñÄ4 ÏåØ ò¸ùmφŸS˜#±¨ˆÞÖ¾XMø}‹ðŒÛ¥bú À÷éŒBme©+äo(i¬{ËXþ£yÍ’Ño>�Õ«+Š…¿²T&iÚõ¾jdKæªæ¹ œ¦±Všy&™|1÷�yü �,“M¿‘ EÐf¿K—–°ˆt]Ô|ðÓRrÎ]—)­% ðûáÔ ¶pß2:ï³4¾!\â4àó‹LÆ�ÙxÙ½ñuë,~0û°t43�‡Sžq¬b5ˆ6`.C¹‡´ÀX8ñMí§i¡ c`Ú¢Ú³Qîg1n\׿!*ËvË×¢U¤coôŒŠ9@…ä|K!WRÑ�Hâ&:Ý zPÆ72èË Þb³ü¼^AóðûáÓh8a­þ ½Ø³L‰ÖS ¶ˆ¿ø–2sq‘ì&”\n7y@ˆoyR è)”çh—åÿeN�=—„r"�Vã¼={qå0ǦÁú+ÊaÒ¦¡K"/¿5‘´qP¡7Û«,Êx:FÃA‚UZ«°;šoÚ*d…:¨#ÿf’Õà|>Åøt<°]9�žYJž`õ;�yæQjKÎ…Îäõ‹bþÓ˜G�+ÌÓ ¼öiÏæX ˆo+€™–ïDLf”u³,ãrOáÏäC�ïOã¡aé]²�àuýDK.],lõ�¾S½Âäªú/kü:dÙwF” ²º¬ÎÁvÜq÷åw€öÌù ¬àýà�™Ï 9öð@ü/åRÅ b®]1çfÈ�ˆÂÚ½›¶ûEÍV ¥ÈãÔž¨#$Ù[Êy •¯ÜÁ5MÁjˆÖÆX̰kŒ÷‰×Oå§Ñö¿Ã¦È|±.!W'G؃kí¡En~`Ó1-FݱýaåRâõÛ ú[~ý%£diëP©Òo…38tˆ·ð>fv�=c:<ÜÚ…»3… „ɾâÜšuVsØ ¯jþÐ;«Ë¦ŸËO£í߃Â#ny>kc³ºÒÒo£} ¯§ˆïU¾šXf‘lukiäa^I>6 ÉÆ�OÔ™ƒ”éé´a†Œâ «Â¸¹˜k} §-eìLb4`,j}¡à|Çø%:JžP\˜t,òø»AÝÇ]FƒÑ—Œ1ã¡ÄsUêiÓ$»â4 ñÔ3çH.¬E�õŒC¶®{ä5à'.ã �‹¬írU{’•³¼k9M>ŽÕ?ÍUæîdË�9†Š»MZ¬#©ÀòøÇTÚìš ÌÅêJNEã®°ÓM?YSr7íèä�y¤¦mŽ™Ì6KÛ1eß.a`Ì®�ì_Q豑¦][-çôpÿ—i[¯Ö7¦½X†\fö—óz¼Ó‰�ƒ¨G^„ÒÖò뛓3hˆe-ši,E¶A1W³Ð²r‡Ò 2|êQ¹^©fD|Pü¨ì°²»‰ƒmÊk tdÖy�§àÏû©5û7ëÂø6þlv&a€›š÷—ÚzâUÝÛçi^V›ÝK–Ö�sYb‡ÏN¸šôÕŠ0²X¨”*¨C�j{2ºfæ$¤a._@t›�4M¡ûÂG…´˜¦»%…«�ÓAºÊòú"dáØ�ÀèRS˜7š?Ôð‰ýJð~.‚rMË"R8̹›LßXŽÒúŸtïPÑ<º©L8~%ãˆ4¨,òJ JŒyÅLÌ›>ó™¾jAƒU€Ýœ–.Ößõ3Þ ^óPû«5@Wv~ºzèÁxzòÚ]ü£çÚg¿J‚´5ˆÒ¬4q �¥à"urOÒF2&æ­µGhŠÓÜ3†ë¿¼X 5ÿi^ø3¶DUò¦‚aÚjt#ÊØö•è^¿Ä£On#z¼¼øƒ»lÿ_Gáv!´º‚PµýÛ ;p 4Æ1ňÓx†n�^'xãÆïj„¡ƒ®p«£×A™,&ЄªIDp4¿oä9¸¶¨7 T°ž‡A2ÇX8‹[&*±î¢ý¼cF›è ²7˜: #gýôÖYŠ%;}>���ò0e˜Ú¥sôU´ò…±qĬjKWZ}ÿfÉBs×)çô³W¢Ì>àV¹Ž(ûŸ†f¯"KÚõ”ÎätvVeqQ´,;“¼ªÛpùûèàOa†ìQŠ­À÷ål½æ‹a%ù©Þk\²ê›tÑôMq-îÌÍ£f¢Ï{Æ\ʪT§¡¬²“€‡¼Ä�ó¯‚üJOŸ´MÆ´J9>\Lõ´µ¶:ŒÛ+è?÷f3Í7ï9»×ƒŸ(ÿyJZݳÛX‹‘r¬ñ Ï€ÏLÐn^Œ ì?ä…ÐyÞ%rœ†¤4–ÕXv™7]¯ZÚ3Boçýš~ŽøŽÃÛ.‘Dj7Úk1Êh||Ò= m¦ùTíýš*u?Po¼Ì±”ð”Ìì>3.xÛ·\ÐA°±èá�Z‘óQØTiÑ�FÖRÀ�Ó•–×WwfÐúı6WNDÔP–^c<ç9]¡@6ãÁqíÖª�æO9Kb,T7øx¼�£³§¯”#.¿Éá²öÏñí§Æòú:�bÝQXëÇÂLmÑäþÌÛÇK„¸öaæâoXï8÷MEkØ�yŒëâïœõ5ýuÚdL‰³]hüøÊK†w�.Ÿ ÊAî™c6Û¹›9œÄÌ7ÌÀF³Á �Oï\Çü�„ª ø�£È-ޏÅgÙ[ ý¼57 ÷í=•é-ÈÀØYàX@R1{x|¯/¢�@G™þf‰Ÿâçø™þf^Ÿ¥‰â¨Ài’§ù™n¿g?ÇÏðóü„€èô¸ä§O[l—ùø@ÀÐ1áBFÔ3¹$!ú�ÂgÙÿ#Óf«ˆ Ò¶+Î5„viZøï8îO»*—e³z¼?½AŠœÁ)Ôj«þ2Ôcôf»qAŸ¨“ 4$š>Wö˜GòjK½ÃÓ.‡ÏÔ Ú ¿÷ÚÕç„î=¡[2«*´ýÆn‚ÖfÞèêZ|í,$0 wevŒ¸f*¶+«Î"�Z—M|®‡Ç´ZÕ±öA+ &îRS²þm÷›DÚ䈶Ôüï̱–¢m(ö©·×¨í¿à•pö{–qS�Á05pÞ¬ä9q[²Á …b›¿Zƒ¹2Æq¡¹1ï G| æVÔ¸ªR»ê¬çâå1µ {×¼©3¨ç0¿q¼`üF¯Æ„µð•¯W%5 †Š7‡¿ÇnÛ‰À(@ 4{BüÔ1n$×NîY¸‡„Ja¼#À*Xí’*o,>±Ò6…€²ñ–›²µzi÷„r^ÁH/~e„Áš;>¯‰ÄÛÿÿ“ÿÄ'!1AQa�q‘Ñ¡±Áðáñ ÿÚ?!ø…}¾„8�'Hñëôù�Ñ$ÅÒæßçóghô3“¼jóHŠö¹AD$êu Ä• >xþã`éÊ�‰rÃy9ËWZŠÒGÞ1‘̺ÔÀ ­{©u†+›¡•è\Óüa>úÅYy¦XNb-$ý ‰{—3èˆëC¬�ãlõ 4�8DÜöžÛ‡•�¿Ÿ0ýÃÌãÄ|ψoÄéô8�>�¿G÷ê8Š^ªÿ�;]P(M [Hˆr†º³Y1¼ÅsÒuendYÆãûŽÙö�ÜN˜ *Nð·7Ý” \s¹×ζy„»=�Ý¿¹@Ó°n�ଌ¾ü[EómyŠÿBI¦^&r‘�}Ö/êâ9er—5åˆ0œs"1X쟘ÔìÅ¿Ï$¤›ÑÅ4×ÙæçÌ!ÄãÄãÄtâ0Þ¹„øúüNž“âC‰Ó¦#Æ9œj>œÇÒ.y– yQâCT«»Ï¬¬ú‚W0\4k¾˜r'ó´yÞãÝ»s§´RÙ8™ÀñÞç[‰ÙYÚSŠöüFp âZp3°¿ÞÕ3—c×™±aN¹oûÚCÊÄç3�ó Á¨ó™×1ç3–~”²ã(NgX)†4'€Ô˜ pÇbr¹åtëߤ¦¶0–‘©hr]hæ«=yÍky‘-z77¾Ò”Ѫ´ ÀV�{R—]MÇ-ÍY¼béÄÐQ¼C“¼¶ êʵe¸="]¨ÔÛZ­K<"SF“˜Ÿt9Ãp®zÎ|ù•�:nŒàeöŒ%~äà•{‰mŽvT"ëÆnö?¿sžØÜ<ƒTb�eó>~œ}#Ìëu=ü´ ;9éö¦¥j»ç7®ž×é:cýዽÉ+eOiFŸŸg¼¹MÊÖ†Ÿ©€C\ŒîÅkÆ²Ê u¤z’µÂèŠå«Ï/ý?W´”ÑÖ³u÷•f©\á0s�Ê΄©Uቑ¦ŽcÈœG7fê—ªVúÂæ†—ÌLÓ Û�®w‘ŽÜܰ¨EÌ»ÖÏiE±äÑ׈Ä6e^1·QASªâlV ðç~‘P+£º›[Š»Ü-m�´o÷O˜q‰ñ)zŸ3ÚuÔô>¹6F¡c��“=—ú=æ¨}ŸÄÍ:teíQ2+Ñâ&áϤ§®†¨|»wßóˆ1m ²qF]Œ_IÙÃ#?ß~ ^¨Åp©ä Þ‡‚Ù�$(ìxƒIÌ5­ë1ÖDØäj` ^  ¼æ`1Ñ«ûÂg9G:ñ•íBמ—è®}Zœ®-eÍGo¼ÝXŠru‰A!ÜÎ�ûÃ6TŠ)“ƒˆoEoÌØë¤Úûî#·Ñ iÖñzÖ&ØÄÿ©ßñÜ'ÇÑ-ÕÇ÷=£ÏÔIÄ¿V]U¡VuÐÙ‘,ÜÀÐu­ø†à¹/K›-¤ËÖ¿1³kÊ­«>h·Ò}§Þ:ôç«Æ czQ@¦šcÖˆ.t•StkƒŒúFO°fV?ú‚U™Kàôéâi�3èŠhßtM×IËQ–�NÏ¡LÅìÙ­>sÚØaT§d%’öÜ{Úó¥ñuÅüõÚšD7h×Ù¦³0ÒámqFרˆŒäŠÉÖav)ß�¼¨VwVBE¦Õƒ©6ðuׂâ*lV•FuQ¡«LÌNU™þèNž“ÄLÏ™í¹í9kø˜¶<òñ:0”„°pǼ(¦õë�oqŸ t¹ykõbIóOZé »`ÝšâºÇèÔÏN+Ž�˜06ç `èú�B«‹r×Yw«Ö¥2âWÙ(æõUòÔp ´â~ÜŸíêÐ-Ty›ë;q`·ÖXä¼Ñ2岘fÀ%éyë„N6e‡·–¶à<Å$¶Þ¸ë\u—% )„Îò6Èò³ X±}n¡ò…Ö\ÀÕ Í›ˆª³o¦s†'Äå•:kpýϘó­ÿàÉ=&ˆ¸¦Ø,‹"ä�žm_¹Éßq«°’Å­×ÞQŒ%‡z31…-{6ù} Rr¨ˆRq38V„·'7ŒXêöÆØŠ}(VkuØ\²ö0Xz%/Dzñ8î ¼j#z§4¸eG‰ŽCé)¡ɇ´¦»DÃU�@/-gs ñÞ Ã1¶EéÂL²ËŽë�+·²ËCˆq©Ó$ë­ýTó8æ #3o]£2 pvÆ� +B�°óé3ŒŒ/�‹ù‰µg¥\V×®PX3L#X,2x|r¥þæY ÑOIE÷¨LÑM`/EåíÄÑMP®È¾.(§ù*8qéâ…�'!2rïû¤S¤%R8– ÂÄ#Ççé¥F€Fî/ÐgP&˜ŽÓN�cËbþl?S®8œùú:C‰Ò|ý]�‰hÐÞ:ÿqõ1.½å4´öŽó(à1�ÉÒ²šþ%Ø^?»ÆJT4³)Œ:bRÞ¼w·j¾ÖÍÊq2/F&lô¥¡(q+e”`’ª³Ñ–™è\bg{ó9¾‰’…Vžò•Ìêæ0§ÄÛôuôãÏÐï㤷7^'Uÿ|=8�gŽf“¤6N“æ(ŸT¸[¸]G÷ÃnõÄÏXY˜=ƒÅ¦µ/U�Åoˆ M¤MO;øŒ6 öñ—¼[˨󙽱6áë3„-&–¯wï)Š9`ç7€ßˆ¬É×Éëß¾æëIKŃûŠl8çÒ#uÙŸâ‰`Ì,�Ó�3™ûœKÅqô/�q~œØÁs»éÄ´Å k‹òÊ%­É}½C-mÅt^%’�Rþ‡ ê_ Ä í}›CИ]pá–Î%Ñm®³d×wc%˜0 ñ8&}àÙ¥pÃ=˜.·„l é–1¼Å]ÅMÔ[œNg_¡8–�ÑŽ¯¤ðîzÎ Â'Ióô§ævO£秈ÑÄl:3U_^ÓCÞ?Š0 {×Rc8O2Ú;*ʽõyɺ—Æø/?áø�©‚X)h¶Îd´hÖ5ûL›¢††{ü̽«ˆ>Ñ)¨¯‡W^ä7@)Rú#ÂêÌb#x%㢅ÌN7Îó˜vK›tg'¬é8N¾“âtô�>�\K9ø–\HÁ£e¯�V;+ž�4KWVæ4v ™¼Öó…ž zEBÂæŸ™m›²Ãštc�xµ0@V¯BUtô!É[èdÝD(©l.…ïn!²*ד§2òná•*ç;•66uME&‹æÚ· ц¢šj[yú@±Òã¡U/¶³‡­NŸGñ- -ñ™Í#&Jo–ÀÖz‘x!SÖp}=a¤M§óú“æO‰¿ˆó>'>>·r�WûqñÚÔµ«Î:ņ’°£°Âc­hƒ¦ÌBùñÚ1¥žGg´ÞJµÙpO'ø•0 âU®(×f·šêñ Ý!ͽ½*^k*6–6ðC.Û×kˆuTs¾±‰À:]4£©„“º]›²›6Ä áb]®#¯Ï0’‰y Òå�™»-ÝÞyôñ.'íú—Õd·Y'á•ç�#E¨:˜—¥Öf9KhñÇh’Õ(å´X4©ƒ3û1áu››©›ƒo*…ñø–ìü3ž7:OmM£ÏÑýNO¥Šú.q4¬»+-è˜ïòµ Æ»0÷Yу,ËB°9ã^Né†7€CXU÷”³1=eŒšó {ÙÄZ'Z¡á¦ñ� }RÃÓ£Þ=í£ö«›X߬ }«}7¥Mºñ˜WC#`4 i¸V£MN7ƒÁVN ²�]‡Ý-FÖâia{«_LV*±§Q�´ÑËùD›!'>>™ÏXÍt%³”ü?¹˜m} ƒ5]û#Î;ÆËP˶õ9³˜� Wpü0‹t’ÿI\+°³MóÄBL ö¨Q�݃¤}‘îëôP®²6÷Ó¤p¶ºŒÂ‘Ô�x2:ÙtzÖsšç¥Vº–Vï¨xÆ?ìA€n c ÍìùÜ¥§ÇpŽAëSP©N½¦cJæD8À­?{•R’ÄG_"€r•aÆ?p–ÂÝù>Û7)ï5Í"ËèJ‰íów©h ªÄå¬rÌz éBîá¿3¤ø›q>“âsâsõ1A`Ò-Ïññ¬@âõèËœ_ÑŽð¾„5‚Ñ£°8{ é¨'Æú¢#Ÿñ3¥ 晉W‡êY¨%ê¶Å·/»€ýt©~dÕl;8ÆÈµÐáÉ÷CƒUÈýÁö…¹§‰–«z©_A/�3´ÏÙïë*dea§5S™CM.Õ"ÅV^³0UUk´7æOˆÇ™ç‰ñ<ñô óyÙÚ ïé)ú’Þ=h�>°›´´!d°à_ÌÅ”²Ž¹ËØç‹!²{#îÄ„­ž Ô”ÆOˆUzúAwmž²‰MÜUÑÚkÁÎv`+Ûë Ú=ø¹l˜9€Ãž•Ì[§½ÇÌĸ«ÈLW»÷ψ¡‹ß„¯âòãî/Ò°ñ…Ÿ|=¥Ûõ‰~åÊ“$~ð²{DŸs\£ƒ]ÎŒRK»6¶ÆÈ~–ìÄUï˜V'Äw¸ó™ÌóÄó:h>æU§¨‡„iã’ÈùBÙÏ…i|Y‰bU(Î�/²âÞƒYíŠPv,Ac÷GÊvfÜ�vq+ÒS…Pà¸ú¿pëq¦I˜–vŽ:ûνÄA}V"Ý~ í’«Ì S˜ïOYMw Ø­Ûxñˆb*Ú§«¤T¡§îàÉŠZûMKfåp·Q–E]Zc�ûÛp‚âS¸Ç‡Z}P`ÌGÌë>'ÇÐRJ%o²ØJlÿh׉sr­ŸÝnrzÚþéLj¸"&}âÛkqVØJpYÞPm¥Eນ¦½*ì†S;?Ij”f�°ÿ°—Vµ £;Éqí¶íß©„ö…›Y½ÏÄ{¿¡òYò„fn§o¬ß;wB‹÷}ØM%),á —K|T¬œ[. ztã—ˆ6§1¨ý4gY×ÒsâyЬmråâ?„j9™H´{JýªòO¼C ßd &¸ qh3‰éN "æuíôy�¸j ŽØŽM#¹€ƒ&Í«ü¥-(éÑ…E½eqêÄÌÆ÷Ì5LBÖ8ï2 †;w‡@y(„Çøšgñ دHë®cÇ} ­J”JƒAÑçã D%b_X œ%Û�;¹KzÌuô̦±.„öZ«¿Ér€Y,nã�ÀìN6«‹ä}¦)GJcûQ�eSé¦nuhbHi¼GÚàA iKÿ õc9ý®^'˜kÌ!Չ߃âO}}ó‰Ö|GÓ‰Wˆ7^?hî½u ö‚cq4=%Û&ZB³C°>÷/=�ˆuužñq8@¾ øÀ³µr¯&#è—µEP>Š Áó\V+ÂD=à‹®{ÍÙv+\aáBþ¼CFkœå—JýK¾»& .I¾“6îA:%ß3 ¸‰|n(«ÁÞbÏk&d Ø{âY£¬ÌÏ¡{®?lÀ^‚+.‘Èk–çÔ6~e¨ìú8ñGŸ§ÄSâIÁÏ_3ã¤u‚cÀVØWI¿“»Û«˜Sî•U—¾0;Kèüô#¶*ÞÌ] £¿1ÉAóûUTÁÔöýˆ9\ØÛ™Á…E^Ê—o+t_2£=ÙhnºñÞ È+~�+!Zßâ¤zö‹]~ ˜ßIJ£Äl‘+ e¦�ã†/|׸Á¡Ö�¢ó#´2ÙµAêpôþE ÔÃÈÌË7X[mô`ì¬5Ü9�á&^$ëÕë·ã/㈇ý~ILjÂ<ý>'>%‚:ér 0nÁ«ñòçÒà¹ÌÑFå6˜7êÄÍS‘_—˜ zpÀ®²åäkÃÂc\6{�Þ¡Ê%.ÝîrÅ+OWÉ›5â �S3…¼Øu5�G©g^õ]|E s�'#Þn²æ¶ 4à³Ô¬zÇ£´ê—|=Mßó�—9Ôx~"¶š®ß¸–ÌxéÊÌ1ûüéà0ŽÎÑ3Ùy"žºX=Ú ~»=º}–;íÏÓÙ¬ôkZô„ãÇÐ�8ž'Ž>�¥…ºwïöæV±yÍÊE0,Ì­4ï¿°Êa2÷—Á]‡Ý†þ‰¥ƒÿ>ÓÔî]ñÌãòk±gä‡I™Aq¹W40ÃwІ ™ÞÃ{ª;Ô¾ » Œ¼uaWr§©©F-¬DÏJ\�¼ún ´…#-²ËV>Gç¼uœPEa»Ÿ¸4q÷ÃÑ”–LÅ?¥së³7çÕ›È>cTŽä…µu”5ûx>Ÿš�„yÄçÇתȕ /Ä^}£`)[ë(E”š¤ œØÂÐóTÏB7·s¬Õwt÷€_”M¶ašáË)\ª„tÁÞà'êxúsy�rÔSPì ó‚_ƒsŒ¯1 ļ5œBc‡'­÷™j1æÛP¼tóÓ]VŸ–æRD@Öùé,» Yi$î„°"‚¾¨÷Y|G™s°W™QKF“ÓUCÕ¬Î|Œ¨l÷_Ɇ o¨/ÇYû"„IO 2óùŽY>C&úðÅbn¦›6“ ×â.î«™€Ë½ß´øB†wÿ×Ë Ç‰ïôyúó§#3 «nWÞ`fek}¿ÈÞiSpÙUSA:ªe̸Ȍ{N½Û}!u/¼v5s‹e߯•4ìÈ÷0 1{÷ãæ>Ê9Í÷\¹yÏ9ûB}BËê¼~>�Ò£{àÊ1Б_«ÀzNm?P­ô©zܯnÏ^Nä-监,ck£šu¸øWÜ=D3/°»ÆÎ½? ~{›ýE—�éüT~30ÓÚÉù|Tá8ñN¿O}Oxi™Y„¹³¯/=?™zkü8›— ¾å¹DcÐÇ~tz°x˜ ×dhä-˜¨~â Å{û·(;é¬ßöæácXh€zÛÉýí0ÖØr¸=ÜyúWÔG)‚ùcjh®“gÒ€ëÒ5ÁŒîªºïò§žßùÔÉöê?‡¦«ã‹ÜØÎÏý âq¾>¯3ŸãéÕ,bV¶;´Þ!p‡•þ�/ùµØÑ5Ï·´(�è¶Ãó¼–Säûp¨87›˜¦˜‹«Þ³«Íç„gØî‘.Ì�Àÿ%Z¯IÃ�ãï2 ®Cû·yº0Ö^Ôô—Œ^£€7ŒÇÿ;±zËÌüËmWŸ0߈Ž^Ë!¤cò0ÿg¡ß¹ÇÒåÂ`‘0Æ[/®S—àøéiViÁý_ÐãÄ`ÇŸ§Ä¸Ðpx¨•�ÕÝ�£þL»Þ…ž²ÎS�Ê£`¬|ËàÌiáÀPhS}.9ª÷Fþð£xÎ%1‘bö ù€!¾TᗡΞÒÅ'܃.Ù‡ó/ º×ã÷klî�üÑËçx?ÓØ‰–)í ±™¦ri7-eúÁÑöy6²°ç#‘ŒuJð�>•[—üSüš×þ�OˆóôëôøœÊ¥JAv@«óÒiþ_  Ïó‰€þ_-mþq'–AXÆ=hë�Ê:˜í¹Ž†çÌÞK§â¿WòøŠ­K»øfsýiÅü¾‘zµÇ÷ˆL«°èEiÏÞ'?1_æ[¾úÌ€µ„t�þ‹ñ Ù®&.Ïõˆÿø•Úb&ã t n2Ëq™oYo^&—X;ŒâQâ.–Ÿ„óÄ'O¡Äé:CYFàÎa˜šÕ룑²Þ°¥Ë/eAÄmT1°äLñS•%û4;áIrØFê°çxúBqK/jQr^="u�S}°ý‰˜¦ð-=kÄ´¢ð óN ¢$’ù¢g­äfm Q³:y̼U"(�›ï˜šÿe¼ÝA=¢>vÃruvõ,9˜:­¶$i]c4:bÎ÷w•Ôè1ˆU 3üÂ)Y+†—7¯~ц£nÖ})� *–ž–ûw1ýîó>=+ó}¥ð�<À pº+»,W²—…ð6Š/8¶¦î¦`…/V½à‹xì=aO¿bíG8~Ó�Ÿ0ŸOñ¾!½Î™âCŒÃ‰Ó0YûËâpâÂã#ü\§·„~ç0}ªånD@ßcX»õÍq1DÑZëÁÆëÏA$èõÊYq§÷ö—s¶K•è]wFÆ\wyÃÐâX.–»Œ·ÞPs¯hê§=jRó÷6¸„´±['=)JêæÆŸLt‚ž�Àr³é^càƒD¯F–Üo¼à²?0oŽÍ}áœDó0SžxÕìV]]áþtl;·]§ Ê‹øÄo²~Øx _ƒ©…áí\Ç@I™_A;ãU� 2Å)�V6ù‡F01òMÝFÙf¾çíë8٨ϘxžÚ�?G˜~¥þ'0u)ÃÖ|ϘëÌùŸ3æsæ¸që:N’§3âqâs�ÇÐýÏŸ¡£ÒqâpúG÷>a:NŒÿÄ%!1AQaq�‘¡±ÁðñÑáÿÚ?ðkLhÀÓÇœ5€éל…Sÿ2x:|àØ�.ýd×Þ ÞpóÎ;¼ó†’”ŠÐ¡K☾›àT+ºvzɤodTH¬ÜÂV˜Q�—�)y0[}UÐvÎÕÆ%`ò!B"#ÞWç&ä»F^c�Â*�Hó‘ÚHQ ƒ|b6:”$;ãOŒfQˆÕ¢…»|áìÅ‹�1DeŽœ�J�4�Œi|(…1_€–PZ˜BñSÎ+“d»›£w1kpq@ÌzÙÀÖªWMyÞÛ¼‰Å‘ΤzÉ·OøÁ¾öœÐ=Œt¶ãV0 ÁöÈ�`ža)¬ÓŽ7Ÿ94k¼å£Ë¼„áçÎCHãaÓÎriç.«Ð1‹Cž¾3v�d\[HG!sÛð%.øg<¸ð4räÄUÇà4@Сs[ÏøÈui(ªÝñš‚ïHp‹m Aå6qCªoXæACg ±³ÆáT”l!à£8öc£wR¿a¤¾ÖP5à-Æ9ÒëxÉ¥^É /è³±5Óë�B_‡@Ð9~ù T\¤9˜ºšˆÌÚ„­ØEP9"L±­t± ØÔ^`’‘øfȉ˜xð¸ÀÃ6׋Æ@ë¼tí3ƒÙ߬駷8o¶=é4Êúpƒ°ºs‡:Lj×=œ\gX?í—òtâ}åÕ{tâ–þLTvæéÎ<ó„R2�ʳªwY64;ÄeÆ8éˆ7�þ$R<·Ö�]t»�k ½Ñ£žP0a:ÑF¾•”Æò\�ç"¬“`ŸŠÆ‡ª‚«Àë pfÏB*êŽñ\B: ��Lˆ”p,›H‹AꦢàŸü8‰0¢jk¼fôžDJÞž&åÍ«ž\$uN|7ÆñõŠìHVJŽJez ýê,HxÜÍÓT"B„u@…î²9Uà,¨Þ’½béå‚hœ±n~\}Ã.h:jåðü°ÕÀÛ߬8m›ÞÜ;ÅÐòpç™M¸[£r×fàq[`R 9MOœÐ§T5iË˯g*¤áÉ…h‡G#D§ ÍíÛ€´R»ÊðËE?*ý±J°Úu\<øaÉã;?Íõ¯•ü89BÔ„PVDƒZ„VdxAQ¦‰{t@óÖ,¼×wÐÿÇ €‰ �…àã®3PÅWþ0È ÁÃ>÷”Á«aæâë³S[â… ,Ÿ÷ªyñ‰SuoÆ÷…J<½ïãÒàE#Ÿœ®4kùÇIQÃ{ï¬F—G}½ßÛ9À'‘Ç:¹MpÑY®÷}b£ÏßÎóõó–6=ü}aá;ŠB»hÞ‰jõܬÝ`Zƒè„8\ B„9ac1·\/£ÁìÊAÓ�ÏÉ€¤ï†$jO·Æ'PÓ/(€ËÐþ©kËÏÎSzg¶M?|zƒ¬]x{À¾Qa€„D¢µ±Õîõóó—íëa6éɧò¾~>ò¡Üµ¶I»A[ƈܭ@IZ o&÷n p•p4à ºÃQŒâÔÓ¶cj¸ðÿßç!ïRN½ä@ÚOc×é‚I �NvÏïÖV,OVøg÷¬Uƒ%�Ÿ¦2"wçùþ—8Œx¿ãï-(®ý5Í5�<áL‡~9pwòCëÇxA"ßXHŽNž‹ñ¼d | ùùÜÉ Òüéý7ïÆ𜢜††o“'Ò`)Í.œI—4¨îùúúù©"ªE4‚TP y¸²ô±Tv?<xõ”3nÎF˜µ-�”¹ €V\qgÁã;ùiœ†Ž×(láw‹ÅøË¿b/¼báá÷…9ð©¡ Cã $ºï@ Û·þà�Ù«7š*O ÚŸä¹îkáßN/8 ƒÆŒmI±�äí‡Õœpôñð¨Xæ¶j+&ÕMÀ)œpS¯Ø¾JmÑHÐx-3MZ…ªpR[Þ´Ëd¥(E"µ&VjÌç½Þyßé?l¨¾„õøüyÁôÇÛ§ûï8Q‚‚íîQ¸×oí뽎®ñƒ­_ïÆP�±v³­¼ä-vS]uÁåÖNÑÙ¶ñ�—¬´Pi§z�ân–æ®ëCü»ý0åٸÓˆ®ðê~ð6Ó‡ m ¥ØšÄYzìá�˜˜ÁÀQ·X“�:øËo¯¼®ª"–ç €›(ß@½\R 5¡)¦Eú~ræž«4'kW�¼Bâ­6›œ]#w�ŽdÍDÝ áJɈ«º*6"#A¡È ±š¦¢&5;&Ç=Û¢´ºS¢”ÈÓqJR&� s{?~¹g†'W>¥ý\Te¤?·ó‚õ"ºï�Üu¿È†ÚþøÀA·ó�º�¯ß¾2#8'ÓxáVþíóƒK° >ãZD�)ÑíµD.½B�>åQƒ,AÀØÉÈ6Ø×u8Çrè"kÍÈCU)ˆÀT´„DI©¾°¤ÁýäQç¥.€æD$xBâå›41@Õ�ï�ìTå]î²¾ýåÁŠ…›öxùÓFyh»úÎe>xPå£OÂ÷å‹ìÙŸ¨ï"3Õ‘´6™çó�$*>ð›�¡‚›:ßž&X" ¶‚ˆÝ�é¼t’&€6î·½˜¬¡#M�°ýOy¯`2‡SÞ:Ï“Ðh¦†1�Lu�£È+*q @×&6äÊðì*SA–¬k¢œ¯ép0 ÈÙR2€E�3 XN…IФESÇþ÷ç ¦¡¬¼øÃ6D1=OÆ2¤�÷û¼ ðä|N¯¾rä÷þxñš¼$ä¥=è>ÞœWÙÔ|VîÜéË× »Ð«Iï„áu�n€�Bqá‹É«³˜KhÓM4˜PðÕƒ¢�¶SB.În©Û¦—h_—æû�¶�Æ�^IÞºtûɰÉÊ /lçAü‰ 4EBö]V¢“¢ìród(£Ð…‘RR¤šxÁåNÎð‹"„Ò¡Áš¿'.ÍvïRte…ù³¶�¦MºägÃÎmÀqA»Îxooœ;òkç�ºlÛãÒ”Ë;Jèa¾× 7&½;_ÙÇbq—¤Û!_?8íÔ„¦µ#^ëuÖƒ  Y¾!»¯&¼¡îXõS 'w'"Òƒ²O–æÞƒ÷&ÔËAµ~áGôaPiäu‚Zö!áî?ÇÆo¬ò¹C`�h‘"ýÜSGBÕAÂz ‘dj ?ô6%M”a"ï/ŸHÿ³*zÈpÏû¬.ÓÌ)� '“& ü\(x³hu…�` ¤D\¬S½¹c¡Ò5êZk�"…¾aÓxpé§Q®Ž-Ö¢H®õÏzñëC[TõÆëóûá%„{«ùÆt°Â´”Ó8ç4¢ä—žrk)|°ˆ¼w¬Ðùï-§£ñ‡2ÅM`mmûaËn¾<¥pÂ:;bõýë*hXþÙàœ=㺞¹ÀÐ¥ÞH[ Îf² ½üfìN){Ä­[^^òÁFe ÷øÍŒ©§‘äû5îÇynÂU¬ ýßcØ,{ýqM(^Mžs‚7u H×q×'Ô%æ%ä¬-G’ä#+ER¯†šÈqÖPØ¯Ì l§oìÆÂ‰›Õ×ß¼¯VÖ šD‡À•?& ÎØV×§@ëûÑf nØ{>ïéŠIÂ4@›úóïÑ߫ /Ç�ä+Òöîýýer® ¼Ÿ\áRêsù˼5á�·»ŒÕv®ºÖpoŒƒðæù<,—[·`îkÇ�&Rݾ2qÿxÛèwÎUÑåÞ;Ø5çéϧ>>{ÏÕg‘�câdŠ‚8À_Æ�5€ '{NÓÛF ]}k ï®á g�dã W8  Ò{ßx›ì–Î5HÞ͂Ң(”uo;¡N�8)-&[ai=Šˆ  µ}žŸÉ$”¾fŽ|þrs–éSCÊo¥‡"º¬b§ƒd Bëàa`ÀsðǼ2' QP\ÞçOƒ…ù£ªð");äðåe1G‚áÒAá<™d˜z�®pp¦˜ÌHêdÐJÿç󻉨CÕç­ãeÎcP ó€[JI|)Ï\âKÞ-—{ï£T“xJ+0Ijà ;ZÒ5ÈÒõß“œBܾþO÷œ)]yäÎEyc†¼áÇyWƒˆÞ|95³k‘ûÞ ”Qé2qFú1ïY¤Wë%‹÷É£Æç8VÜa@±D+`[¸‡‰¥xq€@pʘ«lê·I"[°]¢‚ÊÙ�º=oX4ÕTH`j¡d)ÖK¶µ�ï›ï ¤h6{ÂK�çM›)(r‘–�,°QçÓÖ�M°HiÝ ÓZÞj¨H+Àùþzrì(Û+¤’Nö{¿3ëÈ”¼!5´êb"[v—ãûãBFÔo°Ý?ç;À‚&T©³ñ—¢ØhÄTß®q5ÌÞ¯œ8q+ÖG?®&œœL.À4¿9µk¼©¡§²õügNÝ\8`s·œi±ã¬ÑvëÃ&Ü2ø/›ßYJÚyÿ·y°…{~1jÅ·ã[Ç|˜: ™¤ª¹q[k5ÇóÆ #ÐjŠôølN¡-�Í3ëØZOW7Œ1Ak’{ �-!cxN¹ý¯�ÄmÃ;U-šïinBÂ<�»ƒ¢iå§T¬ y¼†Ýßß ²œê‰8ѤÞ5¾K¿” µê>f 3KrÝöEÞ‚‰§kîqÞþÌ�€‰Æ øôÆuíà5¢ë–ÆÇ–X‚©87�‚Ñ-ÙŽ¡®@\xU8_>®W–I9ïE-ßÖTx2ɘ4‰×¬]•µÞuõœ72V'Žrÿ8õuúqþpy)±Ö ÑË|8rÖ/ñ‘Wé„»¿LRíøgtùë Uçeȉ³ë(h£ÐþìákÎY9Â)zAØÁ Ò Fí°*Å%K"¤^5–±gc±ÅBbP‚$#p¨Pr‘œ·“ vÁ‚�«Àyq¯e´U9+,¸y4„0ŽÀšƒÎ=!@’}KÒaI9¨�ã®n ýuàR»žLUAU/–þÞÌ“KT ±šò…çHÉ*C•¥ò¦î±ÍùÀÑ€8½›‚¦=bà„š×“x‚|?œ[5•ÓTÜÀ£C5€ÞœÎg¼QˆMšs˜ð Ľë¬o&Ôª¾Ö«‰vÌdú›À J8<œ|etzÃÉßõ×ó y0…TåÃIg,Øháœ9qãsL¡‚R=kYÏšÊQ®òH¯…Ûãëœauü0]«]ë ¡Ì0Âô£`pŠ@ÊÇüMíTl Й²q‹Bš·Q%~Dä�ƒÒá+8‹ð�¬øQïã“6=°� ZC—�”BÂÖ°ê<£NsY„à3a¥¹»Ü»úÚ¤I£}Á£B °”Ù° S“!'dîÀ¥²jU¸§VG(l Ì®ß!…¬áÅ]½¾Ó"8…OZ×;wöÑŽˆ˜­´ŠíZòúKò��ê릤J‡æ�ë‡-t‘ZîÅ4@ìÕŽ¹;ùÆK7�œ›¼€iÝ û�ZÞ�™âFÂ�ÎpÖ $RëTæúÃâÒ*oznG@)/Yo´O¶êƒÉณB»O¹�°UèÄża“ä0süëQÿ¬·IÆ*rã/…uãù~™½c×8h&j çÎ6I«ã‚âȼ¼¹¨„×Þ€†øß8‡�ZŠi‘r—_n�¤3KsË‘c 0IU³³,Æ¥ƒXœ �µÉUÓl÷¸‚K&hu�€C€’´k8î¾ö1CÊ^Ѻ]k¯¾êãm+®g¯êdcÙò'€Ò"ã:U~¡€;‡mU†!MdIÓ%‰ 'ЦÚ"¢ @PÞ0ŽÅE…r£l]*ØÐ}3#7_ ;Ö9 ÑZ OXÌæC¡ E�·Îm“à0ø(vt‹}3‰°B•É,Zw¥Ñó?œk¯4"jŽÐR/ÞÔ4 /¦�›Ã@‡ºëÓ¼)ô¦ŸÓÿ0½…kcªBúç|aÄ]–âm­‚‚CãtDÛ÷¤)Çz 4"-eé´`¹¢ sºÕ=ü˜OÂ?|6¬×xb@h‘ÝŽ±î¤ ¬ÜXèx*ªîàšÛE(¡b'Ò>óv1`pãBˆBÐÄ»ûmªÄXV�N5RÛ»f*Û‚ æ ÷N¾€2P霓SñÓPË TA¸ljÍP˜T±ÈYF­ô¦!Âà´ëžpi¼­#sñŠú;ĸÝZ˜kÉÎã}=etüxƒº{ÆÓŒÀŠ:]÷¬, M$gÛ¡òçz¯uÄ(ôÆó›fFçY"b>ëBL£j¨oIÆ�š†¢§júvº=¹u‹w7ûs�dOC8ùÊ*^A¾¬ãF¸ÇۙȖõçŒJtm§3_¯Y¦*m õ¬Àr§Ï}Þsa„Á¶…,9 ‹ß! »¥âT]~êîЯó Ž*Â{ZqçŒVn„½¯ó¸>øNb®\jcpŠÐóÒŽSF(D Jœ†,05^¹ {œ÷Æhêz†ÙȾߦQ°äN¿Ù㊅DÖýþÙ{Mb€à˜ Tüà4(WRN"Ç� :°XÈ!Õ ËÜX1ºÖ:T4A½/ÜqRÔÁ¯>ËÎîQ{"†ƒƒ86evNZ™»»ñf 7>q ü`–#\bzjb¢*õš£F<³í}&]Ñ6�Ax+·.Å·Ò Ú¤î�¿£„+H’NÖšÍÀŽÕ5åóýïÊðþ?÷(]µN¸Àûá ÿyý³‚ŠùöÎ<ä\�À4A Ö!­y¹M{#ûw÷�¤ÎgþzÍv]ð;Â%‘”åó†ùgÞJŽ‘ü¹ÚÈH¥CÿÁß5ãM¾ë2Õº¤}Âöìòo&«€Â.ê»tZö “Œuó+Ê3ÐáÂnb+Á©èc�Çs)Qôë¼^ÓÒ¢$"CXë@Mà„D¨ª…åV¹Ì#t-6XµÖ§xŒqg{Ûç®\1-ÝÈ©�§8L/{ÿÌQ�.pàvÎŽ j»O‚âzzÇh×Ý¡†W‰›Òž�³AÆûøÀ¢ÅŒ6w‚Œþ^0ú‡ñšH‚ƒŸ‘¦¿8åÌ9c�·¾ÇœmÅ­ÒubšøíòáÇr‰ZèŠíð¯<ãó¦µÌùÄÐG™ùç­á°(Rüy㯜JÕ(�÷ãôý1Ev]oüÖzJ›D×ãs�ôkœ �þzË4ÞNï DÕÕà•Щ½Ž—¢ÿgŒ7&H© FÁ|.� C­9;8GãŒM?|Iäˆ"¼úë{3lÈ«ù%%¼ÙrQ'C´±�G‹yÊ-ˆß‘ÄWõ»BAFðTÝO ?9ÆHÁbv)ÙÆ¦ã�ø¥J2ª Ñß3¨¶*8¶&Í-ÞŒtZ �‰×s¼åL…u­þ&*�@nš{;ÅYÃECL"a;R"¥½rþqH·+ŽûÊ.¼jàÚåC yH:Æ×_–phãÎ�^þÝ7çqÌ>Ü‚Ù%/êõÄ÷šˆÅõ5çó…µêµªo}ýbƒvÀWè8ñÇœSÃnQ‰Ô‰Êãšì@N…sí^^2c9H¤Uر¡ÌÒ‚×÷ïó—DòOØÈ*M|õ÷�í³®áùýî$#˲ì´œ5Œn'‡øùòˆÀëÆhv›ËZ�Uvˆéþ1Àa �Sö¿Û1ƒQ®f×ã�é€ "óÿ¸�œ‚¸Û¾+ÃŽ£�;!âÒ \pð˜èÂãÙ­{ž0Ø®ª‘ãUÖùþЛQQί8�FWÊõzÊ[¨£}|b°x.ß8H€^¼uùñ‰Aãl=þøó|+úu¼­H$îľ?³ãrËiï}+«ãÏŒ�(F„äoLïŒE­Ì1Øj–4»¯ –WZ©`UM/d6¥ëQEA/£ yWã ʶÄ'ê|{Æû%3iÙ}¥‡{çèÌ€¤zÀ6ùñœ ïÏ8…u¹ç;uùd^?,a—( ÔUÚXìº]^9}ýk�‹elž&î=ë,oˆëƒ…†›_/Î=ŠÓdXð!³Ì{«€5š;kUàê�×Yžt°ö夂1Ù‰-­;~~®$vM ÖÍïbŒu², ÚÑ/¿ŒN DÜ ’4×OCuEåkË/°Ê0s;È.=ö>½ã! IE'•6›\BZ¾nF¦Ôû˜ Â‡Ô||໪µ2;´Ë5ƒ¤lUö<ž’áLˆσh$m)´|Ìr†,—¤Õ¢â8Ó2T#júe�ˆ+Öê‘võ‡‡PRœ–ŒÛŠ£)‚5øÂ: DIXG‚^ÀâñÜ A)ÓãûÎ4x¸QYÊ u„ψ•ó‹5)(Q½@[pÒMN U\ Ý�Ýd�K ²îß?‰Ö ÷�´à%ÓÉÞ.oœ"qǽncÍ…öÉF¿,j…]¡ÖÃã�ŽrùŸyѵ€U�q6ø(ÍØÒ˜UtFiÇL¸6NrR�£E7Ó‡ñd1Êß-µ;œWg*A¢|3±gKߘ#;¸þWd-V˜2á¡PÔ ,ð}ë%�üñý˜¦Y%Ù}5„1ã†æòÑ€ˆ÷Œ$Ub¼N‚û¦ç~'1Fj Ê>Fbæ¥h)ºˆŠ‰IMÇÃPî.éæY§ˆ$@¯×\Þ}—BÆRà+ªÓgœ©VðÙ9Ç£tMüì™ku¦Yé`‹¡a$r°{6+b#ƨ�µZWÐyjp�0Sd+h»¸¾½cŽŸFt$PH]Ò(€d{ŪqC²:É@Uc'‰ƒÉÅóâ<šã+‰œQéµÐWÈe€€¢=9¨’Q ¤•wØ„` ÷�w¿lJºy7�¹ç*W#În¾F<ûbl¤Òs–šÿAØ V-€* ©— dÝý`Ò¤j �ß?÷Æâï›xÆÞŒŒ±^¾3”mÆËÐõ¹�Î+FŽ\+¦ÄN÷¬]ÀPìû–^Ö:œÀö >ãÆX©Aº’\ÖË·ã ·—ÈÖKÅ5¯¥ü™i¥IhÔÏ; ¢‡·±cA °l¥êf¸>.¢ëF׼渌±]ˆéM�?FÚ€pŒ‰¦’`½›KhÛê)÷“†ËÄ®ñNB„{¡¤ÙØÍ:t2v#±'&ðŽy;ð†´›Â5';Îqâ7æâxÒŽÂ�5äOn V¦('1£ÒfXJ+Â1~pm««Þ*sñúd²�jÃuŒK4HJo`Åvƒº]cñx}äkOe¹ðscÓÎ=0]àüap-5ÖËã Ì(FO! P:6¸€nÝ;®ëÏÏ®p‚ŠÞ‹ûäb.ˆ+§Á7„Ö€ƒrmÞ¯òUyK*š—õÈZ^‡SšüfÄ �Q‹¸o¬ÂeÓ`i 2l�µIqQÛU@‘a)Y°Ý4ûÉ5Ýë]â””Çè8rßXP¬z·@V+³o@>¯P Ëu¼ÝÈ‹»�®úÀîT°Uï\\Ýc†à*U/8 €Ž<ƒ§Ó”%»åÓ³…3DÙ� QÈ+Sn±¹¸4)jè¥�AiÝ]ã1@ØCÍb=“ ‹vOEH@ìv¼y0·ÀÒA¥@›��ârn˜�’MÃ2´@E’®H;PnM*‚^t,(QÖ‘ÍdKDà @®Ì\Ifˆ)�àûà5qÁ]¸_¡�6òùÃÙÃÞúdµÞp)ÖñÖviã:sÆ¡å^Ï¿y--‹ü[ˆWÛ[Ÿ�é†4v6%´^<’ª`! p ûÝ~5ŠÑ>—OƒÔý>æN½@8Y¯ž¿9È@ª (Ÿ=ý`´j…MSU®o sÆ#šwçÆnŠ©R?·�X„T$èWÖ¸ï×"µ ú)åÙðë¡]#f¼ž± sùÑ HÎ¯ï‹ œ¢‹ÍXô“·Žr�b$BË]µÓËï$}gðÆ:KÄÄ_áÅýë k® ]·.#ä€ï*Ö6GD£Å»þ4d TUþÿæ²mæ>@ÕOà Kx »ÆÒ&T‰÷�dìЭ† ó.ñ$H�ÀГÏ–LõeÚ5W1v\'+Œ‚r"a¾qœòz kXEãzWw†�(h/ƒP’Þp<ŸÏ#{èÎÛïÆj›¾?\‚lƒ©¢^I8ÿÌbR÷—鯎rÅß~r.Œ#UÅ)·¦Þ½P—ǃ‰_>ðÍ2k*ÚUg˜8*h-um‡/£W¨îtø›ú÷†åá§Høþï äzßÉrj%’Í{Çj‚Ç@;(g {˜Öæ¥ Ô×ëk¢mI¨YºF~ØJÃÅʶDB£ƒ]{ÿpD G¥915-œš Frßg¼Ò7Kùr™¨i‚”I=9*>zV.æ îó`Öûïˆ>°õÙŽ›>t8û €Þ°Ö´ø=ܰœÉK9e*� Ôä-à!ƒŠ£@C`ƒe9æ<ÍþRj¡T+ L[h!¶á•°ã)!4 PA¨`=b-]ù'y»RÇ{E”J†ãzÆî# ] �Xö\¦4²‘V’üw‘v[ÛAÛÁ*nW ^ è‘—lp½E´¤Œü IZ*ʂ̔½"ªs^­LȺ蜼áÉY\ôIIb–@—¿¿ÓÑÛ ¨'·Ú2°(Òźã…Tp©à2Æ©è4kÊ;êH¬¡9aFøë,zÂÙN¸æÄ%R½biðbiÆï*œ}0t÷q—†‹�¦·qÞ/Xé¡ËösÔ` k·ïœ A¨týóZÑ�#£üá̆�³€ÈÖBéÛ4q;þr'N@‡�À®¦ÇÃåÞ°iê˜Nvòwœ¹L¥yw�Á^q°½œ¯~0«»¦wø[„Ó}¸~× ÊÖ‡ŒòøÃª‡.0Z4±‘Ñ×ï‘x?ÿÄ7!1AQqa�±ð"23‘¡#4ÁÑá $BÿÚ?A¹CDÝUµ­ ´KÜâ#\•>íCÓ‘×¹7†0S$ïËcÞB±´mÎ,Dä‡ g´sq€?_²¥ÃÚú®a$4F±¿ÙR°¤ìaî ¶g%qlÚt™U†qOØ«ŽÊ4ñÉ9NÑç*ï‡6…,m$÷íë¯dvk8UÅF®z¯ô÷"rû¡Á®cOº"ç—ÝRá÷”é¹€wz§i|0¹¦|ù¦ð~&X¦Â3׿Å[�q;|XXÓ<Ïö‡â²Ics”þ›Šµ¤Sc[<ˆNàœP¹îÀßxAÏûLàœM´…#I¤ Ô�üU^ Äê¶I¼¦Dùª¼ŠÕaf‰ÖÏî¿ñN%?ú…[üzú�ÆÐ¾¾¹«*uZ}ðIýÓA£2…ä»ýp0{./hÛ˜¨a]ÜS©lü'cû¢‚ŽËO�΃É=íjShÅ Ò¥rÙª ϯáT¶§XI ¶þŘZ*t Ì*µIà»)?¶þµUi8ŒmÈ«zŒî»=4ê�sJÚž*�ñ^ÕÐ DŽsý&ºs)­Æêµ­:À�:úÙQ»‰u³²ŒÆò=VÔ¼‚N�ˈ[Ôm[ ôõÜ;Ûh!�’} ¯`⩲LtõõM­¨J.Fƒ+< Î|Qn ­»8VÖåć|*èÓÄœ“.ß9óõ껬>K2éL&s\!¸ißä?´$ y«†–¸¢ ‘ Ö¯²ª éØÝzvN{�#’¡ri89ºn®ª6¥£Ü9-“»!5îoÂHT1Õ™¨Dgºe�É1ˆÁƒ9ïý ¥»ÍaNI'œ�5VÓÙI'C¼¡Ãdœ.˜�Žú&ØÖ€ÿ1©�A6Òà¼3çs´gã9*T*Tó3$ˆÏmUzn¤ì$Éñhpê˜ËIÐNç»nôîU­Ä\7ç±�UK[†»y'–yÇ)ÕR£Z¡pmMï?©mXüÆq'N|¿¤ë�0÷FS¿Hëš«MÔŸ€”ð•²pXQä©Ô,q¾Š�ûÚ\`gבù&\–<¹€ êU[ÓU°öƒõîû—ãIʼn É}†[¦ßÔiÐmá/öUƒ@GÙ6õÁÀÀßžúî›V*†Œ¶Í!R \õÝ ÜJ«†`N|÷ñ„ë§:§´ çÏFâ¥înAúOò…ã��Ñ:o§-tÛœn¿P´Š€8s¼ˆä«=Õ�Ë Ð'/ÿÄ.!1A2Qð"q a‘¡�±ÁÑÿÚ?|й6ÓI%6™Ü։˦Žî‡]$9=+ÉÛi‘ÈÛ¢·\ï�ò¡äŠt,±hø$LꃿÜyðÞ丬R÷†¼ŸQ‡Ë‡D}F&îØ¸Œ)ݱq8S»>³¹#¶gv(Y ôE rDýLN�ÑZ É= ‘kZþ|ãóúäÈÆRua‹Œ~áêCÔ¨erDýLBLÑ!¿aÆÌ¸dÝ¢PqVþoÉ;Ïë•|þL|4òj¶'î'Le¯ú$““Ôó©�Ü�Å¿(“õ1n$–ãB½�R´K5-Q99;bÏè†'%gӫ܇›w±ÂcŠ�§²èÿÑéîºwfïRJÙ�I!ˆdIú˜‹´xÐRd]™£$õ+–u=v6ØE+ZMî7Gä‹û�÷Œž¦SBbØRR"½ÌÐòP£óø8hihkÁKROA»ceˆÇêCÓÖÅÉvM'°£óø1âs~ƉÜP¾è6ý×ý:–Õþœ^´2†#'­•É/aª[ %«$­‘�ïónOOÉ”øÿ£�ê7úqzÐù£'©òDðO¶5Ö’Bû™Ðèz!¦ÒdáÕ:F\RÄŸ’ÍŠUÉ# ûÐÅ¿$dõ3ØHsÉ(t·¡Š7~%�TÑœrNZ¥ãoÏãòg–�ª¥¯çö;˜\­èqyq¸ý­²MxKZŸI¿ެkS “2¸ †ž6œ†-ù"~¦)$cÇiF^ #Ób9%‰Ðò,�7¹<–¨Á…åM/jpnÑ“½­?«Ð‡ <ò¼pÓçùÞ®‰B•"R–—àÃÄäÂÛ‹2p²x¯]÷!Ĩª¯ì\N9AƪÿæŸ5c$MjÈJ¥ÕÉ 4ÛÓÿ„¸Œ�‚ŠùcÇÖúž‚‚HH†yaƒkC»Üm²ZÒ̹ûjâé˜_T©“Ã¹ÙÆôlŸ´Å›"ÇÚ½¹‹Ö‡ÍÝ�>æš¾ë4<1{¨ù)"y\¥£Æ"ÔGm£©Q%{ =GŽxÚêUzŠ^â“oBqY1I¿Ù|þ XžM"$ñèÑ žÍuäîY9T[1Ë·F}JØ¿bÒF>#ÊS�R­…Ê]~þ FGhyç‘%7u¢…%ärTp\KÂ¥ïßÇã÷Ô´cÇNÐÆù"NÙ®¦GöÒòf˪;½MíTAܨÈú§¨®x¶¡ÉJ$]–KFHLë’òcÊž�“åe-È®¦8;¦©/qcêZ‘ÃÒú쓳¬œnM¡AÁ;$ÒzÅÜt�~LM¹lž¯ÇÏaµzLD±´ÞšáÓ‡[z 5%Éó�·C} ÷Â�£Èö#j#�’Oíb,îIÁ+ÐcÔ„Üv%ÄNQè“Ðr’�Jzz�ПLmŽ]Nب‚´$4¨Ý"Ò±r‡·&ISСÒH{�oÑtÅ‘P§öØ¥gpî¯aä[ÐçW¡š³­$´Uì,‘jèsJ´:—±Ö½…OR¹PÖ… 6΄8Z§¨¡OFt{1ãGj6vÕU�:Sgin˜°¥äXéU’Ƥõ;^,ì­Ð¢’¢Š(ÿÙbeetbox-beets-00724b7/test/rsrc/archive.rar0000664000175000017500000000446515253035401020143 0ustar pieterpieterRar!Ï�s ùlt �*ð… ú¡x¥èXŒD3¤�full.mpcÀ•XÈ�<˜ûì�’(�&î»$³6Úê£ùBÕk ¹]ª]R—7h˂Ȓ´–ÏT®Ó6U×ásMÊâÉtªã7j7E ®Óuu`šãu Xà5øRFÛ„„„ùwØ3w7ƒéžôçyÎó�çyß<ïgó\÷Î|}ï<ç{æ~ýûžó“ßs'ðžÄÖˆ§¦ì¯ÜoǾYOà½!𿆉êôìn/ÀÐaˆ…�fC©/‹ÔÓ9¥¼},–˜£4KÔË]œÉóíA†C XñBöå0Ðw:·¤Uˆô‡«\C Õ #èÙ‰Ma>�€I¹{Aj¨.äÞ�3jœúìT}õ±Û¬�›AYXœµ®XUÒ{)·ö!ÁYn`».Ð/Ù§³C³¸£Wiqº'bŽêÆç•;×ÕåÈö}i5› o˶`ã:ªõŠLM×»^f%j=ŸÍEUÄx/ÙØÑê·Ü”w;ûÿIUÒ*G“ä¥GþÍõ~]éeŸÒŠ£áíî-»¢›»¹åãV™›ñ¨›ú©•ö1d¾)íIò^ÖpöEuú~û‰®êñ³ºÈÀ 2…ãÌŒŸô¹ }žðá Ö…S QŽíŸàîf'n\·ñhI›ïÆ2ë†i¨Úœj¥QF):#xôö ×äIí¿w×{ƒ¥Çîä ·¶3è+áÅî /0ƒ[ö–-»ÂˇDä!-ô!¢,ÇO"¦Ñ�»MžðøDÛjýó™îðжáI� âg¸<©wè2}Š™£ä�‹()0Ã;ùLJð×µqxDÏò›¬ TÕÑyq8�ßí‡]€èÝî’X;˳ÜûŽ»Üˆ‡dlóÕZIÖÄï2–ëŽüÎçbMÊÀ2Ü´`Ýx›£,÷´,µžŽ‰düÌÜ–ë×Y›ß,ç{qyÊì…é{^‡}þzŸ7‘8°6KL™zÏÁ©�ãWÚãΜ2ÁA&5EÄ3˜†¾7 €«jÀƒ°Nô‡pP7]Ã&TÞ&ìH£Ò¯?Pz^u’H�´&„L8'3þtq_~®^ðÐP"AD½´]~=ÿ’rèšä+ë÷sS¢* ÑLGŸ= óOsÌæ™ÁëàfŸqhgÞy¯ÈÕ¦âÖ3DÃ\<åXòâü½Y"±è¹¬õ¾.z­1˜îGÙ÷Ïqm‚kì#¹ß”2Ãα9�?º‚€dUwÇxq*E*Ó¦ØWAe‰éŒ}�D¡�áÈËëh[vAóïÅ6æó½ÿ# œ¸�6Â9§…4€ýQ0mÂÞ´/‹¦1}¡J5ÑG¹ûrkõ¢Èj¾8®%g úu–º~ß&FÕG7‚pá]6^ùëÄSúô O§Ò/è~‘ÍÍÙ6¤¡Â�ѽÂ:†ip@ $Ê@Âbrk¢ŸÕÁö¸ÚηçÆ×rûZ—Gùòþ+_¾7ç¯þ¤a…\, oÐf¦/ZrtæÐ4|Q‚ä™àéÙ $}ªa­O†û†Á…yTäí[J›8B}Å™¾L™JrñP <~TzƒûÚ¯Eî�b&¯´­a³D ˆË-R^؈yˆ|£zÚÁ[Š21臻X,jÓ÷&@xô80ï‚;Þˆíøøle%¿B”–�‘ö­ œì½§É­èk;öZÜ¿ªµ«>ã›»^Ù[’Ô?‡ÆsS:ù�L϶¼<\l@«¹B¸5Þ }žHŒppPR%ŸŒ3HiÓ6ô;7y$Û“S¡ŸÙºò›nÚ…ãA¥‚¢� jßuô‰‘;�B$^|BjdÈQ=Za¼èó‘Òs03ðùÄ¿õ¯s$<øv–¡õ ?šxŸ¦F’‘âi)©A¥ÿˆ´|õ ÓmÔÐÒÓ¾u5 ª!Ñ‚ºaóԛ⩿efE•Ž36ß¶Ôô�š /€”ï‚J›2ã Ãô•È�g?šœmº‡Ý£|VcÄþbi|æi)’ù^gü¸ ´¢§¦¨­-|ÊïÌßQÔ%|¼óÿ—¾‚¤ Ùã§cä¥$£cŽ¡Ë$dd£ãPÊ9c^Ü!ÒÉHiv2´?ùuˆn»Ó²’d¥c^5 ŽQ)+=*ëÆÉ!•yÇwC±“�:ãÿ† )?±Ž¡xÊä›Ì7(ÐdºÔ1±òOC“‘;*é¡ÿàÖ ·ð@Ä={@beetbox-beets-00724b7/test/rsrc/abbey-similar.jpg0000664000175000017500000024333715253035401021241 0ustar pieterpieterÿØÿàJFIFHHÿÛC    ÿÛC   ÿÂêô"ÿÄ ÿÚóÀÂÎq9j˜aOÈ‹)Ÿã‚b÷gk¶O©.4Ä�hK“HéÇ–.‹‹THÓp߉+àâÌHÁr8g‘Á<¸ ` Rùt3ŒŒ.)Þ_% Óú!vŸˆb,³à àEÅæ ÞpÈ&žñŒ³fø1âø}qNkIJå­1çc�äŒïíÒ›¸­˜°+$ÿ0÷¦ˆ‚©Jƒ„÷ƒ&¾ÁÙ©ŠZÙ5{Á.øµ=~Ž­çl‡ F#t• ×uÛ'¢¥”r&×UT|!§ïziªOᨎÏ�ÎÙ"ÿ¦§Òê\›¾è¾0©#ƒåzu™:mŽ «}ŠT /™ÄâHŠŸ[ªúpƒO$Âxøiæ©íyie·2ÍatH¢á§ëá]4µ•ÙÒùdV<Ö�#Ë«D¦M•ˈ·ösºbú|gÅF|%† pÜÅdÔ7Þ¡-ºÞÿ¥ 4GÂïÂUÂ)y>dß[%‘2?;w�#cœJ¤ú¯H2ÉÍ{Òà¥q£Dc"ßË}_çï!in[Ž—…ð‡ð8)|’& Aɾ U•!ŸG¯4΋Ñmëp‚»ò1üÑWG²œö]Oܪlz%Ú}¶2½/bSo/ kÊì|è»÷*p�È q…­[@æú]­~Û6sº”Æ–£‰AÞšVYÉR(r#’ @uÅÖœ™&|ŽZðÅpÂVf›Îteœ�îÅ’RlîS„RWUóú‚CèÕÆGÉûÞ|œÁ…=WŒ¡²0*—F,vS¥uh �»ßPúÁíšiEuÑ„yüiÏ �êO•¹&C5Ñ>‚O›¾ø)ù÷_( —^)q‚Ï#�–ôÅ[1–�ñÝ-ƒŽ�Dª‹œ T�©D{»)J˜E`Hwî”Gð“÷ /♪DÚ8ëÃ3LÎjþŽ7H2tç3H”…’A ëOüŒ¾ RXÂuî{²¼3Ü+A39k½�O8a‰Iz×0㳞lâzìÙn:¬`�̶ô¡z¦¥é{÷N5 ùå[:U—ì)ÉÕ¶µ5v‰ô‚D›¢E“À@<Ô¬J‡-°­Hós…m!�Å!‰O,Ô"\‘í Qs‚$Œ%{HÑ¾ÍÆÀdÇiY6\ôAÞblŠÁ?«ÂªnøÖ5 5[q¡ÃèKc:*–b0pvŒ”XzY xá�òÒ§ÍÏ–¦ðœ1€¤�ÎØ�€¨JUÏŠ;Θ`1E®k8Y‹R¤ç¯—J àyÂÕIb=~´Îòê¼ïÄe�¡Oón>·èÜÎ\Î¥œ&Œ±ÆšŠi{D€±¸"–<�1(.ZR$-A]"ãäѺìÙÖÁ@-1¿)ÄØª¯–¥Ñ1è«jҢƷ4?J«0ï¾Rƒç„Åü3x>§+¼Lø2Øë.¸‹¥±¢µlœ´åpæÊwÏæ†6H†¶£�#q—ÆN7 JÖ^qHIêoœ‹4?Ï€zp¨ø¤|ë‚·%©$WL7Æ„R€£!ù»«˜Ùµ#¼ã-°ˆ‡eMéaøœ�Xø \zWò`ó‹¤R•Ðs½+«m$æTJ;-¤Ý]QÝŸW0’§1Ö®³&è¾’Io�PÍüÛšVÄe„¿�×I“…vdù’a;ØÚ¤¤ßC¼ÃhY0ªû�?ßÔã”Ù| ÎOÅ$”š˜rÈ yjql/®.¯ÖÂ>Æ.žØB¨Ò/¶³mÓ¤·|�¯¼Ö ßМÇY4ºuoVîÚÒs»RdüÁÓÅ/Ü>§@%¡vmmçÁà•¼ÙÒü½%´j¯Ÿ­+oѪN5çù3Z2Ab†…6?býŠºHž‰.%uÔ¤ °ãiÉŒu›í’9EšAò�.ÙM»ßQuÙMDÒx�Öû¢ëc“‡|( ³Úø_VðóÞg?DœK#‹* Ç{?oøF=�—å8‡³*|�“^�W\gtŒŸO`«˜áPªú´™ÌoTP‚ZÓQ’Z!–Mk{§QÓ5åwa>Õ¢ƒ? %œçxX̳%Ðã'÷Ù:ò¨¦&1-?^L& óM²ôÁdV…IÝ{YÒÕ*•ú�¾¯Ä×5XâÉi£®è5ð|0ÂÅkÖ•lW‡¤™£±ì-Àß Ï÷ã”R_YqïŒn’Eà.ìv–”©¼²K·_òÖß­ÐÔø—@R(!öväAÑ}aÀ¤4�bõÄ U?—Ï\í›Þ”Ç3f¤&ÀeÁÇ:ÒîªéËrö¯¼Û\Å_HæÍœÌ×YÒƒ�<Ê«/º0tV/`ùýêæÑíÞsd—9Ó&dʆÏö �:Õ0øÕ迟˜n7;²)›"`žæ¢¨n(n @ZP*K“ðï„i–¶©ý¤·K¹mØKlø­;G¢÷&X¢xë.žNÏèFê.ùô'2ljbƒrrÈmß +;º)fÔ0‚#liH-z ‹S ¿©Vi¿¨­¸vWŽQšŸÇw©+ƪ¢ãh\]l Õ°æìãéæ�ɦŽê°¼ ±APû 1Ä{P˜­;fiú#S-X¡f˜¼)º‡ŽWmÍV3U4üC\UÄ>z»5E–?Ìd /ÕÇZææ¥ìy‚¹{Š™æÙ±Ž`óöD€„±&G—U|QúêKVKqMTÙ,EþÖ¶]&™UTûIÁ [,“:=]Ç Õel¯”<:Ë�Ô§ŸêB—“åÅñnˆJl­v¯ �Yú.óÏ­”¬1"°¹Hß]lË›,¯ˆ´.Vg7—çDMEŒš¡…l½îJ¢K6x•i“–—Œ²#Ʀqád»8xÊ jûvéˆ%CN–Rw;�åºQ0SŒ_áÍpû»@(ZrûÖ-ä»*ÇmvÒÔ'ÇÙ|¦Bóji”.Íù‡Œyj¥æ_¿ÉÀšàc®°žåÖ80̘ȧS�¥I˜’™\·3nó„ãÓï[#”�köÈß]&/2…ZU5>Ö™õüœèÿˆ9Ûg4±7} ”é-ôíí‰Ó2c)líÁ9ŽÙû=XyñªRéj˜ª²µ½£kE¢jLP¾­sÕ¬×]´Ç¶‘ úµÔWo‘§58j9Z&â­óн+гÑ5t B¡C‹ík…ä–u¸»2Ër[7´ ²‚f²Ml9®ª¤mø£H¤6ìœÃÜ Îyá{0Þui,‹8{…çê8„2sæ]"J¶L¥¡ÉêI†&Á«¤Ë©c»&`΄—u #Ì�ºCÒúß^çææy¦gŠð¤ûAú¹çäMI,µ5|og¾†­Âk D{ë닆I‘·«QœÇ‹_¶ãP0«�¶Ç2îʽp•Ì]Ü ÎE‚óPö‚¥ãe-êr^,L¥@ó—G6Wv†ù«Ýs äUiº36^@!Ó“^@cVÑ2wQ<¨”Â\PgV–ѾÓ.Œ r7Ô[¿kLJ#ó2šèR%"úF昅pØaG“ÇksD·ª?”.dƒ³œ½åo¬k¸é—ñÔˆYM·ÓÍâÞýØu”ËAñ;Ïw«kk—Q>H”aâ×ZèÒ,q ¯!«e¯ ã'éA^”ýBy�2ËUÃÕ½Xþ\çù%=R>z›è‡™ØÝ¸W�5°ÓLýyŸž12;8ùNbTŽ#Ó)+xc^rçUî�I¶ö{/eéZûÇØÛ=áÿWçúäÿh®qx»dÏàšm?W2Œ«}ð¸q·�‘…^Ö\uë»ñg9$ÏþP´.th›oýQš|äcK!nOè¤Ã3G­=W4ñ¢¹.?—¥ôþ æÂ‹SÛ%žHsSt�ÞÒ÷_žhn¢÷ «ÄwoZ®Z?ÉË£Õ±”ì™5?åT5é*4û¿&,—oT™kCðΊ�RÙ�s,|¸ÖÆÐ¦E<óÔ^„ùS‡1ä§Õ� çwœ }‰Ú¸ÿGÏ ¾ ÖsP6A‹ËB*kÈøêgI#W]ØÒX>£V)ovÌIOîYF`Íú’懲4 ^ET¶ÖZU€xwUezï�–yo°;AÁ`|tÇΈWûU¢�5¿‚§ü–„)ÅšÙ¶%é9à*ŠÂ'çô"Ág´t†Š½’¡ÎØúáÐø“Æ[ä÷TŠ/í:ÌŸåü>Kª½W“y‰€&²fèz�]5·ÈÃ÷Õï�uú™*ß`,ü´î„4Ï�Èe¤ñŸû$¼ 0Ê¿ÏèSì¦`i¾¡Ý¢ÏÍ“ùV/Ù™÷̵ÿ|ÊÍ/ö*Ý%†IÞW~7BÖÆ6'¤î|w †xÌÎìâ—¤ õ[E'+€4²¼ä½K›ëg¢ú»¥ÞмÀ¹Ì)€êv‘gXâQ†Á¼§¡÷G¡ÝïÆ ²H}j™•ñ"V>ུX�û§˼ðO@€¤>°h®"¸òǔ꾜4¸´G·'£,Κr˜çˆIiË˳}o?äæ­#eõWÇ„XGJZÙÁ!ŒÙ¾Ìˆ ,Þfb¹:Á³»´ìõô„=rZ#ÇçV'1›¢†æÍ…é0‰øáò¬ N³“.²"º©Æ/õÇP‹Ÿžô^4Õ+â/Ͳdçº{r�Z“N7½¯ü@[óš’x‚?ì.…ø=¡fž£§Õ3…i仺¡.qì÷ÃO~'À©Zx²óÔ;'Iîà¤ñtb”ÙŒ·ÄVSî±üçßWNF±‹ÅVwD©×+9\[Ö«õþ)ÍĵËâ¯n¨œÛ}ô4tÓ„«?׫s@b1Áµ÷ªïÜ©�—-]çþq™Çb/)íˆA¾ë–J�[óHºCIôÊÍîÁ‚êg¬þ-3:1&@—ˆû0ŒÂ¹®ÿÿÄÿÚ\ô/·= Ä—+ÄÁædWM¹èŽO=óëZ-Ž HB³2 dú`W #³Y×ûWC¤Ha!�çÇLD3 [™5Š=Ç2!9NMll«Ü ¸]À¥Ê§£kБqÅo •JßÑbg„bFG¯zC9žñ4˜kæ;‡†Y3Ã(YµžŠìKjø²:Ãe¥=ÃÄSÈljñN_œéâ6ôôGO wª¹«&¯$5 šsÅ\CÃÝ !�í6gy¤0 å3ÑÝÂSQÝgNýðñ °Úí&3»º;†gº{‚µ‘ë[¸¹$6ÇŽ"fzc”‹œ'Ê…Å•Ã+ó2"Þƒ `ãºd ¤{•]™ÚI«ÄÊtY{Iòª‹¸mžžŽ€­.«—¤XÖè½Ö°  ¡×ru�™Â58©_±]s�k>íWjXsi†‡LOGGž—%Ûæ®_NS´|Æ­Ö¬ÍTw {¦,háåÙ˜7EVÒÎn’Ñœ¶7SV…w¾ÑÕÈψ¯OLë'>›=T]JêÒÜ«Jѹ6=W�Íj¯²]›EAê#=ë®›vªç[bËXKk §§Vc-H=ÙÍq÷ZÏ@ŒmÞÉϼ2Ò˜«]Zw§ ûH¹Ô+½F[‡×®DÀSP ÐycÚ±=E¶«ðÈf»i fîhÈÐóÖöl¢�ÜHÑìoCUÃU9›—jÖס›ªÐÂÞónÕ¹OÉûO?sNjäú»¶%uôkÐK·pÚt²u {P�!陑èTü«µhëÚê™ RÇFØ×Å úžÎõùËúTtt8�œÈÙ»GÚî_PÌ@3ÕUˆÄªç_×)N"Â‹©z;±«-V½`üþU‹:,‘«Œ§Î[~ޏôPɅƶ�€ec\¿jÝÐãͧ#ç­\õ é�.2£Þw fäÙ¿q;&LÿÄÿÚ��µù¿-•‘í†Æõ‚Êî’UFÍ^ A¥Á�­/Òõ“ t†@ß ¸°§žæ+íqö¾Ú΢Â$h�µ +ó^p# =¡§³ïâó‰JÞ±Š×b0¯…äÒ¸‡O¼Ùkj¶ì¹ G4JþÛ²íc$ŠA�ª¥¹üO0¶{ý¤¦Bd‘7çÖß´ŒÀ4’H²Bd µeóœ{Ž…ñ¤ II ©<—Ž·ªêA ’,2bA›ÈòŸè—4µ@‚4S+c#H*d�7èûr¼@a…`U¸CÏh NàýK™I–@¢HHc&ì÷‚ÉÑé.~V1wJÞ`¡`,pšµå¯±VÚ ó� í<î¯5QL{’«Ý o§MZ*äPt…éÙÁ•…»òÛv5íÓ—GBŒ½Lø–êžþ—–$4cêìÂö…mUmÛ›(×¶Ô§›Èé[+\ôî–èfDºî–œüVÑ~«ß•ÆÓ¹™*çŠ|ßo¡-¾Üwn·'.lWÑ7.í¹«±yÆrº=6ž|]»nçàåq¹÷tn‚œ�fl;zØ„Jõè~nU銖©Ÿ©¬3W„g™ìÐ�]ÒûÛKØ¢™ ¶"Š¥¦M€Õ­gÊ�^‚µÕ«.˜µ‹«¯Qç�u†îp¬y–ÛòYu p©ì+Uù4>ƒÁé‰ow›šc7uyU=7K»ªZ,ErŽÉeûøÙöÝ–U£5�X©áªËš  9•ê“;*³È*&³¨Ô]`f0\ô­Â„°¼¤5kÔ®º‘ÀV„�¹¢Úk;Jê2wqç¡Ô˜K­[¦pZÂfÿÄ:!"12AQ #a03B$Rq4@CS�‘5Tbr%ÿÚ ù(cå©AÛ#xÎIòÉõ%~PÄ~7Ò§½OÔkCS zçăœP­óŠêÓö¤põ�#Oj†wg@Ä*¤’\B©"mÂmç‚9VOù!ùù¸µÂ¾¨{�çl ÔsŸ[99AµlfF|¡°>îņõ²úàkÓo2�´Ý› Ò6óÑOÖclg¸¬Ó V€uaÕBäT+�Ú5Ó©»8]9 4ð½üØ}g½åáùe¢±™çB^=ü�ü«¹9òK§5Äî�šP*âêhãbf©%i[Pï÷÷Ït $d9BÙßçS¶íÞ•s�À ŒïK’1Óe¡+�\ÔjÈÕ€ª�b¦QûÝaÓÕÜèL� u׫¦”6¾™VzŠœˆâ·c L¨J[|H”Hñ£ÕÔÖæfC!U†$Š0±öüãùÜD!qFe†Á:ÝÝ·cšÛxÉ©»”¯]ÇÎ6>†‰ð¿¿eæiéÝ[g­Yô¬.6Ém¶é¹*¯†À¥vÒ6Êý6)ɹ�—†ÑV†?Šú¾F´*„!.-¢úFUÍ_J’¶UJËÂîá�<±©¥!ÞeÔmø8�ï™eMATFŠŠ:O‹£,ÀT,¨Y<¿äóÕ§ÔçÒ¯¥q{°¹“s\Jñ–3²HÔä ÍN‘òõÛCÌaÛ!AË8§Ôð‚ûS)o¿€#N1¿Ëéš´¨ØúBeN)‰xs"Ñþš]Aºv(„•ÀêntŒÁÈÐÂ-Y…´§Hé5Ô‘—d™íÂ$µH95qk™Á‡PÒ±ƒnó+T%SX<Ôºez¥�8†ê#‚<ÇuI0®×*$’:~qJÅ[>±Ë"¶TœÊìîY·o üAÃ*GÖsëß¹¡Û½@qè.Ç.1›yˆ Ësq€W}O)2æLÖ½tl$%]´µj+ÛvÕ–\ŠdQ‰7&I°¤9\àR’ K—`§"°ºuTƒ¸©¼Ãµz ë>`H¬[i[Sœ6Bî§zm+Œ×4äã°móXëÜÖþ�¿(xÿ òžúʑގƔjì7åHqXÁê·µ@%qˆÆÑî¸ÉÓÂ~ª+4Û>sùfD'«‹G®Ê:µ´Ñäé¦ê�ëIG+rrCõvåITAM$‡~õžž¡QÆÆ »éˆwZèeÜõêA·¤ï„èîÒ1Rµ�¼Í¡ë$ì{+�èdÊ�V½w¯þF+>ý×F=|C‘&ØñÇÈõÞ£ Øêm¼#ΰÍ6½lÌÁä â0áG(6 ŒbpN+ÎŒÀyQè3yûëjD�#Ì4²G¿ryùý4å¯ k‡ëÓà&þ&xÃÆØ‰Yaxåc—]„¸²7#Z¡§êLb¹Š2mQàf»¦ãfÝÛLdòT±ôÍ1]D;§šˆ;ûx#à©u.°1+e¶5œ-jÞŽù4§Ô‡,kW‡cœ|ÞŸ*mÕŠB¿Óš#¨…Þ·Võ““V÷1,yUíµÉ$wËrùcdc1#fåhÏg-äÍ+c¥¼ª¬FUN,-¢m<Ùùf�Oë#~\®¥%�»»#I�ÒúJÇÖ¢Ÿ!‡P'W¦j@TïQîÀÔg9æyC�2Ô_ÐPÏ›VÛ²äTŠsœä—ô®cvÍg5°õ£Þ¶Ç�ð>Þ†Ÿcá«8åü½¼$bí©Žõ�Çk# (áϵ2a{îƒ}êcýÎ*ÊîÍW†[«¸…5T3‰J#�Éã2DUXm<:uwÃ]eTœE�PâŸý©‡Be¨ÆÈøeL>Å–0 ©º�&¤M—qHš}hÈã8¦bOæ v °¶Ô.P×HØœü«¾kFUÏr~_OÓPΪì=üä Ò†#Ï™†r6� ”WRæB1K¾’®5Ú¤âWå(eµÊ�ØþD¯ËPOeß±Û�Y¿7�¦¥áäÄ$iÂ×! •ç–g…×<¾µ12aŸ`ÚˆÍ$ÜØÎµÖÙ~É&Q±Þ¡ ìtŠE:}êbja¥»ø¶q·®Ô@ÿŸ›;øf‡AòGjšnc)*(üýÍ)ÏIî{ø&1ƒœ«ªª®+ž zÑ]În|Ec Ñj–Måu2憙93úw£òzøÊ‚TÐÝ¡½äLb`tIÄ­Æ�v—‹[²é{SQÊÜ®ƒQ�$HÔßÌpÙe?¨‡l7t<€u rrs‘hR Ë!LèÞº‚Íslb›ÍO§;xF1ÔNÌsý¾lø®wŰ?›é÷>�A€RHg4ÃzPH¥Ô½œeŠªŽáàήڄϥ K¨c‘pV+©Ô�ëŽÕçnñ"¯äqŽŸ«Ó‰£aºmMŸ\Ôm¤y6w}�Çð›ÿPÂ>�³º´„ì¹Ò²ïžÕÌëÜÖ{œÒ•îÕ‘�P}jli;où €;�>9C¶(2s7@@Fa·fw¡ŠŠâ@:¼±ëc”},¯Ð îa™5‚¦@lÝ*ÅPÇ �¥åùELâ(˨]‰ pšD·ó›Œdom2mͪT/ª‘ºsš#¨àU“ç‡^ê$S6¦/ËÍFŒê]»#ifѽ7zÛ‘‘Ýr}>LíŠ261�¼vÁù��ùÏ}¾\|ˆ2i|ô‡Fz±Gê Ú’Ãb¹Ž Õ€$S ŠÊA¨ôî_¦¦�:."!…�ìQˆætUA„ >3ÜE�·k©¹ìCS¼­ûÎ^WÆ–SŸ¤Þá¹`ê¤�¯Kn²�-¨SM¶1ж°™Iê›éÇ£ ˆ¥éÓR ¹� �´ìE ô—Í�Ìý¹­«·ù8ÍF3œhFÂu�£ ÚWS®�&T*ÃlR’JiD>BH˜¤ååÍäῳ29úexIJ@@ß>'a𻏠3.™ØŽCÔØÒ5¢‘¤�qé"¬ÒÝÜsfd©•UއÍ&]Û$ê–Ÿzá£U”§UiIy†œõÓSjÎûÔQë4`ÐÚ�•ѲI­—ûîäí¿Í�z>å4ÌY³·È­…Æ…4#Û&™q�èãþ~tRNÝ`TƒtÏ©_VjGv%œæµe�ÉŠB„œjêc¥Ø�±ý_µ°@çRÙÚ²Mη—T>Âñ•-œ¹8¸1õHWM",ØFÓ :%*[è¯O4¢i'u1¿›Ñ÷a ­óY`u`Š· ðkæÆüÁ¤µBàÈ Qnªòu§v“8É©$-F�ð? ù6 ¸ÏÈÚ4¦�CSŽÇ:Hó m8{„èÉÚŠýþjS�ÓQ°r6"¥èÙM)¤ïI&–•eÒÇ SÍͳ�R ;Ô(²*°“ê[^I …¦Þeš Ê~N7?:m ßNÞ%Æi#(rä°çFN�8Lª¾ZhƒÀò†éxÙT7¦ãj@K*^–+¯UBúl&Z‘TcDšë«Á¹_Û¼‹§Àîv¤L¾ÇjÇæ63�Ûê[YA"”5yªCÌúC©S†;�¨wíO�³Ü“ùß½¥éï¼v¦Nëš·Á}Á#‘”b|ÏÌN‚qQ�M†;˜}©2Wr¦¸t¦Þ\•$+jP¸…Ù�‚ É|¯fÛaåC|Ò�zŽü¸Ù9Öü½ÃhØ%Ûs¸X€[ 5Q‰^Ø2:çIþ¥W ¹¡Þ”}Œ1O¡!’=¹™Œz<�QxVÉ«�`¸+hÖ K¯F¬l€“ö�aå•ýÅ×§–‰¨-¤–DEÆg…á�¤�óó(ɨmÝÓPÚ …!³"s6/›‡hÎWíà2Oz]òàwÒGÍëà˜îÃk W*ÙÅ\õÆžZžÜ®p(1ЖLcU,î|Ø5¹=]�¢Ç½I¾4šõv9³Ò-c«¹qq#2Ó8Pzq¶?vdˆéÕµ�Çó¨JQØ­I#¶=¡ø{ûÍÃÁƒZÌ$m*ÖÆI.žé¨!ì_MK+=»>h“ò/zcAÛÍrÔ’ƒ€Ä•Æ)cÉ8¨ø[Ï$’.5\ÌóÊ]ûü£ª¯�Ù®-䲕e�õPw·xô²ÄJ|f¼-zæ²=¼cõÉ81�÷Fd]-�YùdàT\9ð’9n¸t°(o5é¨ó¥8?Ô3Ó.2÷Ü€@­%ÓW!¥ÝFLÈQô‘ƒÃ£^™E©š'ÛRTñÃþ›Œ˜Ãóy»Ë•å½pÈ„’a—"ú×@R ¨af|b®`xÀb6îv®[cµojÒÞÇòbE1d÷i6Ò6½-\®ŸJÆÝëÒ¬î%·-Ëj~+v5h`µqq,ïªFÉýݱ\.îSdm6æÜISÚÍ=åÈP�WƒHy©þ¬Lè¶«Œ¡ªQ;)-pÍÈÄd¹¶œ,Ayn)n¤’’Yc·Þ!½J�ËÔ¹W·¹�-ôβ %[¶“\L |ëYÝ ±�¦IºóyjR4† ÕÒ)’65(űÍ,Š„ƒ½7ÿ™w·Ó©“�‚šhµ¡’9—F(ðgá×ôÒ[‹VZõÑ­í±ú™¢ä®ŸF =ZÝF3Ëf–ùµÝÊØ"¸séiÜ¡ÔîØ Ûó9²ÇÒÃ.ÜQ�ÄŠµÁcÄ<Â7ã_ †”ŸsNÄ®äøjosY>æµ·¿äÛ~•æŸÍB¯{%GŒoM£Ó¸F=”×)Èö¥·ßyR’óþ£T1ˆÜ2ÂsÃꜚ±›\I{µ�θd¸ljá²%âM$€ÔöÖÓ"Fá´ÜAQB±¦Œ¾˜¬Ÿ¶›­f?¥§Q{îßC¶ôÀ£ T‹é‰f .­Ý±™'¿‘¤D’>]\Ï¢Ú'vÔmž6·g—˜õ$–¼Ý'‡.n­Äe4/&N,tÛ·í~gµ‰�2Ñ[@½’¸ÄQ¥ŒŽºµÈçD• l{ø ?º¼Ã*ÞÕ(mgW{K¡ƒ¤Õ£$ÐsÀÒ9Öñê-*×Ô¿—Dxåq›(mxb¯š{y]t¹Ä%ç¢Æªú¹L»é`&^…4 ³` –…Ôé*CIá6‰onÑwN1Wª‘€ºs_ ¦Ry�àk4;Q9ŠŽÆ¡’®c·›©âɼ ¨bC£ðìÀZ°«³4‘…`�Z]\TI.4ñ»¦¸�FØ·½¶DEÉ+õ«œs1\NæÚK9£i„\°V«É#—–Ë«]ü¢{§•cдs Tj�‹ÇÕÁ5ë_Kø#r¼Ä �ê3¦ej¿â‚æ8Ç(ƒ èM'bdVÝj[Û9K†®2ñ»Bc9ö­oœêl¦·` b47 8ùí­žl‘Ø zaƒ¿k^G ¶I&¸?ˆ=­i?'î¶jƒŒYK³1ŒÆèë”`Ë$‹m$„â³[ÜÇÑFUõÖ£ïQÈêzM%Ýî:AÇñ ã�T±ô·rF˜ð&¸’[†t‘ÔÅw}é4ø|EÜò‘ŸêîM9ðÏMBÙŽeÞŸµ+`Ò=)V�W\5$�º¾(·Á·(³5MÜ¨Žªt_ä2æ¡–;~Ž¡Mŧ“R}8ëˆÞ€Î�i<„׆æ…mÎkI¢µ¾+uòšw$õ”Î*;$j‘�:F[ ‘LŒ3ŸÈ…ôuüùîùÅYÍÊrÕã~#3_¥ÄxtV°Å"d׊æâöWå|%ÏûUð×ý +D€à†ðÄn/öÙÊU`ˆv·ÌÖªƒÍu ŽâU¬ŠÕZÛúÞ§v*S´äˆÌ“oPȲLBBší1 ¥ƒaE=š‹S½k4‡Þ—µZ–ø… FfR¬PÓR5#€¹¯ˆ”¶W®²Ü¨“JHÊC¦¤<È¢Ç|LøQ«Ki&‰b’ë¼ÄIø�tëÁ +|MŒ¥n¢gS~ ÕñS±éE«í_¬ã2(såE®@ÔrÛ!zjÕÃ&™;!‚¸¬<¶ŒŽßä3-EoY-º3%qX#ŠÒ$[†iÒ8‚‚Ê äÂGé 6�úµ-«�|Ä··†Ù[’škŠØ‹ÇŒ™4TCb:rÕqÃmn.˜{è½ÛIJk£Š›Ì*œɶƒÀlÑ^^båøÐ†;>^�Q2(d¦ž<ù…“ÞµvÍFrhïK�Cg{µq/Õó(ÓH~(`íb>"`K•GŽÔŠÚ•ŠHÃa®Uã˜ó6mGú�[]O G4¼Rèjý2$‘ÝË3Ûòô�÷ZÞéŽJЎ镪T�œ‰¨SgA5n¦IBŠˆˆe>\jÚ¸ô.¶P7í?�>uRݪ4ë¨àÇÄ_—Ë8I\™ï�£«»Í2pã6…Y#âòsyon5BKF xÊA'j�¹�3šc¦Ýžµë%Û¾}¼&ÎÙ¯ÂðÇË‘Ëf[Çx¤òñI Ï/éoèZ½–·ûR JÆÕ.É\Fhß“¡²u �oR¨ç“ÝmŒÚ¥Ð=aíî [†Á[«•wÖŠEs#“δmíÈÎ…£gnÓZ~™Û–ˆ;þ¿¦¢…¼Ðÿ†— /�QŠ…tÔ„2Ëo¾e«°ƒ(*ßZÌ9`“<7™Ú7ñ.$L º7H¡C4mk0ïSÄGqInòy5$.­†:M#ÄxXð£œ(\Ÿƒh£æG¼ªøs®¤mX®1+O†»ˆ\[hŠUQ›P<àGe5ž‚Ep.d眇üY?.ÄB½íçXmá�î÷7Qÿ�£ H¾• ×%û‘QÇØÖ¶†@ñ6í…ÍœW,áb ÷¦ŒgµiÇ¥ Nýé{ø:qO røH¬`T“1Ë�iŽ{;{Ž¢˜í&¹¶Ä1©$懲šÉðu¢¸¡ƒE È’È/U³_Ÿ<=7Pj«iø™Œ.ðB‘ UÃñ h„È�\=’t1mBâ3åÞŒ0±ÉˆfkuÛ—ôê{cžijnÙÙòÅ¿­E| ÕŒí/ � �élÏ»V+?µb´× �Q9Ÿ¹ŽÞ”ðÅ+ËKhÂmºDVÅNn‚´6Fh„�Ï•·ø»@5È4IwqíMÆnS?C¼O‰0Ù9v·R¹MÄ—;‚£òg;Á)ç˜<⮜7Jžœ�;Ó­p@³‹‹7¨ßTj}]÷¦ïà´”>Õ§j¶øLÉ[UÔܨ¿ú;œúþ½6÷Bo£ÇüyÓHM+ûÖªÔh>ýé_ÞºMi”26¥sí´3VÖÐÂÌè€?„ÃTL(òÔž­ähFàe�Ëdß `\ç#¡¶k—þªø·õ4÷:½hÏý�|Cz Åb±[VjÌæÚ:“>”ŒÜæ×ÛýD'ap:‰®ÇîÌÄa™ˆø»¬c⤺¹4ÎiÝßÌÌÔ„˜LJ»ÛÚÇÞi(´O½$°–ÂÁ¹E?µknlµ!×÷¶“áï!˜UΔâPþÚ9¡IŸø=ö¡Ú»× xÑ%Y Ó¾;×lÝéô£V“‹lÈs)ïHw¤&²h}ûíï¸"�4»ÖÞõ>ž»Åîà7’Ç8å�ŠÉª'$‹XÃ[D÷ݬ¶y†…ªéÒX‘6ê¸Òj[sÒÃKÙËèmT–k§ª'ΪÔ~N~‘ÛÆ1Þሔó4†NL}žáÇ9¨äÖƒ\ºÑB:U +oj·åFJiö­…ÌÕúå4›ïOÚ¯n5\Á7®AŒìµ&/­b–�ô©Õíµ_æå¡F­›Lêhÿj=èTu¨ê¥o¾ùÍ!ßÖƒ gµ&0)|¢‡#kò¶´Ýìn­›]¬„ˆ8«)Ñwi$·“ôåñþÕÌ#ï\ß—5jßËäTg+W1j º+o&ST«õ;o¦Ž<sIg# «àä¹+�uo½F€y¡ ß—ZyWi‡óRЏÙkKútÝ©�­péNygµôŒ=(·OµûÚ¸RG!“R\R1Ã@ÚïüT´¾ãë §ZÆÇ4t�S�zÚƒûŒÒ6ÛÒœwÍ¥+ „ÀðO:Tšv:·¯ÿ5q3.&ˆ¹á.»Y*;ë›fåÜ¡5ռáðÇ¿Ž>RïQJ –ZµpQH¦l¯Mrãæk�Ô%ÁŒéuÔhÒ¡mÁZÓK¸ZŒ\ƒµfãÔ-o�• Gµ3ïÚ³ÓY_ˆvÎï–$ú*‚µ/ö©×N*3†»àÖßò¹«÷]¨6}xCÿ6Ë\gh•ý$:¤f¥ïà ‘Ü�T0¢ôhJiMŸJ 銃ö ¿qŽŒG:�j^øð½$"âƒîEµo[Ô�$%@ËuÂAÞÝèM{bØ�6÷ð˳}7ÑëY¢ï@ØQé5ÌoJÆ|Æ­sz¦y"!¤@ªR†ìבscÛ¥€a ‰W¯oÓZØÙ€Ú÷åf”Î6UÒ5Üd씆\dâ�åk×½09©zT·¤G#㣞ŒQÞQSþ¥ ªÎBmc­¹†¶¬dÑôFmpÞ‹¸v¯Ä"àøÝ”Q\f]¨ÿÝcÖ…Fh‘ZÛÐÒ½[4©ÃÇ¢ö¦÷¥;W—”"Û5ñcQèzKÑëán½£rmÿM¨\èzø”=µŠ7Ó"’.llåÞÞ] ̺²rìœMñÕÞO¦Ø;Ö¶; ‰"2&8õí1¨ìÖ¹F t1ñ¸FÏœ!Ãöµ¸Iï7�ÇÙG§é�&Pb:Yk–ƒ=4?ê›zÕ¶ä'?ÛÖ·Û'l�XÍ]·Ñ5êb°¥sš�â=»€Fþ«Êï¤fˆ î+ƒé~r˜ëÛÔÖ3é[êÇ¡óÖNª¦e8ßñtÚl£‡Ö�€5m75pO_¾i»oíL(xI¤÷® mÊ‹˜ÿ©âH^õÅWXFÎ)ÎàT›¿H p ~ðú…‰=Y®Qߪµi4›îWMi_Þ€‰8m›¶­8¯…URMá¶ÕÛ´6±/›¨§-1Š’UZv×,’SŒ`ÔɦB+×ïasεFý÷%LM¯º�Cs¾øî3Œ~íô�ëÕ±m¨œÓn|Õ�n÷Œyx5Ù�­XSD�_f>µ3Ô6¢’9ÜdØs"YÆ)4ïÞ”{o[¯c[{VG˜×»wº�ý1GÀR1 ¨¤ÕešÚ¶|6Ú¸LsÛé|¼`‡PhVÆ7GjptޤÎ>þÇ×êÅJŒ}h% ý릢н°ÏõcN+&êâ³qæÈ4uårŒÝ†gÉ«–ꥫyJTâ·ÕêÇCgnýŽH­4»ì+Gq];ïO�JÁïWλwm¿¿áËhe¶�¤üK Gt’÷Je 0Ý[×|{�÷£�÷Ú<ã|Pò}øŒûrG€£Þ�‚X“2 `F¶Öëf°i.cåLÈköñõ«ÉmΊ�Ǽ|Tó:ÓhäWe«{¶uö5�«5§–Úó]aºNk&îÙ¿ª–Cƒ�’ea¾vVÎæ¶>ô°(Ø�GS…ÙFwo±ƒN7¦9ÔØé«¦�¹x9¹Þ*°`­¤ö“§5íìt�p6Õ¶ëšm¨àã=º})ñ¹¢ØíSË¥s�Øå‰®Ä²˜dbñk¶„ê¬Pí[“�X߀v¢vl ÉÑÚŠ¯/r W±ræ>£åµndKï ÑT ûÕË´ŽÒz`ã=ÇÍdœÛ•�¡FõðmÆ*Våܼfµnry…‚ê]õéÅk'íQíMs7Ï`Äã}—š¥WM<«�ë¿P}µt“ª™±Š 7ÉÁ¹uä� ÒìÍ?V”¨.õêi—˜£ ›Ô/©t·rÈ1¦Œ¹_eÔpÔθÙÅkjæÙ°ÍzûT§-�R¨;ÓÏ®ÖÖäcÚ¢|dm\ÌW3'ª„ƒ³P�ýÙ™eÎË„ûïBQ�•«‚“.ÅJ9o¦³]é�ü,eåɃ٧ÅCªn•+O®1¥…jßµjÞµïÚµÔ*Ò�R‡ 1_†ãÌRO� äXbiá`mHÃñ ˜®Ä£²ËF`ÃWÄmBAÙ&qïƒ9ßjçí‚3Mr¹é޾%~â¾ûýšøãœBkøoôŒPá|CT«Ëyít|AZ^ôº�ΞÅj哱jµ‹2é=ŽcsïÃ8y¼Í’'à¨Ýî$¯àqìK_ÀàÿzJþ mþäµüÓú¥®-½©Hàfç¹îIɦØU¢f\žÒ 3C¿mû:–FМ3‡²‡ãÂì?õ–¿…Øë-/±S•·Lþ!B‘GT Uß§ØÒÇ1w,|? AG;ºÜo‡Ç=‹r£Q-ûwáü›‹få%raÿi+ŠÚ£ØË¢%æðõ£áÀ%ŠAðïëE 0£�C.#é}•Æ-�Õ®„=n9 ¶Ïšö£æÀ¢íØ%”Úc¹‚>gÀÙÿëG_gÿ¯²ÿÖ�äô®+0¹½yèý™#d8Pµ÷"²7è6–ïWcPƒ_†nyrIo#á ÑûÒ�ݼxÅè´·Ûy·bYÎX÷Å>†ç5ÂV†�ùH7�²ºZœ w¯ÃS‰xjGž¿ÄÍž$ƒÓ$ãU Ðjò]]>d¼¿…Ùy—ÄV¿Ä[Jü/s X%¾¿«áÄ¢ä_J€asÚµ{Ö±ïVP5Ôâ8êÎÚ+hôÆ>I¿kPðâ¶Ý&|³H��«‡R1Ú²6ð:H®Ää�´>d†ÞhæŒY§ŽHd1H4¶ô¹ö£é¶Ý�j¶¹’Ömq·ãÍeèzâ|F;o¦ƒ™<ï-̺¦“SzíY�©êÂ…¡²ûÔzÞN�™8O[Uçσ<’ý¸¢t —½œ�ÿýÀëC½•À™7ýI]#��Ή^5ÝÑ}ô Š�ö¤8_¸ ÚïkžáS|v×Ñ­Ä}Ncr­^µepÖ× 2Õ¼©4+,g++i‰Ú£Ë>¡“NÂ!–îìYµõõðḌ ):dTŠ6Fíw ‚æH[½~¼ø[Ѩý•‘27ich&x›Í¼·L"ˆoÃ,ã³€*îõÄï#´·26íq<—Í‘²xïÃÏÉ�ýÛoáÄ­ê-Ç]Ô|©J0!µÎõœQêÓ–8?qZs¹5Å$™Ym:cÉïœ×í;�¶õaÙi¤›Õ¬S]9Žó\:Ê(s±–âç_J캱M‚˜=�ZȨ¤,™•!†ÍÇo^áÄJ1 kѨ)Ó¿üzæ˜zžàc½1É®ˆµç«5šâ6Isl$‡ü@¾ô5ö®q47K ‚ññ‰9\2á½PtïÚêNcÿóC¿�›»‰�C+Fví ©'c¿âëlZü&Ù–ècåÏ€ð¸ŒMÆÝ¥�¢•£0>žžÞ•»5§P¥jõ¢k†]›K�GôІPÊr>|þGâý ÚBÝH‡×a”’rNH/ûsƒµv¸Ò[«¥~ù8ϧƒâïÀoÓüŸÅS5 ^Ÿ±ŽvÝÔnâ´.T*ï�€ï‡\­ñ‰³d®‘ ìsLªAê¿ Ë£‰ªü˜Þ€ùÛâD¹›ÉœÐÿç9Þ±ÿHq¸±Þ‰£_‡¯t?ÂÈz? |Ürûá П®½]ZލµuPÕ§>š‹z‚`«Ehoz�á›Ýˆzü=mðö:˜uþObüRV¤Â#¹-'“"·'RP— "Š‘s @œ–Œn“tÔUEj)�,k„äí Çä_Â.-$ˆÖc±_°Í{QAŽôÚpþœÖ7ïDQÁ.~"Å56eù½hx'v–vüÆÝ¦’[›†�ØéСs©: Óß'‡Rý»úäù�lZmÇ|Wµ[«õx¿%Ž•-é“<²6Ú�´h@:õhÕÓ»÷ÜŠÀVÞ´õêÑÒço¸‘S1¨ÍK+äj=.þÝÊà~Wâ+vŽóšÓîÛPÔ2kGFuW¥{ öŽlš9«+‡µºI–”åAùµ{¤0´²%åËÝÜó$í�ƒƒŠWpØÈ �æ¯6t Ž�ðÝŸRÍ�¨’£îù_µpKO…³�©K«'?‘ĤØO!¨P°î)tëïLHs¬i9ë-ª†� w4ú² Õ¦ÈÁÍs*u`ž–¥\Kvü¾#ÜZI =ö­öêÞnù¬ýæÑt´GÜÚ[�úѲäÔ^¬s+�ê¹Æ,ŠÙü݈pà©Ì#ÆßþâÚµWQ¥H � Xþ^"ÀwCÒ\3×R#\‹”À‡$ºš‘aA*ÂÙR$+žÖEe¡¸Í ŒÕîš¶ä7d6‹3~´V³–‚Ç aNÅk€óÔ»4bBó=�g”.è}Dl<3Sn•Ð_2!´5ÌY{˜¯+å[>w¡â_„®4¼HsëS#A_bÎNQªvRk5Y-\þò^™äùŸÀ®MŒÙL](º©ÕlP­�‡öY™t}ÍS¢ºË—yfÑ™ ô'N£«’uþ üƳekMM̦Ý_.ÒË�çŸ[1a€Ý"ý¢)…2f²¥«C*šC™ZV.œ�Û°¯±¤¿&FÒür¿…W5’3ÜÇ´!iQEsе¢–BÂO2ÜT¹s^�=5¹[KcYì)]£ÿ®LÖ¥D7讂¶á7Ã¥ ÔËQ‘Z´~JYÉ£U'%מæmÍCC¿&”3ÀwÜN…q„^¥7èVQz–†œ'üf|'Êl,jÉ#Cqü2Të­.,…òèSÌάÏz³6è1eqªÑ+•Ó Æ™™Q| ø áËœ–lO þH±2§F&hœû˜¸®�4žü«ã;rSû4“ôìÈž úbþM¢èe� ÃTF••�D=Ãdfw–årZäÖܺ!ÿF¤'äÈÌrŽœ;|Ëü Viw¹Zb,áÌ�VÛûfmͬ²fu3t;È‚%B›roð[rjÍÒXŠØI»!dÌ�Ož/’/——a¼14/ƒ«fuWåªä‹à©æÆò|¹ŽÝ-eí–X‹Õ+í=ùaª+â{‡f�¢¦#“„l¦8ZoàâÇkÂgéJõóBÂnLË´™˜á­Kõ+‰— ú‹øÀ®¥§Ä;E §Þy™ÉN1t+NçjÌïÉß§¹›±åyšêSRƒe33FÃx•“ñ—âH‚ä/1Ç̤çY¡óþEgCôëâAUQ$J´†ÝG’>e¤ý¤(kù‘0ñí�¹E$qÄúHÚŒEJ ™3…5ÏI-LåGòC™^–X^O“;¸óCÃÐÊÒ¨ðêÜ£VbƇÙ þÆýBʦñ.!G™R«kâ£h�Þ�„E\Zò}'ôS'î3¡û×5+Êò¡LjD‡ yè7OH³QJ(+š¼û‹¡—G$Cw¡‰ jï‰òö;��СóîDêÅ㦿¡E>çqY.ç‰x_ÊùâÃ9£q|ÈìA ¬SÓú~“þ6qãØƒ#t}$XØÛ–/‚¥Ð£XE.²ì~×COTŠä Þ!Þ(p!Ï’˜E’<8¨¢Ê!ÅTëgÉÚk,pœ'Ôât—r”Çäà?{Á�ä¹ ’‹úø+6CïwEiåŒsÔq ¬‰×‘ú y¢Õô8�¥™ ^�qC7„úNܞȱFªÆÆÄ&È{ æ¤×ª dž‚’vhñ^=�Óò­Å)¿*³"^hwR¾z,h?KD7O¥ß{àƹ!I^ƒÚzÂjv;OéæŠOìTWFøÇ'›L4PØðÕZ‰R¦¬ÚJqÃÅs>“´¼O³)�Múž³¤»™Ë±Ú]ùÚrÝ�廹¥NÆòâœ1T¯?ÏAê"8c¾«à ‰ªäjŽÜ½ŽÇ~jÊ•G›GÒÞ\FC“ð¡¨ú5�~Ü�®j®iÔ†,d±>XS3åÞ}æØù.³yS¬÷ø ½ÍI榬‡¬»Ïêæ©¯"4Pˆo­—#|ÞØ�"·öoˤ÷"· ÞY��(lnliNgʰcå­ rW¡¤¢#|½�¤ÞL�í)è¥Üj¢U2 _‘ò±O)«ËÃ|ióU$Uþ*èÇö\°Ë9~Þm™¤&ü´�¢2–ãÉôïYF¹r.B©3¿<ÅÍÅ*ÉïÐî1ÞUäÏ�ÌÌ圳äE]ò#TìhRZr)|ÜÑf+s»£¸ô|‹¹¢U7–RÎ]Ť¶&’ˆ}&8ª™Ç†ê[ÉJ¦Òyó,,,ú9òÀô4¤»™É¿+Âq ú”»ò¾_мÕääµfÜíÑJŽQ®M×yv7gÔ}dvIÖK¹¼‘®¦ÉÁüϨïé¬�Îâ~e°×$wí-Å:¥Š Æ)Å´úDª°æ‡é~L¤�Q\¾ê\ìv;r¯,2Fó̼5×–/Jß#/? Ê×$>ÚYË2‰Ò^'šAòÎë“7¡›×‘9«D,ŠkɽÐù÷fÅl™¨µ2ƒ$WÒSÉj7ýsGbXtš³÷.ué‹›Që�§óDò3Ö)no(n3î-^7z‘ʼní�þϬ¶(…V)ê!úé(½U"‰PwæâF’k¤Úó=9|?ýŸ$.¨W…ó«E¡“Ô¤Ö,PÕ逅“¡„ûš¾OÉá?5Nö=©Q Z*³Ûï‰ââÖ›ri‘¶3¥b£4䦂ÌJã…Kîf§ácK·;qçÍšÔŠÜù=m÷äMDÎòY®wè‡R/S�e�™š>}ѳ!I)~Oo E±°Æ(i=a?~'ÒlˆsCû¦6bæ®Çò¥iè¹2z=dþòÊâ;Ë^_ÈþËAŒˆ{_’ðSL@k{›Ý˜²x/ø†0}@HÌAx¹òîwÞB8XeF‰ztÚÞ /þ|�‰M*­â±^H§ÌcQ+œCÕ„ã×l}>†W¢½+1ñR�;® `ŠY˜=álÐËõ8W‚4ÄoÝ®u-Ä¥ê¥ÊÏžüÌÅ;ßÉGH7¾)°âNˆÛ=Ñxffu{S Ir³|KÞÒÊ`WPU™ì‰L5K+§ú”ÖÎëÌÔªÃÆRRG÷3Ü&0ú$=X{z„g´>Žg?ü âV¦TfTµë”TW¢…¬£9‹ŒexXË6Éâ7ø=Ó]ίRîm³†ŽT¬\¬y˜²Uf^Ò¢ð;²duW²îRæ#Z'%òyLöy é™Ëö–¼•†¦c¨0å0Ø§ÄÆf­Q�É®áÌÇP‡–ØDiùMzV3P™•‰Q˜õ^‡¡«ŸF]v­*%¥n `¼÷(]Ìþë„Ã`A�¼—¹ËŠú—$±ñÔ*òÆÝÄÕ#)g�TÎÅ**²¨­D��ºEãÈÜ$ìxI÷‰£ƒ6�׈˜·¡”�8«7†×àOyŒ1dÏÈy%&#òÒC-J]º#,CÄ�z›ºŸ0Û\Ý!)ÏSIãG Û6ðÉþBâì—ÙÚLÃ:1sI)ù‚ Sö:‹zt}âz¬žjæ\Éw¤p Çò8ùŒl¬§³Aô&g^µ™ÄRÚ]L »ÛÔÞ3·¼rñ(¬—•‡¼ÊÅŸ,´i2©ÁœŒ¬cø@XÚÚ¹�[¼¹[ˆÙ¥g(Ýb8öW0·A9µ“g¼îÁòàãbt”Jcéî9†˜¹[ÁD¶]õEº…š± -©XnkÁç »÷ ìS2?Ú*Ÿ2“Á ós�RÎb·sMJ: ò2ˆ³‰KÌ,é6Új9Þ¼•h¬û¡íûjñ+AU¿•” „¥¦)‰^7Ϙ³é�GQãÑ÷‡Žã‘ S7¹¶ ‚2ÜÛ{me…ìÌ´ ¬5�Ë 8â$úp@ïlØU±ž5’5ËCQE°o\J˜'¼Í·E:Ìkt;þ mH­øQýÌ’g.ì&˜¡ŠnÙÊCˆ=qàÿà{JG¯h¡òâ¬Ï«oÚfÝQr‹›Ä¹˜{k, cÞ,åyqëáå"lPá¯dÃ4Ú¢Cb£Ur»cæYeÃo>%×)S¸ŒqmÒ&,o§Úgh(ôó´J½àÁ-¿OoBª\kÒñ RíK¦Ý�„${ºv¸LVg&|ˆ|Júj­€°c1’/g/Ùˆ PíE-YÊZTÇÁS£òFdÕ• �±Œ ú„Ä@}âªk /D K5EÍÀfe7ɳî ‰Qì¨zEõè_)Q$ŽO½Ÿâ©y>'›ž`©§™™µæ6ˆ‚¢>9YO›y‘C: y":ÕY±¥×#7Ê0(4*žß'a¿ WË cZgî �N}9ú+ÑÌ2e*ÁÚ8R­é,n2Ö*¼|�ÇxÍÅËÎ ˜%¸ðÎɱq€ÓCx`°TÌxœ‰¥þc²íd©ƒ|%ê"Ö�ê bH"àk¨bïÀŒ*x.@ØQ°¯p¯w0È©ÈJ)vÜ•nþ«6}vzï9Äw�EÄÑË ´“ˆ�›}3)c0ômÉYÁ›Ÿ3/]E–Yã¸Ôq÷ E(ª}æRS„�C/3˜êfj^<ÍÌߪÇà ÂJ«Ìí1™…«ß,ꩌØÊØ;ˆªÕN*QŽ¿ ‘ u¹s±f¨‹³S;�nŽ"dŒø…3Wï.*Ul¡iñ0¯Ì —w«Üª†7 ÃÕÄcƒpÞ¯©¶Žž§«éÔ¸Êmuã×+�Âl0ÕªqB"3(tïy–¡¥ã×yÜtðÒq—.—Ú¹¨`=ÎbÒJwèúW¦*>†å XºvИ7솱b/¸\ÒÄÚvKâ ÔÿSËëü‘ô!2æmêÀ¢õ.Å(@=¢žhÑ5ùˆõ‡jƒ`?ƒãsÈQ9 äKº…F¦Èòbuñ0<\]~ MWUÌ¿vÒ²*0 qR¯©˜¬6ÊÐJ[òÇè cp©j6b ÕÆ“æoQ),ÏMúï4ʾká~e-­}f•&[s)©ˆïR– êî�Cò›¢ªša†d²�üšúZ`{k>j`Lœ¿@…ÌËÒ31èÁÔ(€ ŸõÐc—€}áÞ#Ÿì†¶mÿ2õZ7ÒñÊÊ´›52Ö¥6ša”ÐN « ÝîZOtp€“:[R´;�VÔÂPùÅ~¿>·ˆ¦_¦€»3‰EƒØÁŽþ�­Eú°CgÓkf¥ø×q›¨A8yŒm¬Ó�€)‘ï‰ ×M]@?l�LD¬v¼GÎ5 ³-ÀœFspg>‡˜¼G s;SžDz›̪¨`´ù†�í‹IÈ7Ä!3ƒ—2!˜i> oˆƒLn̺ä¾y™ž¡�±lÿê[aÐQ;ú’‹õ87`¦¬~ºÅß§>‡ª«¶«³Ú[Î|¶Ÿl’ˆ9Ú"§ar­Ê¶†Ñ¸ÕÞT|FÀʼʓ�»:¢# ‡ªÇ^‚4'Imôr¯Îw·¸ØïÔcW"]5ÛŠ�à\AP_i“â7ƒñÙO²\©¹J°à‹Ù\À» w2*Õ–QL}.QDaVýM�ñ/ ¦>«8DôC¢ äÇ¥ý ÈQÔóes+ÌÑlÇ­Ôg í®¡BÅ·)Òå®nìjl¢3W˜/T¸÷v³©áñ&QÙé íoç0Í¢ÏöÊp[:¢ùÂ-O2RUeäÆsWÇ8KwÚR8\[ ÛæÒÀŽAâêRÆÖ~òðP8Š$=àO)ÌþÓ*Ê1ôãÿƒ¯•Yª &PÔXzßÔF?F3¸)t7ÂQºø†MØ3~¦ \Æx„ÏL.V…Ê9¶¿x­Žº3~ÙPú΢Õc•`Ÿpa^†ª&€¹BáÇIÞf™¼[÷/"§¼@A•K“7œGáaYerÎ&æ xs1Ž­Ã…aÍG§4m X µ{–õK!ɶœ'ш¨Óè«Æ`©xÑÖôÜtf-¯CpÕLa*ûAH}N�ñ©½ ËÌ-HYáQ>%kÛ0Äæà%ž:Âì¹Kªyõ+qȵó._�'™*$Â;kΗĭlÁm;zTnú D¸=öFnfe7{ëPÑ5fº�h­Ìx•îQ¡ùs"X+‚¸Ü ëÛû‡C”„»’óéç2Ø{Š],(Ùõ ÷êh�ýú„h„dl/³ï8�?BŒ•ÌfÝöK9æ(ý'S.†&”²áà6² ]ôŸ¹}@¾�â'¯izØy0ÍÂú·¯dn[¢8sžu,ç§—™²6ÏP¯h­kƒ�,žÌå` Z.ˆ#ã öR¬á æ¦:ê/Z&­°aÚL+Çw©ȵ)~ Uà�l‚•gXÕº˜WøßiKTé©hÔ¶+?Eú0>ßA<áŽÛü!ù]d¬/õ˜:‚�¸”õé|Æ=(Ü'ÂîR¥×Ó~„:JUwî‰y‚hùcfÝÀ Fê<°k©“M2LûÍ‘i,ìZV:úåÂÖÎ[ñ̵–a_�€™EÇ_)DVÓÅLD°&È[i5G2úŸõ\½!D…�{–Õ4cÌ­Rö+–Â>{�‚q§¥ª–Ö "Q¸Ã1ÄS>!K™Lkø"³)›îu4YÎçF§Y‚œF/éJ ÈÕÊuŸàq »Ù™Ìq*L•†²!·Hû²%L>€ûÎÞ¶uŽáPy "¨·Ï5_Gsc­—)‚ï ÌÄž*"Qc®% g“dÖ¯s™v ¯ôŽ”¼êó2µnŸÜì–®Ì5p@´üÐ=÷Ä£€VËæ .ŽªsÎጎîH�M-¹�À‡;Œ=HDåÑ\Gsô 'r×É„ L¥¼o0zJ{LʈnZ{ÁO¥¦³…~ãî]x0zWц\Ûƒû ±9†Ï0 Ëjþ2æ^„­�žbÛFÙ§l䜸¨nnAM’Ý+Ê  GÐ…±„ÄæþxÌeR§ ?Þ67æ®eÜ»–ÖÂ|¾e�=¡:Öwè/—Ä{�ñd+E EÔ£sÉTKîT¬Ç,*¬~å+ ö–? K ƒ‹æSœäøbÀƒ¾ù”î¶ ñîÃUº×&¼8¾ò´½Ú¢ ØEì½Çè)¶ÍTihæîã¿V`Y–£\S…�ñ0+;½‰“0úgÌ*”õL€(nㇴ …s—Äg%“ˆ±/"ÃÌL—9-ð¸ÇÀ|‰4§è¨…ÙîJó3ïDǼ¢0È~ÕÄCÞ^†Ö€3 ‹/_˜¬ø�ñ{¬ÔA„•[/´Ð®`iño¤×ôYßóÈN+`íGåÀsf-‘ŒÊ°Î/ó6‡ m §ßV‘kÜËø–æiœÇ(£¬¨i®œ_†Y@1™Hò­é¸ùè>Ô¹ÍÜ3ºÉ+ H\ó>D®¬\;QŒpN×P¦=-v83™Ó̬+a´Ò¬Å¢?žxl¿1ë¸i.Hdr¢Ò&`PnÏ´ PèSìvTÄ,ãk ­HVM¦T$×ÕW­n»DÀ£ÌÍ=Ábš~',t¿o—jéWÏ9¶¹xnXØø%…/µÄ! nc*íl‚Z`ϧ쀪*mo3à©Ú1ø¸k«ÙÔ}Âw/—»4ßå/H·BŠx€G6¹{Šƒôju8˜ÛáàÔ£«t·(=«ËÄ &„¤æ=_"ʼW'd¨¦q#Ë�zŸxA/"KÆÌ¤Å°DáLqÔ ´n X5L ÷ JŸu(˜•Ó“PÎã­[É &mù‚¶ Ux—^¶Y©cØwÄ÷ÃøE6}ÈÀO»´Î G˜½<¿Kõ>�»îc´“œÌ¬?òp�œB‘ødYYÅÙô 7Eƒ ¿cè–OO4U²»�LgBå‰þ†ka Ôæý×3Ò\n:Dã+j|Kx“’!^¶M[4RÀh½W´EY;·ÌÉ!ys b|WR×@H>X“`-„½A* 5ž¬ÈæíÜ©¥V3ƒvìF)®^¦–çØFT¶@_W›îÚŠÜZJ&Ø#§l\Dõ©xæ]„T§ý±+älLX–EDKîYÇoÙ¸1Ú15Y‰5’ýY”ú6fÿx)…8 aþðUø„ÛQÁ NÆe~r2�µýóa|ñQI€8…X\À¿B8Œ€61}¬ìU]Îúœ¦# µÊU©s=ÑíxžAè�!¸'´¨v¢n¿º‘ß˦;h­Ó.—\Ú7Ãdß³rd_8^Ÿµ+¬ ç0ƒ%—Œû@†G$A­1óG%JíÓîR¬P.£�)gcÂ\iÔÎ*~žëԦʚÉSðÆSWlªò¸òUÆH!´�†~BZ=íÕ ¿zõ’åËô/ó063º�vÌ“ _áí=³Ìµ)ûQoƒï÷ò¹¼Æ·Ä"AÆ ã>`±aÉ÷„<¤R鿣1­–þÒó�2 ñvÝL+°ƒýKЯT uIÜÝwL@ÉVûHÅd\¯mã(8ò5ûÎÈü‘ô;]{ ‘ ¶Ó~j³ÊÄmU˜±�6ûÏz½½2ð¨"¶SÚYÓ¶WSŒ^¢—/*ˆ‘NÓ�Wè¶Ù]†.¿¬m›»ø[Ç™š? Hª¢jÈxJ¹>Â9ßbÿ©ì$PþcØ ×HñÒ<•;’Ë-ʧÍsüÊü±~ЧW³ˆŒÐxϙΟ¡ó%¾‰ÑA™eĬÄvn}ÄW„8±A³43*Pæ(M@™ÓI¸!bÿÆ",Žá†3>æ"hŽ¢¹=Ë/ 7a⫘é ù©ãÃiâ$�L ¯ÝZx©à&5äc Üžæog‡qÍ«TM3‡Ðõâ-Î!¯®ø•¿:•>3Ú½Å'oKR�d¶®á¢Ï2í§iÙä.ðܬ¿)´p.V3o#îk–ÐM—Ïp.ñ?§Ì¦³ïï6 ˜Œ¥ò—Ìо=S¯+öEqS“½ˆ¿ñ …ůijâŽ6R5Ä<áƒ™ŽˆÒ*ù€ pw6Ubr}ç`{œÂÛ‚Æg¢ˆZÖÛU‹ÏQQ0¼ â|y±‹|l«}=Acuè­øýØ ¯Ìßív oQ%zÝ}>�ôa¥Ã&JJãÞQ([&*dñº¬eì‚°PŸ‰dG •ßâ„À€ÉOºÁÎe¢ß™Ã>#õ² 8IFïU‚×&¥J@ûðt~ iQÚþ!¤%2ÄV3ˆN%›ºŠG<ÙíRÅ£¯{?ÞNpÎüÍ+«˜sÖÅçÁUšŒPžôL] Õb1rª£ªÜ ÇÎQAA=�]~7qÊ2|DnæN@ Î‹á¥â³íÓoFê3O’WÄk$c5•,ÔÂW¡zƒ‚ Y‰xß6T|rËNì ¡eLÞæ[ᾄZVkqÒJŠ“R�w´ð ´ÄcÖG¼5gÄ+²«cï©k †ÙT³Â¾ò�¥âàðüå0Æý�:£3*ÌÝKRÔÀv¸Ü¼Ùs°M¶™Kàß‚*(¢-Ú4„³˜²Þ JÃó*T®�$Sµêß¾,­Ë›J9cLJ™Z uÖ9ÄæÎÎb]¾™k“ÃÒ :˜‰¬‹H@v÷* È>ÿIãF\JKÜá<d0ç †\=æ~…–â<‘ùœˆ¨²>]®­•qA3 ¸G”D|lìýç?†ÏiH'Pï ´8 îÇj+šå—¦‘Xä–i�zñ[+^˜øŒ·ºYp“»s#,G1 ÕÔ÷ÂvÇ1¬•[Y–—Y×ó2—œ0˜ó8ÿæS¹¢=nÞ�Ù‰›H•¤b½�ï3*súyÎ2ÌÛÌYýÑ<Ê–£ò>T5•.�Ã"(.n>È”nVªY¥Bµu4­$¾ 3(UØ<1,!WÈ4Å ;^÷ °ÇcÈVU¡�@ö~à z þΡBÅã²ß)DÞT�Û�©x]ðNaPZzb¦Ö½´þ0� ýÜ,·® §7UPØÜ[ÁÌDÖÆ „tí0ÑKÎW™cÞ%Ùe¶!¬bPûE?ìæþfBÂü¢w¢p„^#×@ó¦�z c�F2J°åv)ræ¯é(Þ]Ò~ Ê� <›ÌÆ·Ü&œ˜Eñ1’Þ*P8Ú \: ÿa-›h`º €"’á…�©ù¨ø‡RäbZÂú}W3P^pG*˜.¥s5 œ#Ü#R¿,Íj±•“›š%iMúEd7ŠŒ)\òL‹ù©øa‚†8ýÜÃt·=0×ò‹÷‚Vw2—11Š„çSÁ8.ât¸ä¦YRÞs¨ uµóï.õÔ¢U2Ðî’÷\Ä&ß1]Tó¤ÑtzeÚ!ü3™Lñ*Vî±d«À.($ÝGó8™¤Íð…„Ãݨxy2J¥Ë¸ˆ>0ªoøAJþ Ìb¶îê¥kö†T¯'SUTÌòÌÅè˜7.2ªæ¿Ýb8FQž¦Q-·÷euœ¬½L> ¾a$]5^{ô:W¦8òA,‚12êQ.íñ <‘¡ó-é¾á÷˜Dü«Ú3gƒ_¼·‘ÙÏ£Bœ± ~]ÂØ35ÙsëgËV\�Eh[\!áÛãrøj›q2ZÕ»ÖÐ,•¯€À©Æã —=Œ"¾|UDu§LFýå,½Ó€ÝÝw4Âtc63‚+¡Á.¢�ûÈÓEöÓî: J^¾"a=·™ ø—We¯¸4ëï9f÷¥Ç BÕÁ�¢*¨2œ²š²Ê–Ž,å�Eì�ÈC'â4w ::= §ÀËúƒ�%=N\ÔÎyâFÈøxƒ3_rd÷NÖm´Ëb??á—çÜ~8ާMÝß¼XCÌ&¡åï\˜¤f44#bç¹Ð¿¼zªQ™ùEÃÕLúí9IпË(vÐ;Œ\ˉ§fò‚,¼ËßìË’lr&6w2uoÜÏK±x¼—ܧ]ðŒxï“úœÁg¥\Ê€UÉ¿3ìª'�ð–©¡91~9Ÿ„ºgéÄ^@EOô¼ÊEŽÕë33ª­2›ï9�áŒôëY˜9%…*µr‡=ÛQlvJŽí¿�z˜�…ŽøKäÔÆ"(ê\Q~9›c Ž Ê"Á¬Çņ¸Lpcà¸x‹…ÆÑöaÁC}¥UÌÀ´•[ñ5�wSZêŽîmtÄŒÆ3Ô”5­õpØê2ôê2+t‡:øÄÖ¢úî Y_ÄÂ[n¦F‰eÑŽ¦Ž;€4Q´¹D¾nß¿êm0#èØ�Ë9![Ýãí*Ü�£t÷Sa>n�˶׼S¿È:!ô%Îì`°߬DhâÖ?0 ý­¦P®8ÏG w+…�+ØüÅ{ÀÅjÈ 3RÅ%sx�ÐEl•M� ÌU�X ÌÁ¶ Ìd÷îY^NbgÄ�®XÖÝ•ñô0p‡^n.ÛÓ«•5{·�ìŠ4g„^SˆÑ@††jn½™#þx‚'UyNûˆU,]ìõèÊ*ä�jÓ!Ü¥ÑVË3¨�¥…Â7º‰Oùu8šzN.?+[d˜¡~ïyµÀÙí96õï¹Ï´ùˆ˜f&]¥7 Í.$–ü1®ø}.| ÌKBñXÀíà¥%*ÍÛ0\�?¼yІ%îoÉŒé jæ Pm¸¨¿3%ÖsðÀ*ýáOSÔ9»ìîX‡œîo»e8Ô:£“·ŽÈ>Ñ]î�Áº®IaC}L×óoÒ¢ ÓžgGEé˜W“æZæá˜ŒíNšÂ7l¸%°å™ÕjàûÀd³–*‹åqŽOƒs�½¸w`é‰[—F6s–.}^}Ø…‘qzGVŠe}©ßlDp¨¸³»j§6J2fY]x%J/ SäÑè"s½ÉNA:–BQ„œW÷#Öa<¦ÐaÍ\‚Ï- T®,yî1›wήc¥>À—˜o¦)‘¯¶`>üLˆ!,U.—€�!2¸wpelñ ËGLoUkÄZÒ­l®cc€UP‡ùßÒh×ù~=(B»P«\÷íbfÌw ÀeÔ Üã ¦ûW õ ‰žQ=oaÚû̳©×„W¾«š±¹à3™n7Œ‹PË›}j*çCÍâ2À}ˆs,— À¿©*“e2„*õ²bŽ{€šç‰Éæf[ º7Ÿ2ˆz,LõÂJ!–}€Îtø„ýÊ ٽÁé~:•¥„(ª Ðx¸z`¬2¦º9˜¬?d¦Òpaɸb¬^ `Ó,÷6ßUÇ@ü2¢Tám˜¿X5±#é¢G_ÏÙ‹M±_ŠVÇ$ÞjqyÊ;Yû*c aÛC‹‰ÏÇ\}žt�/ù/ò”¼ùó/¢X>ª'Ÿ¿Lÿr}ç0Ì ­mÎÏG$¥ä¯—G$¡Â²y§e°Y¯»™¢Ov´�özc¿Äy›{Ñï sÀÓq?ëB¯Ç¢–Ÿƒêá-wÀ~ù Û|µ‡¶ vm2ý2 cµt^ƒ£³ë };ñl»uÓÔ ”žeðqÄVºÎ{…4¨=mìu x?’]&år”·”LE·u¨V]/0A~6X<‡ütL¯qî!7UľÎ4Ào,§y£é•”þÏQdà«ï,6èTz"yš:”/„[dû~¦î0ÜqýÅ+î%›¹0>¦ûR§å÷ÃKLù�µ)¹µÁ�¯˜8Üm@y­1YÄ2Yá„ð¿h=³RSWË/?J®+Øþ§wâÕÊ´Æw4bÍø–¨6d½E½e j WÅ„t^ãŠö¸>þ¯ª\T!ÜvŸ�D.!0øÿe¯Í0BÞ56÷§¨EM ºN¡ýÄ1Õ`ÊÅ~h·9�QÁ9ªýãë™Î‰e³CrŒ¹‘{M‡n£n! ¢&ñSðÓR²µ§%YȪ¬Å¨‚½¦óo ݇B(ŸûRà›ÉCËOÎû!Û�–�dcõÃ#9«M]±<Õ¿1à…Æ4eSla�ß)¸ÀôÀy£•Ñ<ÃŽ¤Cü ­ŠlæaÞ´îŒ3 zR0…_K‹˜~. ¤á»ôz¾�®¦ëc Õ><~!·úMLâØ£{ ŠÚSírŸhvÆiV–Z¼‡2% ’ï¨Ïk¿Öó^¤B,mãû‡2åЭNY^ß™˜²öƒ,Ëmµu5*á�Ìä9šW½0¹p­ñgÆ)²nÔ~,ÏK—èO+²Œå):gñ703ûŸÒúKƒ8¶ž%™¼‡üË*ó+™¶ß�æfc[¸šÛ¡¸7oìL€žçs ûË MþÏVK�aTÉU¥Ü,Ró|!rÂÌ«(&”.¦DY9û%‡îåÿdxj[WC¾Î¥ýX8éÌeãÒþ‘Ö’ÕÁíÛ§q"ò³2wV�&îïGRÄ >Ó-âȃaÙÛÿŠŠØÚÿqa衹í>”d•ˆÿ�5(Á °lg—Ïy#‘¯LÊ@F(Њ¿e¬¸¹ü�ο†~¾f See Ýnbk†Žežá•s4ï“{]”÷`a|¥ÐWà çÄIj§mf^Bë÷Gè Ç^®Y²¡GQ)-åŽcu÷âà€©±�Žê‰«ÿ>€\_Í)`¬N}J‡Ðå× ‰‰¯D׉¥‹þ×0ÙEQ½„,Ûù™]BsGº,–Ü©NY/¸‚îÿÌ vjW¾‹ž�û¨c/CNa;_&Àþb_V5Äl0ÊÈûSÎN2«1÷‰�ߘs.�×sŒ -Ô^â¾"°: ®}çG³÷Ùüú\\Á6¼@>šo˜¢ ¾ûÁj®ýÊEç2ÎÊ¥‘QÜѾY·ˆOuæh÷+;EËèEæ"sèF;Ï{qk²°¬°��q¡Äê±/Œ¢´[1 ÅíÊc>7pt«?tKHhäb8Ó)7°à˜ÿâéÓÁþËàf‰�cÓ\«ÏÙ§Þ Q¹n (p'„ÒmûLk­ãü› k�ñíÍ}™¬o–QõÄýN6ú ¥…‚)T+=˵â­ÿäÂÍ«õG¹âñ2%ÿ�ÿp[5½å-¹¡µixè#„eÅ7-±Ì·åqÕfÛ K¥>øæ[HTÕã=Ùé¿Ü¦~L° Sú!€+è=oÐÖÑlÂ76;e7êðü¤ôAç‚;°·ÇR‚ƒµê-7®:‹Qàð”E¿þ>= ÑÙéqbËœBe8lw0:DãS.Ñ“÷ r¨ãDË߯·#BŒÅ(q²{@MñÉ/U1îìgl機žˆs ü¹‹²éâ7ÞÆù§kq#N#Ȃމqe\ÃÊ|1žåÆPb‹âQ6¡LðÄØAX^}ÍÃ&U.áƒ[§âa‹†‡4+”ÇÅÔÓ7:/S9•Âd¼ü;ù–YW½O[b.q¼²¼%^¦4Üľæ8 ±–ÞsÔ×7S‚M“Ë–l Ù¸6÷ܯycº9”ž äÔ¶£Ø˜Ÿ¸õ ~Ð/‹Ÿ�]NOx÷-„;䳓ÌP¶<Å**„¡U¿sSWDn„%@æ‰h•0âF¯‚QªLL…éö@·Z‰Xû“<]Ýf^Þ–a’uÎ"»‚ç•‘4‹—åAÉyšqPú\AÎsj+…îWòêeÿ1ÇŠÚ¼ø”ù`Ë:|‡p;i7‰ið"¯ò™'G\E¦¶&AEì{øâ-´XôŸdmùVZþ¼‘�P»•Í*Š"§Ïê" å:‚,ÌW¨F–Ï3e‹�M„™-WÏ0¶ˆÍ,n¿Ù‡åš€«\V¡ÀóïÄbÃÁ…¤¨õ…@©fÌï9ŒzpÀìMjû–œ21÷B.ª:+æ-KǘAlj›¢1‘íÑé“~IY=0ç©{XÄh70&îa<ãH˜Ê=LfŒ¸SMIWVYRL{cBÌ#ìí˜áÏ-Vª.°fÁAÛâ{)syáˆàeŽ5îVÝÁ9×Kwø¦qíÄb˜í\Y²óRÍ’Ç–Àv@8ê;¥6À³]LSû(–ÌÂópãQ­M'5¤cpÁ(ú€qÌ¡/Ä{ÓÇÓx 6©íz™`]ÊÉ9¸œæ²L’ßP…k[RöX£eb©:4‹ ß�ƒcÜêòWq…2°)(Bð<ÕÃé’‘¢U|FÀÕìàM„GŒ¬Ú Ut_æ]�Å#Wæiq•f¾eû­}‰žüJ}’×´õ5K)ÕÓ Š@�uΡ'•6awøîf…^/;¿R�–X(àò0R±‡#ÁªÕÞ—ÕÂÞá]ʾÙ�ÌPÇ™Y8#y0’_—Ÿ©YYªk2�/cد’¾Óbκ *`êe ÄV†‰V›x¥MJɈÀtÍ×r‡7 Äk„ ¯÷(Ú÷)–y†fKÎåMLäÏl½ ‚˜ùBÀínpcâMgĵº¼„ Å�ÿ,<ºüÎŽàpW^¥5 « q–_)ƒöfîb�‡o>cÒe‡35%1�óîb(¾58„Ü«ªÌq“÷ ,ÉÕ8=ËTQŒÖôK8›°L�qì�j$ÔqIæ\�6÷u°¼‡wm^¬)S=kw€Sé—¸Á±ó¹bäÀíÎàPÊ'e�Ñ åÑÔFk�NŸÆŽñIÊÒáó‡ä ¯^æÍ‚qñ{ö™Qµi}�>yƒ÷ùB÷»g|EÊ]ƒ Öˆ˜â]ÞÞîù>Øíê7ºÇ3ö‹ŒÜærÌV§†¡G¹Íê.<Àé•�ÔÎ Š4ÝÇS5™ÜÚ_-{‰Lå·¸Y$a„aÄ ý•8l¹ñkqi´Ê(-Ѱu3<¦e°dñ;ƒ&ää†>Ð,/ï/:À¦7ƒÃWºÍ_ƒW(®óøúÐçèT§3Õ Úëæg ‹SĦõ/Õ�ñè™)ÄhØÎ­võnÊ?ˆß×-½ùcµ LN+CDmðpÿ.&•ž#ZØUSџܺõ‹:¿wÌ!O•¬4¼â:¾éÄRõ~ ¡¡u'¸kòh9Ç©Kui^[ç}L#¯�™^¨•‡¦ø•qZV3фՉä<­¤ê5YÜó=ÌÙ‰m›eZöú•l76RJ"^ñ(Ó˜mÔ2LyÖâ´¥ ò‰j;Y¸£ØìÀó 7AÞ%ˆ OŠ)Ï8â,*­Qf\Ïd6ª|ê*"£¦a"�Å·ÎñÀ¨ŒVø�Ìi�)ñ÷.¢í+m÷_›ª?f^T7µwÄ"×/qìãØjº£ö†þ¤ºÐÌj¾b¤h½L¿u1~ô.½ÎHz«ÿØ=Öº³¹]çU?Á̹¨©ò‚b.Ärp†4B±MI%åÝLó.®q(5i*/ScdQ©/C à†Œ°o¤Ü—.›ü z×_¸8&€æG' q.W "îmø€çä.\½_X—ZqVï TÚ°¡‡gì¯ Ÿnc³U„ÃYfK²8.¥1ÂQ{•ðeT*÷·®¡YV áõe­V#ÎÛåêy¨wù @Ÿ™Qæèq{T” ­Í›k °ás39îYPÌ:`W¸1•…Qò�DC»B‡€áÂîæÅð^ƒÊdÂ…ã]E TáG¥�Ä–±»œW [¶,;¯0 ¨¾ö”Ti f=b�Pý›krúÌºÑ _ÓFq)ê=âû�‹åá-�iOw P�ªùEÙÃA•y⢼V,é;zŸ50iñ0­Ç`3S~G<ñú–CM£ÝÖˆ–áÜ)à“t±¶žþe4ZYp�æRh&ƒ~s… Àízn¡,¥l½~#$�–o…þ*dp¶Äe/¬š~ e| âgå¯Ôl/ó 0 Ñ™dQ5»–S™W¤À'¦.\>ÄeÁSes¯�GpÁK7†*±ËçÆ ªJ€ÉÆx•…‚ý1*Ù2Ö [À9ftRÿæ¡ÔýËŠdÿhÇñf“3!CÙzÌhôº, î¥�Ñwàß3P¶ ·ÌUëg:&PQ„Ӣh?™U–<&l7%‡ÜVNœ,. |ðܶ¬àzúˆ°¯¦&ÕiNq¨±ZÓïs£xÎ=úG¬`"Æ”#¯—>%Wu8%Aô)Zê^xÏ1ÃÇȦìÒy–¥A¬Øê]jÑç‚–úË™^ÝÌZêáT¥7~R©<| #?ÃñP«vš¥_¹u P•¼ï©TQä|ÓÔ ‡ òkÜHŠ–\s‡o˜:ͪ–ñžŸ•XE(ñ¼“UÅ£÷ Î*àRüµ­âj\JÃnÍÔŬÂЋz‚e{x‡šËÜÎrÏ.fW�\rùŠxM˜…Ô¹M²û�lÉW<Ì9üÊ5⫈a–:L‘ögQ´öÅUáQJÀØcå ù:†ß�g‡ícbTs¨©ÆI•÷nbªs83N*bñKg¢£{ar˜H[h˜u}’ÅÕVóë0HìG´òøô|ÞÈbv5¢¥´¥ïË4ƒUçØœj>óÝC6ó¦9¶üJÒ+ ª6I‹òȯ.mî»…À&>,ZBÜ‹.5Ø‹…înui¯í;p~'ƒÿ ·Cjœg^f& !�ñd¹ˆu7YUâ[ʱRþ—Í|s4ý1Diá"å—¿£(Ixb¶ñÜœ¾œ•Ä·ÊZ[64¿Ì`V®^œkS1fWQuÕäEÔ&l(�Ü–+ÕÇÀŠ7[Sñ@§M ÇüCl#AÃö”�«Vw3Sæ!uÏqRæ|Î6\dð¯˜ñÉ xuu(Ò=à |Äë”ÊáÝqp0-žWϨáZ±õ þzŠXE®5º…¶ÇCÇRÖäWG0± @WzZÐWòŽs§)~ãÌÃŰËqÛE#"á:« Ê1¾¼L.1ãN®V;L*æ4«ŽŸQ5v {™‡€ïûAÈW&®Pró :¸bJ4Þ¿¸lº‡ÒÜ´\ çèoD(ØåLå†>¦ÄÁ£m:aQ—n�L tôéÿV�N¡l\Ã�•~%[]Ib•˜XŸ ¹»ÝÁÓ®žËÊ)òòFÌ1¯|ˆ {”�ÂÝ ¦<Ìþàìè•|Ÿ‘üœSðuZ=·Ç¢Ģ6;‚9^q¹@q¸nµñZc08†¬–g3—sÐñ.ÃÉ�ñaËã‘^ž"’¹ÙUÆ|ÄÏ^›ê*Ƭ¿¹³ºq™¯‚^z /¤†Å0R“«5Ò™—Š©æL�æ'™U5·ä˜?’�Šte–0vq.†cg œî;d[:¸%Ô sDÑ›ž:ƒ˜`rï¦_î<‹ËüJ�|7+”»ù•> ø·`Ï;&s¹^xx†!s"qQ3ÝO…Ez–»cws•“âXŠƒ\*ct«qMÓ§×.¤ˆœ=Ä­åpùŸ‚!©Pš¸êãNµ1‡p-mê­z—®kAÔ"B‘,Lj©HQèÄʪ”UÅqsgy8òv�¯Ágv€ûÊ!›1q¥þ�>Φ 5dÛê*7‰þTÃ’eŠ& ‹—\êáîZ"Ñ@vôÀÈq7\1-£ÍÌOÉÄgµÖ`ñ$p‹¶™ó˜ÐAf¬,× rBãŽz&0U¿˜MFµâ¹�§yaÛá…E�‹ÿıÁ2iÌ!hk'瘳²6·P´‰ÍTÄÀڼͨb'4Ô²0«Í<Ã>>•î=–è£Áò뉖>b�˜ñÝ…‰ï¨Ç;܃gp˜µ>‰ÁüæbYêÝñS&ŒBC› 6ù– ©dSÍæ C�µ$«Ðþà ht×]ýåˆ$gUƒ=zerÊäÞ@f«™€_mß‹Ùîå/ÏG’ÍT•>#üDö%vW©U.nỪê f«–õ ·tæ¢E5Ñö’ÁAW&gz…!yQ½“Ì߯“h§ûæZh89ÿÈ={±ÉâbÝÛ9%úZ€_æ× ÇXò€³¢Ë_¤r´p¼ÅkJÓ[œm¬7� )Bc>y÷vó9ú³¯2¹;ÍN~žJD̾ÀÊÆ J•*ªTãy”µqµQ4•-ô¨£ >&Uù˜Xf²Ì7p©´Ä ~2ëâfpR߈°•YqŒÚoš®¥àí"‰r�z¾H®vV¥Óa…ðru®íLÕíê? rËlºk±cÀy÷ºŒrs091™ÕÊ™¡`º‡BÝbzz›°ò-z�¶ú—�¾Uû‹_pNsô+™åó‹Ž ¥ø„ÛÏ3(i†¢±6uê. ³† €ÂÇŽâ¹í–êasŽ=G‰FlóÛüL$k…ÛÍz—c)´°¬Dfcë‰VÔàþP™¡c¢€xìOy˜’ÕÑEz…<¬Wú”çTëõ.‰u€á~Òà¨cô&«r¸+a¤ëÇÚv†VÎë*=T6mr Á_îlÆb­TijŸ‰ž'+ ðù�” �½“Gž"¾!S’ýC'³à¡þà”º"w‰K][g ù•ô^·™pn ®Ðw`ð¤ê’[³¶– 7ãÌU`ÕpÇìCLËŠôà oÀ8…FñáµjP¡*E)¦; /îE|UñBøó+HÀÅÆVôªuâs,"K‘×8– ùa€n°³ üEžx€ÑiÓ¨Þí{1â;¢p/Ô´ýXƒ;ÔÅãÿ‹éÌ¢/îDV—NŒ¨™<URßÇÁÔnÛC´` G´t¦§(‹säæÄPÕ6y¸¬¬ñ 9xÀ²{~$%Í6BÊ©V®fBãkêWÌÑz]ŸiE ÷Ž¢°W‘î�ž"8y=rOúPœ2÷¸ê+œâ5ÞqÉì–N×$§€–P{cÐeY¬ø„ÕÒâ€8æW];Ÿ#Û1‘K£R¤ÜûM“ĵ5ˆ+W$·@®%Ú�tr“š,¿¸£Clb#I?SшPÑrñ™“üË3pÆÇ;ú,KÝ.�²¾ÎÂ|Ü?çl#‘]^‰VÌ 9kQÙj�‹¬L¯)'© `fڭʺŒ(t%æmúÛˆZÅ�Ô{i¦':;üÁPKs]<æ5Ïe¨Mœ"bSÕó#U6ÑY•¶9D¼1Kqî_��P8êX²† þ:…c€&Ááøð©XÔjÇ%zŒöS^Díí0é1:¯³ÏRþ¼_°k}N ŽQ±ýÙµ”2´âÑ~1÷�“Å›ùÿ²Ñ�†g¦NÚ8 ã1"Ë,½—8=T%Þ*:ÏØáÄ®ž%�àѾ™ä¤Yj4[“óÔªû1ˆ`›xè—é’—Ìá"P«�q‡IšNîŸ?hnÒYp´`à†x—Äýý�W¼µ1¤ 3CsìôÊr§p6N•“º�Kä•�Äj0zX_‡ÄyyNó.ÿ\Á¸…â2‰p´l™;g‚8³hgñK¦TkÇ$³>fh58?H±¢X8z�Xö˜G¡Šó�2ö–ÈçÔF– C,Âh5¨ZµÀ?¥n#(ðó5ÏíÈüó x¼2 ôŠò „,%Èö{ ÿQé]™hš–̵‘0ж#¦ÎMå®ðÜ1öàÿ÷ ‚?êX†ÉÀ¦+¹OœGW�çP¥µSa¥J¶%Fá)´-YŽ´±�*¬!Жm{�Ð(ãìšÖ¡$“L)°¹•J;Š] ì5̺Ug_A:úƒW,ÈcYU¢»µ~§[€�D †Xà ɖµcÍ/]f#"AG²1 @m|™1\F–(t^¢Ç5�õp�1óU AjV¹ÿà­(ŽBœ�JèçÔÌ*–Ò¯Ðõ±/úöÐnò–>y¾<¿´XS;�Rê8éÁ%6ǘ-²_~†vÄ "hǯqºïùXêʈÚk»™5­¥cÁæ7¦£˜·õ ”Ý9\Ô†~�Ã¥oË;a‡ʼ # ŒJ'p‹ìR¯ú›CšÁ2–'(¿=|•�:Oɼ&üT~‡^&'…ÍQŸr›&7�̵‚ûO0m#ƒ ü3J(ùb.Vªæ»Ê’ˆ™vÕ3x)P^e±UVé½ Fg”.ªó4ȇÕº=j¥ñS±pZŠ(9·oƒîã�d£-ÁßÓ.¦¢á¸˜=* %:Ï(Ïêš¹²2÷7= aqNefÕ ÂP=Cžÿsƒ(Ê+a_3'nÉRêêS‡çåÎ%�,7Úßæ�ò<-ž§PB9…~y†Žº ,˜ø®s) ÓÂ8ÆãþvîvÇí-aÖG°öLåiTñ�RýÏiN”3®%aÒƒ'7/n€îgÉ<3íx&V2nz%b»"üJC—öÞ¸%å Š‘‰óÈ#X¨È©Ž[Fá󿯇‰CuFË_Lj`® ®¡P­C.5x%:òùõ‰Ùúƒ–ù<Ä¡}4·œ!u¡Ðù8•ümuríìk‡ªWô#No‡âfŒÜêgBŸÇ殽´ËDö6Ë4N@Æ”ËS€%Œ¦žc)kŒ´—2^JÌ#]2„p kÔᄾ;ÌV»Ì¬Z­K².¡¥1¨œöoÁˆŸ–kV¼ø'³¥†„ •'¡€¯’\ Ó0 ÞXÀX�yƒÀŒ¿¥kªÍnZ�O‘U—hwÊ3\øêvqO$j̲RyçlAÈ•&ŽÜ‡1p­üЂ�²áëÖÆ¯‰.«†Aáϸr…°¾CÀÜÅ“ Ñæ�ÄL«G–Zo‰ÈDG>?q Á®vžæ>“Xµ*¯S”9¥™‚¡ÃØ'á˜tÙ9+Ük¹æÙ›’ ¯3±‚-·7#t)dÆÒ,UWâ] º:bÅËm}L Ì´å¯Hª¹ìBõP@Ô¢¼Föqx¨ïJñ…ÛùŽ8¨aE«^YBMóá«Ä~º…Ê´!«Ì]å 3Ë“Ð@á ÍW¤Ò¦SLš �Ã` –ãÀŽ_ì�ÄÀÅîýÐ0íÔ¦á ¾æ6ȺÙ*‹õpÅDL פçz½¦Ž²›NŠÀÍBâ=@ƒL–òc÷ãv™¿ùО-â!xç0¯ø†{¢»ióÄÌf\eo?©tˆÐÁI¦”oÃ2O¶Œ�::Ù»·zŽRðè?2¶¦÷xy)ø‚’àýBEc:�ºÀiÕûÌ1i}×B�u"ÜEC¼ËæPV1ÐP: œñ[÷cbàÅj¡0o¼ðÝUë˜ãAèn3‡h߃iÁf._IÝG̸¦»äýJìÄt½¤¤É.šzf±sà§M 6‡&~ðQ‡b�!,,[#]Ì_qx�º–Œ J =«+芬v§„ó; ª°ëǃzY–±:¿‰hw“ûa^Ú­ýc§œq-Dêày@ämKq|ìf:ÞJÃÔɉì)÷‡Õ,eýGœœò:…&ŽsŒ#lUTcˆ L,z´Ç‹hç"è~`õŠdÌKé— Y™‡ß©ŸdŽA ¼KðŽ·7™s-C€EH/w‹´à(z™5}y¹Aàõ-fd¼,oÜ!’­Ö@4ÄÑ"ƒIáæRü#h«¢[Eùç‡Kµcs5ò?„jJ©ÛÁƒ&“æ†&yÚܧ¸Q—*‰RKaëÔ.i¡s�‘†ç¢æST:ÃOžÈ‘ä±ÿæ¡\ËßgxNüMª†14v§â-™ö„TGR±�ööüÇߟüÄÜŸî"™žn}ªG:„6&gxeAÍôü¤1@ØÅû¹˜_�*ñ×ðLŠÃÔÇë ó ·i?3[)9騮"½€ÿË-D窲s¿±>v;ƒ@ŸÌѲgX\3zq=/¦Y*¼$ÔÎkPEw‹–Æ�Êó¼²ÎúÜšõ©’.o¡‹®ÈÚÞf–k„÷&rà˜©ëùÀJÜh £÷²¬¸©ŒZ®ƒŒb2‹…\hßS‚Ï?º4Çå0¤ì!�”8ê]ŸsM" ¨óÜ&+¶,¶¨ízJ Ô1QA’ÇSŠV%K–Nayáëèó}/3™�¥C—pp�öÖfÇ`iÙ[î&1O[øŽ0\ª£+ñUÀïŒ~‰-FµLr­¦¼¥+n7mY¯ˆy°”.5 êGò¾ãOº~ÑZ_ÁÂd2âæ<©A{‘1•ÝvB¼'>#“·p7ÚýÌÚqŒìÊüËïº`xOɘˆŽ[­Øk@É@uòF„‚“nù”E5û…Czñ3·ÜÚ×ðܧL ÿ³n÷í-G⣻^߃0Kû¼·‡¡55Âï‰H�aJ,/Ä_‚¯‚,¥ƒ~pé3p}2™SÞ~ã<�//�…-0w[sÍÌd­†,"Ô•/Ò8i2ôíŽkLM ˆÖ¥F�ræè޵.ž~…¼J™¥{�N‚ñ)| @‰f]åµ ”cƒPŒ&ú®®\8ARz¸;fºÚ�qü&]â)»Ò²§ žË»> €‹Óâ%šÿ·oÜu,0¢–�ð„@ô\ äY”[*õRôɆXÅVg¥!w2Š¿tmÖ]Ñä¾£gí ó£ÄÇ\ ¾k˜®…S’ìr…WÊú�\}™Ô«±èY˜þâ9FÎA­5pQÔ¬âÈFÎBWÀ™Œó ¾;)1ö|K‡»Û\Ìg™â(±c Ëó–—En7O¦ø¿I¯} ¦¼D-IL\m`ÌÎ"ê�3?勦|AË6¢˜=~>`8`ÔI/lÏX§üvŽiaƒqaÉæ>K™²|K®tRn.[³‚॥uÀ‚ô®Š`«øÕ—ª¾¡W$Õ¬m:Yß ßœµñ‰âŒŸv™½'ITý·,æÂî¦Í’¦>àÓÄ#Ú®¡[ËÉŒà4»éìñ¼ µ qøD­©JlÉ&¸T¶‚�3„'´ÑÙÏ0.WÔÒo̳šf°“ *»![uôÂÇÁÅÀBÙ.²ý¥èEÂã&y–”<Ðö1�•‚õ˜ª°B ¼ÌãgU*(¿r¹L;âUØ®!=Ç•6�À=§öµ> qP Þ¬�>ÙS½V½P‘ ¨U>uàYZ„„ÀZ¡ ü̃[$Ì}™0˜1Kóë#-îzm"J¶…mùÔHìѬÃ@ÒHðú´`i‰ *e;"ñrá[j“ oÑ¿-sG„cY ÐŽ@wñ\]†›ÏSòÂ^óJ)2Lí|^â90õíi01i¡Õáý&‘î]W4ç(½âŠè‹/èmù‚mA¿‹ÍG zLzâó2–½é55ù}åRú<¹2i¾�ÔW‰Ù²��KøZ|LC#Wu/Fž¦¨ k2§®+÷•G�™¦ 91¥«+(ýYox4|טT´nßçäUš1Fœ8JÀ Uœì0Þ ‰­¶¡³¦fQ6 ‘K«ï,¥Òa:ŽžéäCÃé爗>ÌIBµá–%̓éur˜U¤Üx  *5uGÞÒ`â9iWÌ•ÎþV‹°Va…�™FÜIÅK+o‰Æ°Û¦TÙ}A® �¼Û²…é÷ £º·÷7so¹hIð°$S*�ÿQ4§ú‚Q�8ûjWàƒûOŠ&^Ø›A=¿(^×ÀFåU©q`€ J÷§‚U<îþÒ+¸(hоQKA©—9T•¢ç,XÐ…ós97,‡½ÄóepÒ±,䔜û•�<¹ˆ|‘ðlG^¥Ïx£ _§Ž{á”ÁaÛRúþyLÚvÔ«@XZ†ÈDÕaÝAT�††�Á9qeTÅ#faÄu,Mý|P$AÂ׊•¶¸ˆ; Ф$` ¬þ# «ºÄL£õ1§ðlEËMa�.²âåÐÍÑ‚Z EzKU¥÷˜oÔs¸Ïžc¹¶>H$ñÃ.C¿9feP´õÃX@Ì„÷e_B¶ÏܪWÚ¹ê¢üÊ9²ÏøFSA(LWJ á_m� 6÷ˆ‡ éDüGdà£^"-£x`:pYv±œsö�=£lËj|-ÂÂoP…žˆ°�ñK2Î+§Á,.;TñÁ€�!«FÍËDÛÓ q,Üd¯Ý Û)­•65¨¬%M1@ÜšÁj»âëÞ)—aJ5›#.“¥É¿©D…Cór-À¼�º¡àÿžþ#¤Fm�ñSv2L¬z™î§á‘˜à'r½>˜gFF£:¸§Ã/E¦oõ ×âAçðˆEm(¼Â|H�ö ûFyI‰­·®áé~†Ñ^�X˜;Axs7ñUº3º³‹«…“Id]¿‰è0 }剣̃U3c�†ba Ú¼õ6PpLòµ½Ô Œ5¸†Ÿ±jÏ� ,Øý8JDM'?1¨n½BJ4?�Ù32}šÄÖFGƒN׈ÔÕѤðæ=d¨m²S\J\@åñ<åË„Ì¯ç °ê¥ òÊìˆBãa^ÅKßs4ÍWcÿ:‹’ç(+B™sx}2ÁÀ³IA#•Š’«æ {s‹T³´º bÈLUÖ6.‘€ÃG”G»4pJÕîF˜–U Eî+H8ó„½7²Š-*h_Ê2M̈씔Ón'úžzˆãûF¬4ôDsÖ³øJȲŒvLòÔÊÙ.á 8 uPM”¯L!¾Fz™g2…̶Ås:ø “}…þ£bÖ?\ÿb�û¯�"¦Eq¢°yŠWü"³Ò�±Š[«e•«ßó,k‘ÿ¹K&ÖÖ‰(ÎÛ$±V …§L½5FWï:êcÙöÇÊEÙ@f„Ì!ûH¬Ä>]\ºé¥Ûæ%?g%ÞåÙQ½ªÌ`¸Š~aÀ˜Ó‘îX—£I䊡·s-Ì`¤ð¨åbÒ€ q­[mJ#¬Nb]5¢ŽÅ�CHô2ôE­X­/7™vSÇÏx.üB@‚·Jù–æwPüñ "ºÉ¢%Q©�îsÍòºXLŠë ×¹ŒâÞIz´3^f+/™�ä–¨5+Ä´íˆÀB¯� Ü#¦¥è•Ž‹jsùަ¯œàÉ0¸Sa«¸Em//Ù �‘¶ˆëåÂí-¾4•y€œFW_™1@ÚQ«ðB3,ÚÿGÄJ°è¼zu)@ð`qNgd¦]ðc…] pîìÊ <²—Nù†'Š€Þ‰�@²Óáš>è6#¿é±`åâܘZ¾UËÚ\ uÁþuJ.="ÒÕ6þ:�Ë úù€åC«Ÿ£/ ÏZ w!OŒÅ]“'§Ô@èâáò+«Ã˜’ ‚ pq(£}ì4¨Æ�æ5$*ÇQc¡Ìù4À¹‡þcoŠ/.!Åÿ$²ˆ¡ÕÊ‹(Êü¥©@+PdTVò¼tû˘5ˆ‡õ0¢÷øh«šìsX6MªbE-¹ex,±k’,¯““2¦ÿ0a¬�ÁHGcÔ|íú¦#ÂPù˜Ô2jq7H¬õ+K«¦§Ts7U¤àrÁåÝy˜îZýlgU¿‰¹‡FGŒÅlS�‰v˜VÔ¶ët{ª:³Õ±ó){°Ðš- ¯Ñ Cãü0jkZú‡„^ž«1”èM�s¦¥,À�ƒxc›@€Ø&dÇ,�ñ” wx¨m ²ô%…à"¦=a»ä¢˜ô à)j\�ìôq}B(±�g=.4³„N5KáÙ¹A/q4�i.Žœ°ELN(¿¤Bt—ùD›‚aºæCÜq™J»Ç›…쪯©r€)c0}²›¡ÕÃ;Å’o1Sº¼Kóíáfê÷Y, ЉnÎur£S5€6AÙM§}KÏ¢w‰Û†T0cĸ} hšr¾ÔX`á¬ýJ�€ »`STmÞŸùŠÐ6PkxšKÏU†\ÇûíÓâ? p‰�öˆhÓ�˜êT!ËgÆ#Ç–GÏò^Qß«“Wl¹CÅJç×–õMÁ˜äõˆ(ò�=|D³að”1é¹feÏ›×’žŒ×–J|ÛÁ³l^L_6w”š’¼Y5®S0,”KJD À§~fÚ «b¼þÑ„fò?0 ÑÇ߉^qZd†0’ Ë`W�1s«×ýpEFoï0\ˆNy¸54ViéÜÉŒ¹bò]ÃBgNïÂ~À�n7Äwb¶ååß2Üxw=?hÒ¯XøF0ÝõÅ×*y…¶Ð8÷ Z�Š€0Ù˜»¸|î~R»°þlÓçz_ÑA7™w\N¥¡@®«1žµ¾•å…HÛY«^ö­ÆmLj–Š9²æŽ¥H¢-T´íXŸaƒExAësTö(=Fáûl¨ù€zŠ‚â8‰’ûs¬Ì¥¹P?ìm=êè'£%;˜“ËRËú÷öÜ&®Ÿ6 x«­pna@úƒË (û?‰�`ù¯3Yç“ä%£—Årq.‰5ɾ`‡­º„)�ZêUÛ=pHÎÓª¹ŽË Lv.ðë9‡dK¦Ã,ûÅlºñ´Xxe6D,ÀbpÒÍÚK’D'¨ÛŽˆvû€�ª€åùîu€:^fY›v#æå]œ¥ÀÑ:˜Z,? gÃ>ÅÊ» Eã5ž2ôqˆ r„+1l¯ònd *í.rðÜÅäüÊ,ÜŽ2ú_¾¡Åa(©h!åqsRÕGc²/´¨Exþ&¸‘°ÆoÌ lÌ=°­½äX ‹èškâÑ™ åÍF›‚»1̾”à+«…MµßöW0TxLJ &Ñ‘ªuíÖdI�49:›ÀZ64²é$å›Á Ã±Ž©%±ZðêÜFUé½0zKû¥�ù?RÌÝtög2Ü”Ø#‡ÄªÇL¸vóOÕ)A³FÉ­‹ [ýÄÝ�y†¦ÁM÷!Ü  2pAr6Ðì™ÅÐåûøùŠCl¼ _zàÌù±Ó§%":Ò4_¦%¬3Ö&õæÜMÀ3‹ÔÇ]…ù !Ø8f‚®¯´œ>—B‚ðpbB6„8�ÌY<1Ï;[KDÎÕÍ7}âUËÕt€BŒ…>Ÿuv~n!€"ÖpM1GàŽ¢åÇèî>ߨš+·0fù‚î÷§¯Ä({ €ñl\Ê�©ß¼É¢ú…`Êy¾RŽ ,W2ê¤R­4»\‘ùŠ×~Ùv´ëO±(09á‚4à™`Ãõq·¤ÊË-ž ×3�–ç=F ìê?2„ÁǼb¥îCâθa¿]² ùc×úƒ«‘ ¨ Ÿ'Ê!µ¢s˜ËÛÊoâoƇòÊ–S{ÛÄ%oÀZ+Ùñºg¹ÒpÅÁñ§S{„þq€_–ë3Ì+-̬&è-ìAñ.«1x#%ú2‹å8õ7*ñ?á8úVí¨è—ÚÁœ¹�¦Ýv\Ó ®ž?0ñ]:)ŸÌBÎDl œ$MIȃ•y|¥E§d ”ËrÍ^®0m¨ßkÛæPçÕ"QîoÌWˆ±á& 䆠øÇ46º²%{“µ1ó+’ªºânWU¦ÖbTo8ÂÎW11ÙåÒºƒëìfÅéÛt‡=ñ¹OIJU‘èD €KŸcüBÓ£tܨ!‡¾â¶ª_«íkð5…âq,V­†�˜˜>3û!CÍTüKË?ië=:ަ:ˆ³•ßÁª�çwù„{ö혞Ž.¡¿Ô¬dû”R“—UÿÉÏ<$¾´,+_Šu/ ˜9þª¢V"2ŸDAž¦ìÁD ÿ’&ÕŒ:³¤]�/_E<öׂQ»U苉™f¦ê8_û>a€ù™>Щ;ÔR †<ÁgÙyY«ïs …X¥éñq¥-îx ¢Ý¿ˆº÷µŠè•O1î5ßÛƒ­1"*OŒÿ ˜(rq²b�°´=Î@XKÞµ[Ä£xaǧËi˜Äòö¡3ýüÊ�ˈ;;ôæ5oOâ$hžH¢�AÁå8òœ;5ÏôtD Ê ¸7ô9‡ôëÄK„áes ~O¡Ìq?ûåUFq¨íÉ�Nbõ_ÊWõ0¨ •ÄÆ»—ÖÁ©kéÚõ7ue]Vìþ<ÂÃnõáó0&>Ö\x-my\î(¯$py–8V£(¡¼Cå ‹±ø þ¢ÿŽx��`¼‰SsNýœ¾ãésb\áÿ�O‰D£bn] …8IDeéÃòS Ù³Ó°`çú%x‹ˆpÌÏ_òÁ+Æ-Ž&—)ÁôúuîJ¼gC)¸ËÎú|x�†jè�û�ú15ÍS +¹� «Ã™P­4À«†^j6å¬gÑí÷€QÐÃvÆÿ™kBñç�°¿¼zûb9Vfk؈­%¨³KÁºœ�@eìý«$Å·ýe³<×›˜†ç%“÷A' k¥9;%§/ža,ewügaÑqÜ[Åj"¾ §17AÁ¿¦Rë`¼ÄMøƒ˜¡§KÏ0—梴rRï uøŽ>ÓÓ\Ÿ$:MñËêšã/´žýíP‡8Í)½7G.ü%_šâ2ˆs4ѬL½ÔE(Võxþb3+©çp„4O¢pÏì>ßFOÄJB6ø^ÆŸ¿3~¥˜›&¹Û)œmûÉŒºd�/€íœ»³¯ÛÏü–Y¬€~Ì«¹}�ÂŽœ†‚3/‚î—Óß„ÞÕã€ø`·p LሢX¬c¢ x+Ÿ0ú…»ªû[G9n&w}^Ê. T®p”÷úñú˜>ç!íÌKCÅœ¾ÐµbíúEZ=Uþ&Èâ¿&% K—·÷Öëá~¶ÃíSüœœ*jÓNæjÈ ˆ|ÞÀÎ/«Åù‰uð^—ÌäüE(aa}aR—²*¶>y” ZÏhŤ à%äꈕøÉkb‡ÇSÜ£f%ô†D-"8ƒ Î1¥‡ñ¿nÓC -™OÄŽ'�P@ª ã~X…/…ßÓñ.òôãíê9_xÙ‚¸:y–öê_g�ÛOîP2º®ßˆþYˆêæR]Ã@Óäh|½N Öx§„ÔLåtøu2²Ÿrä™5š} }¥Ô§Ç��S�[¼*~È…øeóÔÃsSEx…Ïg¸(Uð[6Ì`RáéhÌó#Zn¥šüTÀ3§û=Î<Úòî°vBÉ ¼Ÿñ)'q´Õ ¾©›ôN»ƒ“«…5^®ËµÛ)kûÌT»úrBjš�½yEöù‹¯ù9À¥6ßÇîÁò3dévA¶ÁA¯XÉdEŠôÔOHŒ«Â¾ñYœ‚[¼û‹¬Ïû�öb`ŒÞ:…îóng±-À—iO‰Tw…Ie÷„Zy6̨Â<¨6|ê[¯7Úº÷2-&÷y‚>…ù2ÞZR—kÁûmVJ~£7î #wˆ›�gÏ\³îß°h•.«cYdçH™ø}‘7˜_žUåEºäs@G» öF¸[2¡œJèÝâ‹îHBÖåÙ ;?‰O©+Ào¾c$uO76ØÄ6ÆQÙ~!ô!² Ìä™�ÿù%nmå�V@²ïÑi—þ—!ƒOÊçöL1 épt·<Ìü�¯˜P΢Nq(o–f¢L1Ÿ¥ä›ðÉÿÈyæ: ‡uW7`<<Ú••í*=™�D£|D€=«ºÿ@ù~�ÂoK¥„>‰»ž Ì8ÃQ�¸ŽÙà32%Íþ‚g)X{Kê-ÀzN( ?’R1•OÙÇÆ&¬Z~ÃŒèî fúÙ3Ð^Y†Ê7Ýú SYùê|Gg”FFo82= |§¸)¶Æ·ýMÖäÎUõêuÃvq2áRã׌Ãa8C³«Àd¿ Yî,VtPÁãטˆÂ<�þ81¯Þ=ÁŸsóÜ``ÉË"¡, ~2pdz×Dà|>'�‹žeúÂϱþ¿Â…8à›Á3ÇÐ�îiæù�\m`xƒ™^ÑÑǶs–c—»–ce³£_U%_„B®‹NܤCÀ: ·Ã�ø‡ A�óPµáÛOš·ÔÅJ‚~�›‰r£W3C¥* ã f?b­7ÒÜFu™«‹å6ÂßPpÀ�òSý.VæÌ`/e·Š‚ÕÈZ èÖ»‰4—9ryø†�*ôª)û¨²Ç‚Y¿¢ç3p•/×?ó+°Ü/æ¢*VnŒ>a„j¯]¾£w0Süw6[®Ýg*ËÐP é?+e§²$ä|3ŽŸ|ƒ=Çcy—™‰W¨`ƒôc¤ýøsúÊ ®sÜ+*� Id›…Ö]Í °«^&Œ„-.Çåõu½XQõ˜öCEóÜÅ”ÏÈ ¢¡xH¯Ku²X£dÀ1ý£©@®´90lÓƒ�fýÊl½yè>©(Yó8Ä<Î&sÄ<÷Ä®‘Ýb•Ömkš ‘€CwïÄÙ:ªÛz€Næ<öaKüv`Ú÷æ^öz!K@˘pu\ÁD܃‰ÂÙK®Ô;ˆHW‚±†¾>ŒÖ¦™dÀ^Yh¿?K‡¿b’å­'/þJ~e®“J~~%†éƒ¦0<6ÛŠ9œâK Ù Ngƒ>y˜CŸ_´*QÍh&<ø8'dƒëƒÌÌ„µÃ_Tá¯1CRÖÚôM­þg$iž~‚²@m¶Beäúr>Ó™±‚ŒLô—æ=¥Xt—ѯZ”)¶¦cÿÄ8†X»»8sî8[GùpWx7?…"˜(®! yœJÄçS*­KB5Ë<µ›ô’UÊ2å]L@‰Z�¥7÷”ØvTß73᯽�™q-¿¡º›´<¹˜�f¨�ò7YIJôÚ€âŒÎlAY¹ž5Ãñ./¡�?]ôçü)ö”%¥­e³¯»@ ¡hÞ#ASÐŽ`׳̪êÕZ©¹i‘Lr©¨äy�CÞ§î¼ìûG'ÒªZá‚D^¸â*éP*ðÞ 7y–¸CcüCGtó?àæZXˆ)Úû•G[ÀË0kC¡ŒCrHûÉ`—Ÿ™zÄ¡àB°¢ß*?)qÞ¹„(²(H0«.PÏè›y—*Y’73=ÌJcÌdÞ Ûö—P=µJ2#ßr¨d³òpÍHÎx Ð81¼ºµ`Ö†qÇǸ֎¡éd¯ºÄkvpêudÈm&£áV ˜>î6up*8•Ô§?@öTZhÊûÀîP”Ò}æZîf®+¢÷R‘¯ºšß0ô"­ê‚ñU/~nÞ—õ+®‰•Äg•è¼Ê°Y29]ûˆµËë¶ÜËe¨V9z€0ÄZÄÑIÛsÁºÉ«øgl¼¸C]`þàK@·–#“¹¦]察‰rçÝÚ¨^uwY:ÙJ< A2{wÚ'‚…iÍ2ŒÚ‡ýŠ~%D þìÞâ³Ï™¹é˜˜�-ž(…îâJ¬p÷T|E8ß°KüH9B9=ñU¢)©Âߎ"§ùBWRÕÞO›×¹…¶IU|2ÂÏ’\£þæd8&�œyª€Šª/*—÷I\ÇÜPúŸTŽP!ÇëÞ¼P§àW1�z‘òeÏÇÄßÐolÕ´6¾,Â|³NhÛùŒµ œØG¹r¼›?ìÖ$ÓôÇÒ¥yŠs¬AG¹Xϵk 9l‰0ªý{Žû‘9´òò÷ê6Û€·äï'pà ~˜©̳ò=Ôƒl+¤þåªÓVòµ¨©2 ß¾â(‡gŽ=Ì¥Íë•‹wS„Þ@éÝÜ;ÔÞu %ÆQÌ—{:b·‰iƒéf 0Ù›`€�A쪼ÁCÂ@Z²‰SÉÊgÀêö¹,`ߦ^Ø-‚‘ïMÊé�U¦̦¡kÔ_äËÚ¹¨`hñG™™í´·xášîûÄæÞ'àJ'2ñ™pÌ>�Óªg• ¹Ý¥ÑpÞÞþ%r aÛ©ËÞuò™�̾èàÀ 䬯ÓGVyçËÔ[Q£Wåñ/So øÖ¸3Ïë‡%‘9úbYÒ=ÄüX˜ÛŒóô Êè…"vÁ!0e@4e …M5gqN1 q7[uRÌÓŽân^‡¸>`¶ù„k¯"å×ÇѼ?Œw#üÍ0ý翢߬ ;Ƙl]ú›w ¹@a-Ô>ô˜ÍLÆJgäë¨`Œ;y@*Õ9„*—}ÄFh¶«'5J¯šf�Ôwõ…Îf¿^bGl··Þ`oå?'¹æbÆÅLÜ[›såØû`·8þRáN9`¬-¦iËܪq }à0/óÜÿ>ðAkÿ|ĉ�ªÏÿÄ&!1AQaq�‘¡±ÁÑáðñÿÚ?/XréËã9#o¼}‚˜-Nof9"�ºC¶ôo+h¦¸ø0™¥*`��7çÇ;�+ró¢ÊD')– ˆwØL©<܇j¼-nŠ" Ès r(F»v|oãÎl :ƒÎPÁÑ�Ž„Þ)]ueþe,.ýžñ(� M¯Ùš‹ÈrôßcbMÔ šTºòç‚Ë1ÑyV3\á(”ÀP„ †ÛÀœ²§¤l@ Þª[3‘›,d¬Ük€¢�>05N É£Æ ŽÍÃÄË �Æ1…Ô¶b_�2ÒžS¼;AbßîNâē߼W„îy“Šü;LT0lRLJHïŽîNS®±À~¯9ªiÒ^1H"¾'÷"ÁV¯ñ”Àô¼b›ÍbÔM¸ŽÛç‡l·ËƒhQáÉU(Íe¢ß…6}à… ™×œ8”7Îižñ�Bž;¸Rù6ˆK£‚þx„x½¹Þ²êeNå<âXŸ`RÄHoM- -[¾&ýbÑœÀÃ2<ÌÙ»k2à{„û÷—�›jŽQwó‰7a¨àöG†b- ¼yÍq޶ŦÒ}É%ÅÑ1PÑÒä§�`�Sî@w³dË´Xé~½çC‚éöÝ0‰Ýó`Nn©ãç¬×�vÁ«î0²È"§}.‹¬n)ÖˆhG´ãhòªÛ±oç$D’ï@èä;’|â]ÆX8„|˜÷˜ !w ;äÖHË�™0|Â[/XÁZ¤OX ͽø÷¼1Y]¦¾˜µ/Ù�È,÷¬Õµ^ \Ï{Ê¡}–ï䛜1÷zÃmvÜhˆÑ¸÷Š W¯îÓFó/ÖA“ƒ*pÄ:p/;Þ8Î!/múÄ ¸8’I£6è»ïŒ¨4=ëƒ4J9}Oó ŸŒd�&… â¥(<«t9stì€ 7R0¿Ë…ˆ> Õ<¶ïÆ>Ac-uA²ž;ʦ�ϳS6�Iwž{ñ¼óˆåqÅ¿X²=¢1yÕ¸ÖqïºÒйB|âMë8W•™T>¶dÕt‹Ý;p®½Ú1ìâh ùÅ"Òí¾þrBXÙ:êfüÀFKMëÇy»,m" #ç$9ñØõ8æ-•¼†ôcõØIÂIÊ(fh¡´©|ƒ ¶ÂÛhm±¬ÞZ,íçÛIÛƒJ­›=ÝÇœcK ÔŽ }pcæ0ë��¡8†ëpŽsUòkÜÄlè2[u¦®ïFU.#9)§ãÃX´|iþá,´š@ŸÎjå!åÇhþàĤi ·�βH)¬‰•X§f¯mxž-±©ü‹ó�‹Íˆ©Æàvi•ñЬÀôùtQÕ Íí$<A_…ï$W "7Zƒ06© ¡Ú*¥mìitM´¢ ïRˆhÜ«Êm{w‚/3î˜@¡ìÈãSCÑ@›ÁÃÉH÷ïؤœûÅÒØà7V¸†€_5µ/MÖD>{|el¼½0ç ºñŒà{úÀ¢ó„¨Ž_å�‚§n½k¼¡­ßM`H”ZQ¢yãïÕF ª¦¢p˜Ñ¨Gål3û�¼Ö€ªoXƒ¸#A Ë>n }بiE›æÜ-F¨I§âëÎNU͸³„Ír\´ò,S~¾óÑãG¬ x¨Â<ˬ>&! ™(T× ÷2ÆCQ]—xÜ´á6>qÇšçÆ#hDñ‚R¬‚KAó†VÃH~ù1_8B{–žqEÝ–W'Æ:®ušN=b÷œ'J¥òæõÁF vèúȼU›¢0¼ºãá]¼Ë³‡*M8ÆþÌ:­ãhZ3àñ�ajô Ú¶b jQS†õ¶êâJ”>ãž1Uh‹ÑºÀMŽžt�[:Ùh�Rh®NÙ¥œ \ó�hÄIôé®|ä¢ôÖÑd'u³l¦L|5<�Ó{sˆ´"*<Ñà<â­5‡!�–›º¸ 4ÚÙ¦rÝè  'Q›"=æ˜*ÎfΓŒ$MzNòU³§¼†P§)§‰¢q’!Γk y 4;<øÀн§&#ãVRµÅD&š#Ix^°ªï’‚vsÖD%T:Oœ$V1y¿Y.±D2¼õµ KJpá IÎ^2Ke�‡Žf_ê±Ð'ÇŒP.•Û.D1“Ka,ª,ûÃÆC¢°ãïNš&Œ“™K�Däã#ŠJŠÉ8U\W£ÛW•Nn¥À}z4­h"ÖîÍbdj K¿—¼$™�ÕÙ@Kœ4'<áIHÆš-""O>ȦºqúØ6öáøÖ(³¨\ƒƒj#¼˜P¥Á©4œu…*Mó.ÏW" îÆù`g–‘PÞ¦eÚ»]¡åCž—Öu� âo ¶÷ÎKÐù€Ö—ÆK ]@rŠ"ê�à¹ÆõàEÛº;ÍFñM 9 Çã ìÕ²¼Ò\2qQ�¬¼e\;5Š7åMHá�!åMÀÅåx+‚[Ðt �­—œ^Ï*Ôl›ã¤&#°š*«v]b~’ê(õ¤�<Ç{Ë,Rà Ê *HÝA§&Py¹~rB¨ ¨¢šJ˜^ø®Ú]!¡·Ž±0ËP£a³’E!h=ƒXÆžÁÇZG¿Œ /.=¤èœÌÕKSGŒ�û65¦b]¯ÎA®ÝÕÅrZqÇ~q .,®Êt›¼aˆ¢Ò¯’½¦G`A¥{ˆGšb\cS�:Ñ0½@ w Ôü8hd³5€ÀGm¡p�˜¨€QMBïX»¡Tå 4fðˆl�%rÕã¦Ýãt†ÝÓ«rNqˆ¢rØt¸rbS„» ¢ï"*lU+·ïm;D¯ïA@]Wÿ¹'öFÀè¹VC­áxY¯ùEÈ;õ��@› ­]¯A¬P!¥ê+4�æÀ!ÀðÎ�Œ¥·$Î9ðZâpVŠÏy ‘„.Î8ÄGûÊÓyÓÍÊTÁ¸ÿ2š"¿Ú Ö6°³bÉã…†”:éSŒ:‹(ÆúHÝò9Ä„ðW~̉”6QRj›Î»¦p   <å¢ ™Ø #¨Ï<%ªË�mâOxâÈ'Î4ת øS%�‘ÕT� ׸j`Á‘åR¨,A®® +Fâ€P�™Û;ŸøÍE9)*ž†»:àÁ%&¤4¼žÌ``šïÈÓiâËøç°•øÄS0�Ò®S*§6iE—¶cS#ôÜÞÝ×’X¨¡ÑËÙÃŽ2]UT£hÏk€?„Ë¸ó„ø˜p·9)ÑÕu¢bJTd*‘?&:XïŠ<œE>·‰<”5�Ÿ*}/’hØ8U2&ÅH�øÀ«Âm£\øn8Ö®6•Eb”é¼Lú$¤P!RÆÎðXõ™‘(¹=2Ó ¥TPXNµ®Ü²†Ý õ¤ìÄŒ‚èEàºsòÃxDP*À|à ïã5Þ.ŒSÛ³"v�iç8�bïKL×�Ó“% lI0JiËJ:—“¼Ø4e�÷ÎpK3Ø*¡JV"Ýàq˜xÖ•²/¹«kÀn�GxüÜT)sО..4üÑÓ~1|+@‚ÎÒwÆA1¢¢*|êãšý[P47¢úñ�¤šÑ;§C±�d+U)�zB)CœÛŸx£BÀy'8Dðô£e› ó–¿�lØAH'M a0µ¾ÝC tßî×ÞóˆQ&¬ÓЉÁçlºb£� ïÖPv_xzц± 6c|RŽLƒ*Çxb›‚s…G#U.qqdfŦ,V(.~ jÍÁÁW)p øÄB ¡:7|›0¢èTìóÆ2‰(A5ð%¦±CvŸ–±9HØòIçÌRЇOuƒñ›„)ËÓç ?HðÃox8˜—5À 1|÷u¢4#ø“|à0ñWÛ^‰�Ìv�1ÓN§ÞÎiìSKÀ`LZ¸8ù_€QÊùÊ*b/!m é­{Á !a<Ö¯zó�î)°�€åÛ’Ú*¯c®çœnDÁå Ûáã$4‰ šçÎ\zWãö^D¤[¨Õ;zÊ6SàÐ\,ÍÖ›^Ì’vï õŒl¤äÁ�žLBŒÐlþåÀ@z>Œ͵%µ4T»rÐÇF� cÆŸŒtîcý΂«­Ã#M#_]bŠ+�9— |ˆ8ÛŠ;V¯fŽ&Ä'Á°H¤ÈçÊ:õ”È2�œUÍ"榫€žÊl»õ€ ¨‰¹xï÷„­Q)�P§}à-p€W"c"lr8<Ëx¸šôÚ¹§ íˆ ªkç›@çÞ&f¹Ébë—X©ÎŒE«…uäÉÛqCÀÉ'CŽ€I2µt-õ–å(*CCS}Y\«g)·Šû©‰Z�«GS­½¸òÝÓôoàêàÏ…¡¤Ûïµ<âDϨezá!‡jM KÙ¡¯XÎ434'þó�6Þ…›lvs†Ú`àÞL(_z“v:çÞ HR×ìï½c „,d ‘{_O\å¼¾O]âîaˆÉó±—Þ8ë³7Зç hýÎ+ÀƒŒ…(XSÓx«´Óäã*1 õ€¸ð#ºôa|M=Gò9Ù1Nè`3~0Ô R)ë L%±:Tõ¬,äätÎ~<à9FhðF=þð€¤ àãç6¦¬ÒiµA¤Ž˜ä rŠfšEc|Úf˜¯V&ò‰Íø0„äðoÆ ^Ž2¡ÝòÀ:7’ ±&³m´±ÖUM¬®àWÞ1`§¿ D‡Gx‡°Úf䊢,ç�z3D vœ¾1£GjÚPyã#Ž˜HÃ[^2Ê=‘¶Dóã&Ù º§;îó3KÕlÉ`h¦Ó*°@€B&¿¸è¬4~×®ð(¯¥%"E†(©÷FhÓtæw1ørC%r'–ÃXòäõƒiTT9/–ñŽxdéÑ|>ìÚ¯7Î"Tž³ùœžþ°4š pÞŒç³)Ý]dör׈=^p°$:2ß§®3Sgh«ÿ|âšž:9ÊòŽqƒÌ‰Ó.Mد’u�Ùñ”©CÆõlRͳdÝq¨§œÜÄHhÛxâ­Üלú ºãÅIàÊŒÑã©FwÐáòÀŒ=*„§>>W Êÿéë Yv¡”Ê·EjøÁlÓ˜@£Tס2v¨¤(¡²å]x¹ß©Ô€:Û qͲ ¬KÄ ë/‰¨(lZë—Xþ¹àhÕžó ' mS_+�P?š)|Ì×>˜-l‡NÍç xÖ¢¹¬x5Þ C iµ ˜ÍoÖM™;�/ޱÈBè'9[t­ó|a´'D4ÿÎTM*s„ѲdÄׯ¨�‹?ã#Q,.3kÓœ0�s•M­êìl=âÆdM¡Û¬ÁƒHZbi²ùÎþ�­5.ðÝ¢b9[]³¼Þ¹NÁ�$t8Š”uVŠ–/+á�ðô8ï~®UΣCàõ“íѰññ‡SP"èë�"Ë_;Ã�boáN¨·zúÅ«ä×Õq7ºb¦—ˆìÉáÚL)‰MûM ÓŒšÞ½c¿ƒ�ï XŠ…š~kø1^퀎êO,Ö/}Çð� ÀõŽÚyØ~Çq2熢«»¾PÂ:OR׌ƒKöÝ«‡„C¨¾ øÄEóO »¥e2�èd€µa‹y®N´¬¿�s§¿ŒVw)]üw½÷¼Ñ Tu5'W~ÜiJy‹–½áãÜH˜À‡œ�|Ù²�sNË»�ѱ´}aj¤B¾ òò·Î jõ‚hèâ—m‡bGßýÓB)ÁÊéuÞaݦËaäÖœ* ‰6qÑ‹XfÕµYcG\ãÂÜÊC åyó‘ˆ�»áúÊÎë|‘¼Iˆð+Ñ•ÆÜn��œ¶©å±ã*mt_xÃn5.:hO €³Xû®Ó4ÆÙ¾yÀÚA÷øÆ`µâõ¯Œ¢xÊ=ÔŠqŸPøÀA6e±ÏóQ>GŸŒˆz0 N±§{ñ�Ôdƈºdüd&Š•Ôž±Z=ïí›’¢èyÆßŠQ¡9¾q CB‘:÷�¹Â¼P3àçê4w?Ü’Û)gã¬Ý„^}ã ˜¤v ãßY0ƒ�ç³ZÂ9ÝNg¦!:‰Ëy Q^H!æâh� äˆýÅ猱ò¥ZÁ N`Yæ´a „ÒïiËb�#H׬‰qÒ (V›Ü�b9!ÈËë¥ð¸¤�-<઻ÓpUU¿XlEä†Fé¬ýçw%çûeb³Eëx†„\ DU:¸ÄQGcÁ[¾&Œš^¤TQ]޽á¯IˆÉtt ùÆ#U¼7°…-¹,Ý–bQe|ï„T¤"iÓdw�4,¤zu9ñ†Z­AHÄ%FzÇ«RÍY<^'x&°àÈçÞ5”R&¹¶8 ù€ËÚß¶ƒ”ÝSÏ?Y³…à -ë4bϰáxÖl6‚ñ�VüáAäñŠ3œWN±7Þ7À8¿"¨¯(÷äp$,¯‹ÖVÚÂI[¡aˆp Z Ò}Ž6*³sXq\f=žqF¹Ë‘÷É Úy#ƒ—„D §ÂVøw…ØÙÇÎ"˜º¸ˆysk’w†µ^.:@á¡Ïœp‰­Ôê;p²°¸Ð5㼈Dã ëC”¦ñÐ) P’Vk¼³{ ä/3]¸š%ߥÞõ|8áaÊÖO ÚYæa©Í‚|ÀÕ1Z `lß”YƒÅ"Ñy„ 5)�ÓªH>üáÝAu3uƒéƸŒu~LEuk42„† ˆ4ãXÔ1ßÄÀŒ—`ÖÊeLÓJhjnjë3š¶écë;/ðçh¬¾1&2© _°ƒ…;ÂGE`í±ºzçÑ�‰¿O³Ö7Ü`:}³¬³°„R[ê£XÅhÒYåô÷Œ+|г¾|k¡ÎŸáCq§ç¤Ñ@høÆƒ‰©pü.øÄ#mÄBBt¬FZ¢YðxÁä1À�¢z˜õ€ìç!¬WF¹ÎË4xÆécä.Êà8Ç@]ñ¥Þß8o¼¿�}`6làí–|g E@ºíÎdò¦ Ó«Ö¥q7ÅÎ"¹vZ&‡Ù‘ô�AZ]¹í¶á©]ˆÎ®Nø]D&Ûƒ}f´5èÀ{K�*MâS”Âù}¼dHC(•Dâ½ÜK�)èc6lÒË——DAøóßXki“ºÇ�ÝÜ£HÀË{SX¬©;äáÌüe²r±Ç©t÷=Ꭲ—³—'Î8GƒÃ¬b½`++Î@*òåÒáÑäùȰÃʬyظûÆ*°¼|áX´Ë¦(‘ EƒÂ8âûy`‰8³ ½%@¡ßÙŽÕ˜ èò øpÀÌÙåê°¾²¤’KÇ‚…DU—<Õw³M7¬"$ºý1Pª;Еy6Öº®kÕ÷QÚÙeîãlX‡ÐÝíÖ“©äPW‘8Wçœi‰ZS—Ö*Y ™{žNE�B»§ó8I’œþ0M¼mXùL7iÆ“Žy0Ê CÐÿnho8ŤtCéwÖ*E ïo @¶®ðU´+¯.Špõ—t?8ÈŒVóá<˜†vÓ4ü�8ÀˆGœckzd]8‰ªgf/P±ØúÈXw‹JaÝf 5‰³uš(K…H ¯£Û~²Qb½dkTï ¨œ¸tç9WÈôù˜ÉSôƒÜïs€j¾;&‚%A÷·Þ‚ úã#<ÔÛÙ¾µl|cŠXt¦Â04òq10�Àìüaíyd6Ö¢DÐc ;&±BålÔÈæ �úpÑ®–3Jï“ã¨+qW4n˜È‰UÞ)J4"ÌW4l‡å‘E�¤!åë�U·”r�øqÀÉŒD°´@ß�˜£°a;46¦¼fär�dwpÇ,„ˆCfêN8µe«Á=h‰›À ‡ˆ?¼m”O—£Œ'ÿA['§_ŒÐ(ƒ¨|¾\…ìRM{÷’‡‹‹¢_î$”*P^•õÄÁÖ=Œ£»ëogg|Ù>ê× Z’� „ë¸�ç4í¸�-°"4õŽ#g¼UV,ýL˜óMe'üàê‡ùƒ$¿˜­¶†N ¼×­0S·ÙƒI~1…°šLàù;Á·.¹Äf¸ÅAœó„(N gÄ4C±ËŠº#¡|Ï›5â1F&§‡Õë’+AFrL@,z¥X¦×£[1 hh§Ã‚×ÄÜ+éÞ]h�G‹]a˜À‹§Z!ÇŽùÞl¬ÅÈê¦ÏyŒ)¾Ó dô9%åš“…РÆ›ÂhÂÇ� '¬¥­¾r†ð<ñ’ð�³ˆ¨ä„E«1ú…iL­°­ï¨Þ&ôЊŽ9Åè(|È1ÝÅàZNÆ=™FCjaå^Gx(lâšQ¢pew�]6 x‰L6„$ Jš]ÙœÐÂ1ß=<ïJ T»=Þ?xDä �lÿ—:.Ï¢xÉ©ª"è9“¼ Aˆµ=íãŒëÙtûç¼Ê57Á‚#´Ûta³h]*÷øÊȒ݆¸ÎWÏœ@›—`©0tE»ÙŠ ×}g­EìwŽ*ÇxÆk§ M†Ó—Î2 ÈϼìƒóÖ”³oÞ,AT^pë bDë»”^f)9¸¬+X¹£úòùˆÓÍïSp_†kÒÜzùÊuˆö1£>qE½uƒVÂàW••K)ÆýdH­)O.´Šc2t'úßã ‡€QÐ0N´[ŽYa¤1fñÙV^Éy”L Rí”Kã$òY ¨r¾°àx´`'{æŽôž[5ˆC·qvŒ‹”$p¼º×ã¢�ÊGÁu´Äɳ=°/bLCF§Âà?8¦ÚÓoBÀg0· nsØÕW`pe'΀'³�ð,' KWb4wrÏÄÂ!RY47'{‡ð_˜ÝT ¶²ÞŸ<Ý`«¼ šñÉ1wýM�ðMÞs;)†ìX .÷[ã ñ��l L@îw(à{I€‚V¢›˜¬G™Æ²ÁCt¯pf¢Œ.Üà|ï'Aî Ïc— ®ÑšÙ€D6 åÄ;˜i“x�-;Ä<‡x£®§œ [O8Gv�Ÿ9(H‰ n@gfñ<Ÿ;Ÿã)NwÇ׬àã®ûÜñˆÜÁf¹r�wdÙ¾5„-zͺ>XŠƒ°³NÏ-‰Æ:˜øxÄ_8 Ô0q( ã8YšUZd*‰µ½róøç%±nK±½ñŠ_"%Ä{< ›ÁhŽta„ÖÁŸ<áàä w<«“¦QÀ e‡wZfê“b¤›ƒ�´Þ)!)i»,¾cJaûÃgDO‘�Héà�;»ÝÂPˆŽÚKœ‚œ=â¦ZyžqñäÕ§.BiŒ€W}kw8OžÉÑô…ñŠ’TÎŽé³x“H¹`×ßxÑÊBðHxœâ Îõ[Öñ!:·*R—¬¹ËG>O3¦{ßP#Å:Ãa%‰¢V�rJFH{%Ô“o¦éÃHþ/¬7HSBBfÐïÇœÐN Áô4¼nñ(„ÖkãÞÿãÞ%(_-,¼cP¡w‰àޏÊ!ÑxFM§ÁËŠ ¾ÌºÕœ^±CYaP#°x0КéäÁŠKZÖeA8¶©±ÄÜ¿>æ&5¼,ñ¯$ûÄB’‡©Ç=`€y(hOî÷Ò A�ÉïµT¯ýç% nT¦“q›ë)ñâY¼fÐå ÇÍxÃg vS„i{eÔÀAôã)Ô�Æ!×éM=™EÄñ�1Óï.$Ý»ÉàBè¯/<ë)I…_ª')øÇq$² h ¿â±;Œå}b;¹zL®ë q‘ä¥:EtòÍ¢¬QÐŽ´ðaõjd�> Âw‰8Uàì ÔØAÓEêbì#F½P8ÀÃ]оð‹¨Ô°U®ñq² áÍZ¥“ªídøÅ«¨ª‡aÞ…@¼Ë…€WJ9¦�<É<äe`…2BB´Ü ^AG¦› \ByÍVŒLã¶ò�¯õ{ÎÝz þTÁké²�GÞ$ (LŽV$Ö°Þ /Êpë¼g{H¥êñÝJ×—'Ú*±«J)MîÕ™:Äpùº›¬ñ‡ Ò„ &Þ=$–U_¾1‹5M9ÉψSë8ïcþî „C¼yçJuÖO1µ¼†én-ÍОpU§;Þ=�: ùÜã`Þ×XÕ Þ²ÄˆÔÔ-!TÉ•PP/uã IÙ#ãi¬ºAŽõÎK’ J÷Ö Õ(=º^Œ "ˆ¯eÒMd›ƒhÅ}\ó��€b…_?6mä¸%Xªë‰Š9ñ‘6Ün¶öã¼5#Êi|ã±H%tòâî×DjóXïÆ,wE,i¦Ò�É“®ñmÎFGgœ5äbäHñ¼"a&öÔb“b›�NºL°„б b/ß=`ÈÇ~v�ËÆ-=PP ™ÍŠd ä6,òo$„¿qÉP^#2� ¥ÀåW'¼ ÷^˜¶ õÎTâœ!e¢µ�¥]ˆíÂüä„Bâ]:ï>´b<´€Qa݃}àPE�Œv÷ŒŽUD)óÀ´þ”×ëœ7•¢œ[ëO´)¶ªÒ÷óŠ€!J§–™q1�éguXy!“×hÄÙG‡x± ­;«çq‘¼'™–ž�ÚNDÒ'x+m ½™SÖ¦š:Í/#îQºžñMލª]~|Ó9=-@ŒIŒä<7‘UC¦µŒ?<@@'ŸyÈŠ@Ó_£³ŸT|`Q…âÕž?9}±fíyøñ‚š¥TQHšY2&÷6Âuæä¨!誚g��˜-ö%š¿8È¢uóë*ät+C½øÃ�ÇMåá=Ü–hRXâ:¦ô629%õƒT U £ÿà SÞoß:½ãÚ“|,È)zuù÷��.�gØ;ýeL„²ÈÔÝõŒíØ?Züa’ˆ ‰Åx�ýfà9ÔÖ °ˆG™ˆÀ± 9¦¬}ážh‡��ñ‡©E…ŽÏ üw…nàÇCÓ[f?,§&ä' ³O;r K�¢ÏŸX þº�@v÷dÄ�±¶°tܾL—ËFÚf§<Ü­;h†Ð;{ã ÖÑ÷ö ¹A� ¶œxÄ´lE7G„eÜõ—'Ŧ È×Ú`Š´˜*�hñ¦î;Hî/FÛ¿(cš{¬F΃ó¼ì= bªÊ› “½‹5ˆ¥x©zb_…Àù!CÇÆ:81¨$S«ñ¼¨/{m9Ö°W#v¿‹CÑáÊnæñv—µ;ÁgY„ø_3£Œº}çg‡”õ�dÐcZ+’=dY¡5=$ò\ƒ¡ŒvAï¤üã/ ¢tÑÕõ„7BE )kuÞ¹ëVo…[¥Z¿y*ÓŒ�pæÓtD†à͸�@ªò‘££‘‡;…ô%Þ·}æ†’ÊØáÓ¿xEF eãZ¸Ÿ³MvŠ;߀F ‘>f5©ë³N :jë!•˜Wg¡<9A…À±#eâ`Vë·y³És¼KûAdÕç„"N'X—nÃŒœ¡…hrSÆ#{òó�Ä[D·ú8 ¹*ž×Î#' cÜ4ÇH˜‘áúó’ÓpÒÎûõÀ¡i¨¥Ä€ƒ‘2|<)ˆ‘éÇ~O½�œ�{ùÍ��¾2*¡‰êe�¸ä/ÆW¤Ü¢ºÃjLpÇ�lTç—):­›œ­µ…bSÝAÒY3�ê]°:1VÅŠ´‡ MSŠó„)X‹~ˆÑÍ Áó†°D†§+8}`B\EÓá>#÷—ž}Üå¦ ªÚ™& •}àÍ^6º ¥ŠDkœ.^Û8iV7•©»t¿Z®Ùªtwó5Šø!xîœåà„e�ˆºò˜ÐXØO/^·�õWRhm€vÇbßS4€DíͰJ§£µÜ�`‘WªŠjÏ£L)PÅ7|5Ö°òì©'ncÆ#TˆP§‰Î)/©sEá]á¹¢ìì<|œøÁV a"~rQ2 ìêÜi›ŠHÔœyÑCU¡~`“AyòmuÁ•£�;! Á·vá¸&üá<ã‰Ûìáù˜ÚI� ¿‡9YºølèMIñ‘޹ïßanm}› ­ åÝÄ™wœ?uÔ¥•ë.l’ƒfñ¡•´èŠ6[\]k\p,,~üˆo,R“\n‡!Œ¦�\SŸx³ÝÀׄÂö¾ÁÄ=ÜÕ (¨©“"ctêìñï/æp% ;¬æÌE¯‡GÀ7È{Ö#Dœ?# x‡ï%–œ¨™^°WQÁ¥z¡úçúC&ž$œ�·2®9d&Î8ÖnÛŸNÒ ¦çã–…ë«¿ÆÉ…�\ˆ�¯Ür_:T€&éÏXãäLÅfÐI0Dm¨lÆé}-�T;úâ`0V¯H›¤fœƒÉAhÇ8¨h©âc7'ËPI„xÒPM‘9HÝÆ°–°¡ Ã7C¬‚&Ö º?Y¨Î?  n†˜7TN-QMªÉÞ¸ÅIåQ1µçI1)« •wœ á!Ãydv$”qÏwL— ”¨_Ƨöse(Š€þp5» pâ£�s‰œ íf ž�PEN¹W‹ˆâœ Ðme+Iáq<¸[7¢â+È ¡ �uïÎ_aa¥ÞG·ÊSá›Êy=åÀ…àòäq¾°–Q}êå·ùDF➌žC§clŸyÎÐt5ùNàt 4Îð�Qf”ÒS¤§‰w”ªØMè›ÁÀžvͽ…g¬Ø ç¢[ýݺ"Ñ"8ßßx[J€ïÔ+bS¡;ïX*ò€æ®jÐÄr°ªÈ>F?¼V·�ðB;áÀšEÍ/ÎeœàG›zÅnºÁA¬ c)¬Xò÷¨Óý1œkï# b¶®o¼i¬šß…ÁÉä¬hy÷ˆG�Ùv{Äó8àðzIÎî²Võµ9‡ ë—’‚lƒ4üW·mh\¥ï¿X›y•+® Î&V2 S_ 9IÊ0 3õƒ›ò‹b P pë ôMaþàµ�P]�\C‚®E°‡œ$5™lÖÁ9ÊÊ×`RD-‡�r¤2%E!ÈÚ,_Ö!ÉRŠ•¨Ly2Q¿iKÚ| ˜D6 jNÞX.ÁJ«²¦ôNó^o”hGø1óºÐÚÕI;»Ë"åLRÁ[€„Ø<Ó¤Cõ‡vÅ Xo�å˜ìß�[IßY¤€­% sÞ¥o@ttóΧïZ{´%7àÀõ+ @T]bÂ%ÌUÐͼ]x€Mg¼ï_ Ç”óŒ-ð±7áë+·D7Oeq¾\=ŸE"¦²£åÇAì6,ñÐ)`@T÷Šœ°„8ç¯\fæhˆÒ´TðÜ ÂiÐìãæh Þºm½ä«K€…±ç~1±á‡Ãu”£‚ê÷’»Œ‘ƒÄá†öÔZÛvä' òŽz1]q‚³Îl—YxjdÙ›'Œ æoEV‰­zÃkß—#„˜8€rÀµÝq×°7åÚåÚúLêûÖG»ÞV|m˜/8Wr•îë4‘( àÅȹ=å&?X2Â�VœuÕÊÒ�% 0tjþrÛT¿„ÆÏË‚äNѤØP¾³Š�53£1©×Σ„N#„'#§ôn¨«½ƒ¾wƒÊõ=ø0³ÊB/e}c3:ÔÑË8Þ?Z°àÝÍhóë45VÙGÉÿŒy¡‡ÿ#¬Ý&­V6½ü`B™pXÀ+Ï>°— ð*K×¼|`,Öµâ»úÂJ›.º% )ÉÍÉ*Ôo�­~zÍ.vR‚yµ^ÊjðàÓÆ©É–††€!va…0¨b`äsp!ËåÝnUцlü4Rò ¼=Ç^qN´:Ô}Ú÷×Áî4 ðOîY5Ö¹v×ó%uÓÙ�v6©L ]äÃô‚º�íÖ><¢Æˆ«°è®2LóL‚�Mt¤åÆAÀm‡ 7gáwûéŒ@›Ûñ�N zŸOâYÁy?l„¾ƒÎ•Ø} Öìßp\Q7²ûÎyp”øÅñ­õñŠP)Þ  ùÄN†8žˆ·9N¹ö>Ü0þ’ÓÀW®²;ÖùšKháAW€ÕyÖ/gÌGC¹Þ5XhGÖ‡ãÒ¦¸“ZñòLD Ú�!ÔŽð‹Š�ìÅ Œ¢ê¡‰*]v_¸ÌC¥&“vŽ| ÌYÈÙçyBRŠÙìŽí`Ï dÐ ‡§“üÚ‰y¬L”Â`𮾬nµr~¬Ã�S´èàù«·Ö?E NLcH ¾prâ= gÅ¢oîZÅÜXøÆÉˆ<¦)ä1Q$é4ÀQ£â܆ò%ÐŽë4ïCX°¾q&E{†O̪h^u8;Q�×m8¼4n›qx눛c¨äÇñ²Ç‡¿xàa¾CFõ|ÒÉ¢�ð¨ZõšÅ¡GÄÁ #®M!–ÞE ,+Zq�W ð©�cÄxƒ-®Âeˆ‘ÉÐZ~0µÈÐx”X "[‹çFÑÅ�*ÊŒÍ/;74žQL&01lJd‡›0jÓ1‘U†žð`ã›’ƒÁ¸Â¬Ï"lÅ1ˆž)\Ýe$ÀŠ.å/ŒçðT¾ÄÃA>ñ@7ˆ®p6•y˜Ó�{ÊJë"søÎdšPüºÂQ}oûüÆ…ìò©ÎM;ù—¨RVù™@÷�;>bc /àÀÄ-ËNñÒ—~pVÈ‹gMðã¾±<6øÅ¼¢¤ÌàÁ@úÍAƘ#x™°�uÁüàÇ— ÀL“ž -5ùW©:îñ‰¹|ÈDÜòÁëX¾&AyuÀŠ&M±(åà‡iÂÇÀPžÁuï–àC@œ›o„yɹ²ã§ç "”x+Á‹ÀN¿ÁáÁ º˲~Œ'~6°Iï!eJ"¼óçO-Äàž|†zIWÐkífàí�œº Þ¶ÒÆ/P� WïY,!§Æn»úÈxXZ­Þ±¬†Q£Ùªù+ƒŒt+5BDà9ÖVѬæ·”a­Í+qú¨4ªy\›²…j7*.o¬³b7²·�àÔ¡Yç­a‹e�j9ǬjOà³xë@ §“÷�^ ÿf)kep_\b¦±†f$Ó¶‚¿‚¿Yäí)qÓ«�’"tâ¼o鬑)9q™t9Í Ôõ€X6Ýà�&CH†8.§ aÏxa4›æc;2š ñQøœ-µR«””ºáË`?,ÐîäÓC~5€5¢�>°¥Ëz�O¬pKV“Ã…‹w›âü‰* Œ=�H†Q] &¸Þ&Ð^€SÌà;ÇÓh–ƵFŒ-•*Tô(X̵É780@Kï"@Ukz\j²†E &‘Ò½b„<¥:yÜóÎPe Uòåm‘œbóÅzïl‘/*Lüaæ7’LšG¤~ðâ‚Zz\– N�øØÚɤ°UjÃ]ÂfDiÉ…¢–óÓœ�p Ý81nÒQÈœ«£øZÍ€«ºd÷�æn7"ÚóWûW@!½q³6>¿6ã#2ÉIЦüà ¨at�Ûº÷‡ýÕ¬­€Àà: ¼æL^¢/RÇuë°ëŽ4´?q_ÄÂÂÚ?'<Í…Gä8÷EuåëàÁ: •ë¾âôIý2'ìHf¼À$¿g*¡à¸¨AãðÎlk°ï"QÎ4Ñr9zÄç“_XtRÞÌ#®n±C�w‹¤\HÕ |;¸�tÃYç5CÇéÛm׬¬�©Dù?²—’Òw¸~ð—çIY)MPfRý¬.‘'W…€Ü°$mÀ€àÅAXqÃ%ð‡�œw™¨U¹ _÷ŒW»YH>µ‰µYì�Ÿ+}‘Þ•O›\ƒÝ¡ÓžL ÊÙˆT¥«Ìu…[PÂé#gÆ9,6€ÖýÂ]b^ÁPoÜŒk C…}åìÝ~¾0#�ÒÇŒ'RªìAãÿ\e0;¬i—�OX9æ�íáÆ6Þ´Æ¿×%¡F*/ ã ~¶ &‘yMßg£¤g*?xVö&Šqç&DE‡N(€ ð5çú#|=IŽ!({!ˆÔ;`¬Tg%ãÔ†ËÝkµï—…P& ïœºlC 6|CÔ8ü˜ • §]ŒÖ!ah¼ß=â7Ö,ª$!ù.Ij0éGÞð: B:c×E½Ep¥:gžþ³Æß5�´p�>ë8(F×½â}Ç–=ýæõŠM"™^Pðó�ÀÕ{Á:5ò`¢(bñÓÄËXEÖ AÍœ·¿o@w†¦"‡àAÂ÷‹�Xº"jðoù„  °éó9ÁÝ�¡¢5­¢y1ÃÄoJPñáÊQüûqC¥©õ“ŒE»P˜ˆ�P€Í|†«¿b¸Úñ�ç,#ÈçXD©ðXð½25†�ET¾ðÃ4�tJþ2â%àÇ%%”Ó­ûÁèlç†cI¬ú9B‚Æ®pÓ`�¤žÖíä:`£Š‡{—zƱœfW]`ŠÕ��77V¨?è¨"ÕàkÎM€l½µ¿ûƆ¹’•áÇ^ x¡ÛŠ:ú.È�Àóóˆt€Œ¼3/Ég¥#Á ÖéÅ›ÄMCÍžÀ#¼­ÊU[E´šï©‡„Á)zíÖ½æ�Ý* Žhãk'�x½€I¬5C´íÍ\EdQÆK¢‡‘:Ɉy:Oõ–~4¥úq:kŸÎ…ðÊüJOUœÍàµ6µ/HžNÚq„Bö�VmÁ"Sü C0 @gBí72ÉÇ"œC€âäúúy4OŒT*_¹ÞÅQut/Dó–"õƒÙS ¯­Òõªb<R«ÛƒüKôß~Y.…O­ïÓ HüŽ%_->szµ9‰å q€w(L\€²Gû‘†�*¯Õ~°ï§…�&Íõ‘5CÑÐOŒo×ÑA5æøë ‘oW÷í�À;€‰Æ™¾piÞÚú¹ÒÞ�aâï?W]j8h¸çjPiP+Æu6Ð#WнÍ&E uqR[¡š_ó-‡vîþrÆ1o>×d˜õÉÐ'ûËü®ÆÌ)Î�üå;>çƒx ÍcJ²B‹W`Çžq(k¶ä,Rцì—�ãò¿û� KåÞŒ½ªEA=˜ŽÝÀÝ8}â,M‚Uü²¦X"¿c…XÓ�)JoïÛ0ž_ mÅA;ŽÃrÎL·.AØâå=*S4ȼwX\³a!›:ˆl `C (¤ÿ¼ÜNØ[w‹ëBáðw‰g¼ 4×I³¯þåò([Ã÷ÿXpýà’¸HxÂø¦»Uô»ÎU×U¯Šñ‰ƒ„ç;pÑä'Ã4þrQa£O°Úô$tÿ1e_W:�Có|dëÏë’œPyIÏÆ%\R漃›š²Ðõ®ÞjMhU5O9ùvû0§>Çï8Èkx|a¥P6˜U!ÆÜ_DâpæŒ eq€ê©O Û�W!—Gz¸jÜJ¡ÆƒlÎÌ1 ¢¶íŸ3’ˆ:Î@lÅóÿìW‰u‡P3V^rd¤h�%kæ h?G#ihkãv?µè ·%ìÍä=?Óã7ðHž¬cè€OëQ„«ï¢ó룅ÑCÌ�ë½+È<¹?$PΰÈœ4C„�C�~”?89@,éóÃ�#滫ï×8šÄ€òžyÞ55ѧárJ�›z·É•1±&¾÷‡w° Ë.1¯yR‰°�ãéê¨ÒjïHó¼´,MÔ:‡x~Å7hÏîh� sç¢/eü],Í[�ÒòÕRÙ3�õ@5­�âah¢C°\TjoÅx\U¼"Cëÿ˜E�)�ìU~q:uøh š/ŠeÀ ^AÎ\1¨}ë4�òõ�øËNò„£j[„"ˆSª ²5š8‡…B/\Ü -7q—ù¬ :¤D¥Š“Ù�î. 6-€Ù„â„5Ioë:A8uŒ‹Ãlc5#žS[ã6H|ƒ2‹¸“&¡‚/ÎMÕ5ÇŽ&&”B=äb û/P§Ï.°Ú¸ j?Œ4<qx·Æ ñ›½›DÍ%�?�8Éœ ãš�àɦ‚øpÃäo!vüà¥>UÐ9UfËéÁB8~.O÷ jnµ?DÀt2¹Z¼9¿¦‰©Î݇œyJ˜+ýïš�F-YÖñ¦±*W?mhåš‹¯�ŒÓ1i¢�¨³8òùË Cü˵¡ÞJ¤Ø÷�PFÐ¥WÏœ,è`gÿ*I_Ëãœf£(JÖdÄ�Àõ‚]Zïã"T<½œ(Õ(­=8ìôWc^û€S4b'!³Þ4ÛnOÁùç>£s =Zâãù’¢YÛ¯ÆqÕç4 ¶œ&²yGL©ˆ8ïàèÖ»ãyµ>yÍEÑ {FºÖðP¡ôcÙvŠ&ô »ÛqÊPšDáÍ¡Všs±3f¨+g¶íÆßXRFÄS|C³£×ÇHªÅ›.?À£]sqB«>‡*@ôÒ+ïe¡úõœ�ÄòóƾñNôל=àWК^˜s‰qÜBáׇSl„Z��®xÞTBÕ‰“PòÒt=|¸soBDõ¯¼ØÕæ�4­�-Éj˜Þ€�³_x’#x¯FÙ¨yýûÈÍ�­o„Ùï(íШNök}8rÂ5ZG²sðáÌIVêhÉ4BÐñ¬ G án¶g{ƒ¼ÄOÔËF‡é†�Ö±˜ã¡\G-ËBW¤pP¤GÑ}xÃnÅ&——*JÛè°„6±çï•5™+£ÉüÅ÷'Œo0 q¨½Z}.°8Šèz¦Ü ¡!Ûþ0�.wÙÁ÷�€¨ÙšZ³Êäþ±êù/g{ç|ÎWš7ãÖ„Pm<òº2™U‰ëɇQ9bš÷ã Ä=šc)ó‹pÔ›9…²öÙ•óFñ²/¾™c€ ˜Oo‡sœb$P­;œH ãÀ™²�àÉXÚ:å:Á)ÂSõ†�ÍJÂj˜}ô0haêB€Ju¾'8¹‡LÀ�œ>q CrÙÙî'ÎCG0Ü)tá¬c?H¢øCŒOíY®¿Üœºç�õ†£„ÒÅ3å˜Ó*Û[q?8ÊȈª�é댗æä¨Ú‹¿8:…­ÙÒxï$AÎ÷Ö±¿-näº<.<ó {›Ö> ’‚Ûíg_8ËgI¿¬`ÚÕê~±`ŠÎ�åÿñ‰g‰¡Üz ÀXìqÿÜ>°Â'šªüýbÃQË ž;Æ ÓÄôùó’`+Á›ÖlU¬P€¯;m‡D â=ªC†¬2y˜€HzÂuQ”PŒðÇœ*6� ëZÊr‘?7 Šu=ºN²21@ñ:ÂÁJ,¼ÛϬp5¬¥ŸMÞ<Æ×D}øÁ/¥ú?›¸Èj•4.¿ï%Kè<ëÐqîàî'™å{]á”á‹–Ðå;3BŧŒC|>@ï‰÷Šº ìØúÃ+àÎx¿näg”¥ÞV£-hö¼ ᱚbÚsñ¯XrÀÓ¥ÃÕÎøJD^ ‰Ân«‚âµØ¯Ïh½pIpªÊÛÑÒ.:®²ö™jƒgÛƒ=�ø{wXôfàÅ´Úñ&.¢¼‘îA1 ÖÆ rÆå¹ÁK¬\žñ¦ÆÚ² XS“¬ínŸ¹£¯}dh»bÛ‹H�ÝúûÈÒ†Žã³53@ áûÊSB­~ó–¨!Eç—óõ› ó {Â\´EåÏìYƱ.޳CNÅ+¯X®¼á2³€ÖT·ËšûpmAyzæâ0¬0R«Ñë#wb «£Œì 7^N®0€†©G•zï‚CÁ²X%0¤0²ßŒn–Öù�æ/vÕCÜX.6PÉ^×ðb¾øu©\99…𜸠V#-�É×fl@…ìq{Äz©¬�ˆvÚë‹‘¶ ‡* åu–p@Î ¬"Fý‰„>~°ÿÔƈ"4žrIœ#=…ZNñP‹ ½ü,åÁ{Æ¥¶™³u<òúÖ;®ó�·l�LJ\P·³;³X¡�{æñŽ38W‰ò±ïË []/§ÇŒkE‚5Q“ùøÄI#q|£zøÄ\µŠ…Ó¿!„Pé&WǬ] ‚ÎàQk�åaô"nvøÅ•° êoaÖ%E³ãàÙšLlU6ÿÁ‘@4Î��tm5@;<:—ñ�{•òþñšÎÇJ»Äz¼áÙ¼lCž½¦Mù¯1#Zùèã4þ»ØbGÎòë߉¬`ŽÞC¬‰º÷ˆ�Û›‚ÄSâãîÒT„ªl¤G,‡”N»|çr‘¤}á�r¯CÏõ€/!×Ëõ•‰FŒ¤=šçlÕ NÆr’‹¯àÆ ™Ö†ü¾pÈ<¢«^|eÕ•zOàÄç² qïîh}åç�ecJ¸B'ï ¬ GëNؾ&X.Ê6µüÍÕ)ƒ;3¯9OhZ€oPƒœ Fhµ§/Þ:·n®ñ•O’q¾rg%¿›¦‹øÖCËÃI¢qáÆg#Ä{½ó†5fÁKeÙêþ²Â€Žs&õ†Pëóv’m>zÃ_뙸« SäQÆÆ'\àƒ¬“S£Îk�@]Þ5r÷lN{rs�Ú:-aKfê@‘-øÖC0'JKêxæcððDRtÇžþ± LDÑ›Ã!÷’¦–šéï7 v–ÓÅ® ! v¸yò5ˆ»œ.(a«’‹R>ÜdðÚ^FÀ›~°ù EÛŸîiOt€òøËè¾1Û b¥ˆ�u…Ñ!_ôÄ�-%ç'œ]qÐGæä˜Ü‰7ÉÁ ³7ß»OŽ]á}Ì$t]ä8 �A·Ž ÍâV‰éq+ÓP×8¢™­«´Ì â ˆœ´Ñßœqd ä‚=ëAW‰¬}­Y¾òh *—WÿÎy/÷™EHï|Ç+„´69»¾ð¹Â DðEoÖm�š€^ÃÇ$Ê^<ˆ;æ¼ ñ°ž^µ‚‹tpùÈ=’¤6*ñš3@Nè“ó„ éÕ°ÿêd‡‡ÿÒÐgT"/cøÍ²ƒÄ�BDö±Å†‰ºvóÿÌáð•ämžnP JÂmÀÞn „6äkÕõ›dŸUwҫIJ`‚ÜîAp$×9iÑi/cƵ“5ù€Í±Ê jöÖóŠˆÞ‚ ¯Y¬+Oe¬â ó›&Vk�Û $rR06»f²°Ñ~äËÍíR¿:¬x Ý‰ sç9:J ëjå \’¨¢ZÈ^G¼ã춃è—|žœÈậ»!*7�2…óy眤ºUaØ?ë(SW—‡ÔÅ8‘' öQœ3NOàïCÀÛ €ÆÎÉ_kÎ�)ðW®ò˜˧XüÛfü‹–AdQzÊo%R =úÿq†j>Ù:qptÔªâÔÆùË÷A_,E$Z£gÛ‘ "‚â !%mÎÇ$‰çÓ€¡ÝÕ˜V*Â%‘íò äg@9.ô{Àn¸Ä#@2 vcŒ^‚Ou ÿ2?b]׸`…»Ä/I‹¡�X$–$OIÓš u‚ VôèaÅ ‡ŒxðppÁºØþ0C¯f& “æP#ÙG¬|b$¯…œi¢up à sÁ„ª�¼ò÷ç9,7¨[ ‡2¤eüÀ÷œIWnK•'<⎲=qÓ5ïœj­cIÑôÇrdAWPyó­�c‰bÍ%•>@‘ÔøÍ_¤»Žù¥”Þ¸Á‰Š æ‹HÛ]Þc¼†ÈãoŒy�.ýªÜ ÉÜN…¶tUù.U(½—G~]a?.€r ùÍÚ}‘�.\êãÐ3€&ƒª|bD¾‘né´êë ¡ÇÖiExÖi“i›9G�Ay^Úчìx€ÃéÖ”j\iþ:M¨¼S·ÌËin¼ù¾3�Gi1ãA–Çò½ðrÜú€øHŸ*÷—~ðàÿr˜Š.¸p£kiÐx‹mJ6—Þ,Bà:9‡çu¸éVUwÔÀÈHÑð?Ñ�ä&˜óp��f¸ËØùdwœ°Ã‘þÐý hl/(=ââ$+ˆÜÐt×9²Îéx^|E¼s„"Ú%/„µõ�Ô•Uå{ÀOb° ž¢–Zëeydàïõœ„”Žb• ŸÆm¤¸$£r�éë³N°•Qn2g†ƒÈ1§Ã¼Lè8й |.8Ól9ˆòå\ )Ìó„+# 8¹WÁT1µ†Y‹ij) 0�åpŽ0€¿d¯|LWì¼#¤õ–i0iQA†Àg^qã$1§fÁÑÙâÓ’&2khž4mÓù™˜I$ßnKE`ÙVýIóšJÃ…h�*%ùÁ+(¦‚À8~q‰ÊTˆ'7£ƒÙˆ¦$ºuÛ|—~pøpMÌ©y£` Š�ÖœQÈZ‰…éÛåfs[ºBU}ëœÈ;Y¤oÀ\�C7¶øó�]ô¥­â^Xêl=íÓ˜®2 ŽÄ7æû˜ÊµK¯ë–d€|B;äëXUC§òŠã_>£©g§/¡@ëØÞØ‹P,MÕþ¸$¨Ñ–yRì$¬R!P¤ <_x4›$qpÏa@ñìÁäÄÕ»•�nÙ3Å™ì�¹Õ×Ùœcwñs ëœÞÕ¡ñôñ÷‰V£wL¤4Õ©òe_a¸”N›<«€=w\‡AÒzÁhh¾oþ2˜~aV…Ó�U‡œ¢ª˜"rȸÝI€®" ¾ƒ¬ ³œÞѸ:# ÆñJ&Ñƾc]JÚÎQäÞZ‹/îW­5ÇìOÊç ™EfæCÊ ù5‰°�ØŽJ¸ þp%ñ(éÇï°P!#ëó9k`BÚ!ÈkÈ^80Øf•Á# è«²êkGËŒ@ª”>�(⇕È$Ýñ€,O¬ BT„9ÎtÎ#”ºq!91946¸_‡ŒãU²'i;?¹0¡X€ Õ� Ž‘¤UÜ…°<¬¸ &¢…�Îsip'J<Áç«1ú°ÔMuãÌÖ"rö6*Qd£€.º Z•úæ·ó€±Æ˜<&œ|cÿ„.Îèì „ÊÄkv«è¦#¡Sèv k~ñK—ðÃt@š5p‡:«ƒ�°è|µn-Gœ�øzç�D¢ºW âwˆ¹éT)œLvÛ6PvÓÙüq $;ÞMÁz¢ŠÆã7N{=i\g…ØyÛP·r|ð£Í”œáÙèh> ýï/©P¯ˆœáBºÉ§UÀ É<—þðQY5u�„A¸Î ”.:4l´�ˈˆh GxxA4«W¤vU-4°H»¢;$õ&¯>q9+n´S¹¡B—ùÖíeýä™4Ý%‚VxÄд¢ˆKìMOÊL^À—$ˆ4ð;!ÖSéáKD} :óƒD¼¯Xï¶n3¦ÿÌØ7ñ‚Ú»øø;;ûÍS26ê'½Óá90j_%”ð*á‡@§CU~¦méh¤ØøÅ r&EåZ¯—s~Ï€;tìpVR†ÏHnwœ# åÜíÂÔ ›jÎ]ܬIª¼ç¯üa!k{¬�ÍÖƒè- w€Ëk¨ éÞÓÙ}üRˆG:7üÂJ–ž�às†Óè_‚ùÆ~ÓM5ØõÁñÆò\IvZN1?�0>ÅÈÎSŒJEAZŠ9%Z+ÝÏ Ke‘iNt°ë•¤(ãRÈm¼ž¦Ьx…÷‡w´üwoÖ�1¢ÈTõõpnªhAé`^`Íì2ª!¦ï¼1-E #smT ³�'¬j�½i4GE ±rÞºËÂ4‘èÃß³Rp¼oïÞšd—`P=ø½g> Dí°^Xa—b5ÔGŠ®.ƒñ~0IíŒ]€mW7ÂÉhÑG`zUèYDm;ùʼn–×'È—e}᪶ÎEGbæîB‡OtééXì¤vcáÙ¬bZ\ß3+œ«ô' _QÁPýl'2”~•¬C´9‹®ÜÝ1ê.Þp@usŠ`–`Ü”]õ]w(âçñ‘}*­äkÞ7l¨$Å|E"93©ßÙzùÞ¶w Ë@ã}âm©PyËʳn5‚TyW�õ¼Ñ[㯦_sÖQZ©Ë… /¦3Á øèé‹K&!¸Ü–‡J'#�J#­eV�G+ÖmÊ„3b wã¼qh°éhæ8Ê%–V›¢JKÎçœ Ï5C…Ñ4c;øÎ�G¥OÆi¸s˜tQ¦ �Æ(d½>Š« ’  rÀš |˜@ £äü0<Ђa°ô˜z˜;Ù>;Í.éUXE×ó >0¼lœË{é3‘x›à'À¿xŠq›ÒîyÈdjɆu©ù¸¶°hzü6¸ïåXEZ�ÿÆ µ€ìÙ­5Þlv�6ûÎj¾¸¿�Í8tx9Htõ¼t ŽÊYN|¸ÅWØ_És–NhÜK§ íÀ…S¡ÞOXö²Ý¥Ø=ýu–#C‘÷Žc!õ¹è :Ö"(€CRHGãøš0F•7iÆ ±p‚^æ2‰ÃCdyoóHC@oéõƒˆé\ŽÝ#±ÿœ4wh)÷&o Õ�Î(¡wÆ}`Ù9ï<ÍÜc{ÖÑéÏÙÃÞpØ—ü€Ó±kˆ¢$Ò ¼ãtƒaö需|† � ©<˜g#0¯Þl¾ý�L \EýbV³òÕGÆhVrJö_8AßÉÈ!ZûÆŸïŒÖÁ7ϼW|xÂä5RÁ•kƒj„}nB”…„À>Tn X›ô¿+€¨P0Œˆ6r]ãž%D±Æùáf<Ûl`¦ôu‡e°æ¦ÂµÀ ÆÉC cýj°*¤øÂy·ƒ£uxó‚Ë¡uë&�¹iúÃQZÚÜ=tŸ™‘îõµðaõŠ’‡‡*¢—zÆŽøŽÇh]Íx|e$ð”ðÃl;K¬aFÚT| 5ÎâòCGKÄ8Âö� X³wŽ2•C›ê— qyf)ìâ˜Fé`Zõ‘t ›±\ìã‡!pùìñ”ŒÀ¼!>Ù�Ä<Θ£ÚsŠ.2U§|d¥-ðëfCg¾›¨ˆšBúÈŒ§Ó2Š—&À£Ä¦²`£Ñ‚J{ç• …;°Ø£FoÌ5Ö¶�„|xÆÛ <[]?x…�·SÏ6º Nž±‹Xª‡Þ€ÏþåYü@­ÐW¬P!È¿õŹÏ'yº™§•*嘨8ó®2²5úÀÄðñÂiç@ÈQi+ÉÅHeE.œãÍ8Öáͨ{Ðíõ†ÂºAn -Û»ÏÖI.üÃx®¤r*(> §ÜS¼c�ÒòÀîåûÏrÉÁ¾‰á0~6[Nwi¡çCŽÔUÛ{ G£—pÁ  ë¨}ë4Nã ‘jØœ¸-8°¨½`Y€árhpUUÇÑ –ËLä{i J X^à‡ÜÁ¸NéÀsà›ãVú�°«¢su\_8˜&¬_. ¾ÒV½ƒ( ¸@$+hºf‰½83¾ íßmL)va`2h±î€jhÅR9jºrK u¬…G!k¬ëÌõ�G åÃê9Ë Ëp*a¸› m¨œL W�iM%v™8>#B HxÁé{B–Ž˜Î˜†p ºAËÉ$.2&²·ˆí‚ƒõq16Ä» Åæg$8Jí€Þ™“€…0ÜO(àŒÉÖvÔ:S"s• ·»—Îzp£’ù͹[þÕºMyHnõ퉈$/ ·øÂK‘¸ª‚ìi­g± ºóðôÒ¢Ä_¯Šu�2ÖDÜ!üÎ4ñ…jWh;šß»ï5är0´ë@�úÇ…p†ŸÚ 'ßXb·ƒ_�Ò?¬¯Mš>0’hxÄRó‚•!ýrDNÝçÎñ Áöa9!c{šžU8«QÛÅÄeoÖ:{÷”SM®QŠñ®9 Ùã‘8 ›;‚ÐßXB”ó¡íêM>!µ©W°’¾ò�áÍx˜»=Àˆ»;;Â7¸&‚†‰É=9 ’UDV°ªqÎðÓ0áAvO#m[‹`w«h�Õ|fæÒmöhqœf`UVOë%`Þ4¤|`†õ·$ˆë ¼fYöç @å�8g2lKHü�ñçƱçÑ+eZÌz\F¨šêïÿ FD €Lä�¨�n€ r4ÑÔ2¤ƒx/¤5�‹â=ߌ6M8ˆk§¬ :〆’†iÑÓ›÷�i5Žž^L'É×YIu‡*pÌçWñŠ–Î-w2J'ÆçÆXŠ è‘?Œ9aAZ‹å‰¹ˆ-V:+Y>pZ@¡ּΎøÆ0ˆH!°kMj÷‰¨›Œj ¯<àõUÒÉù7$Ú ×É‘|w“ÿ˜<šèÅÁ"P¨x‘½7Ùžóe/ m¯GuzÏ Þ.ùË2£_óÈ�ª•œ½×:\”I+¥Ò§¬8Š=^fF‰ÉŠhá.Ó(Gª °Æ¦Ãå3c¢žT…Üñ89ÁŸiÅŒ ~s~š‚‡²³GÎGú IIzÜÅ~†P$ÜõùÂ:|¸‘ayÃ#=ùN”:9i£)Ò… Ü� HO`¸äCÎLt:×F$„kÁ¯ŒYWDSßyJ�æ…†±èðæ•51Ò ŠašÌgÁ?%EzžC…ó¬£-€îŪֳp[Ë…YÖ -@E/5€ó²p·*G ƒBĆG ©NVËô¶fÅ?.Î�œ¶ ­ålJÑPÛM2ëÅEúd:kïü|ãG†Îp„ª¿Þ4]p™¼-¼>¼Ü—»�2æûÄù–×§í¸¯K��èÂa“�#Ã�&#^÷, ¡>þ7“æ@÷w½îùuŽI0VDp9ã“Mä JkͲcQ3CO`Å€I–¸}Q¥Q«]%ðÄj`ƒwëW“#ËVoÆLX/dÄ,/ƒ—1)Û~0º‚ÕÍéRh|àV¤Î4oŸœA(¢n2å*…Ö¦šõAÂÏØô(ÓXC›V¼à„У@�¥zyÖ2ÚÑ`\y5wÛ«&/Ÿ�€±á¶M®ºÉ…å�É[Gœ]P-îr5Òo9U:…ÜBhó‰ ·Ô¢?¿YJ(shÖiâai:l ‡¸Ùª¯5ÎT>Sœ¼Fî `c¥É°ËÒu�­7‚pa8p¦§ƒxîñzn–ïõ—«ˆJª(âkÎå‡A¦§«>K½¼�òeŒdNA!ÇÎynpgyŒRÓÙš?®iò6�»Œ0x¶½1¤èuårà£V:KmÁUÞðMŠ]ïn¬óë1F…˜•:@p2dpçœÝš|bY©‘Â&.ó”Šð8¯ØGQ-læ15P¡HšM÷ÖÕ‘­•à7Ç\àuúwš™ÃCÇ8…’–¹Ç$MMÞqHX‰l¿—zã%˜ÆªÖ´u0½™( ‰7ïE ` ‚p‰±4à�Ku 9T¸†Gn¦QDÞ#zÞ€¦{?XÜwÌß„Îd5†Uå}â„hùç ޹™@8Nò´ãy§E›áè" 4Uã+k‚a…�« jÀLÈÔ;§ WGç«£C3“ÂS¦W¹ƒ–ØEèæúÊRLBÝ]më—+õbÝ7„øï¶–·�0e?vÐ[YàÃ2%­ G´¯qŽ™€& �Æ |85Úq€ØE8Ä€lXK¬FE>L�6S™�ZÞ/gÂþ0çÈs…7„œiÆ £ƒ–ÎöšÖ¶ï3ùLÚ«´Óšƒ ¸Ñ¸4¯#”%-$± [òœ´^3tòlùÆ–8çävi¾3|þÛ”+o.§EÆ‘jƨŸ�·YÒ�C:S?ñ“É»ÒÿpG_®%‰Nß©/g8pboœKïç;³ é;ÊwÃqÐÔ4„ê@”\­ÐÆÜDX õùrÁbQI6.ÞþóÄÀHm´Ô«|hÂC Á»Á©ê8rHY6í|³œœV‡'ÍÆVh 7P AÈõ\ЧØï÷ƒ¦÷ˆðK ”áU�Kä´¿œvú\˜çчå”ï=Y9{[Ñ‹¥I€›ªòlàßö Ðóq)ásŽʘË—=ñÁ¦;%n:1]ᢺªDélÃÚøH¥¥k^?Xõ+ŽÅØTØ\αTݤØ19r«Æî?Âiœ’¯Læ4 VÙÀbcò´{Y¥%ÞKˆÛ"TŽœž²tº¶ÊM¤sÊ`7Ä´#w$Úv—œ]u®½åˆî¡†Ë­œ7è!ç ƒËÞÏ™ƒ ûÀë—|`“�rÉÒãB¤W±Ê ˜ö&”A(×bïi–HeŠq- Û?Sî) rÐiSµ“ " -YòLQ¢RØØ;|xpWº÷+iK‘wÖ%):”\£ã@'~Š ˆ.0ý?DRZTÕÛšÎ]9 áuÞnòˆßÖiœç¼{k.ÀÑ”„ãLƒ-‰a”p2Sáò‰Çf%kä¸{ÎPG‘šS–·Þ8ÑÁ “Õ8àÇ@ªÉæ�^}fâÁ R@öÍïøî– §V½òh)pµç…é‚„â…ÝÀWFî ¤ƒecµ�¼óqö¨ê"«�A¼R¡. Ȥ{¹´4ïÖ=›0y ùÀ3÷˜šÝ÷Îfï�üå¥yÜL˜¿-�ˆQáxÈ„KéÄ}‹,H3xu´R*-K’0L†ÛûÁìA²l1ê@Ãz¼`pSµMÙ�*5\¿L\ƒ!¯œG– ´´?!ã;=ìÀ^oþMQþgî9Çé€^2F�«œY‡­10ÛÁœŒÔˆl3¬× !lisÆc°ù{ó‡9&ËT¬0ÌõqÛð_yÞ5{k/ú0,ÚH¨ïµ÷ŒäåÝ—Ë£•“G�9ÇÃ´É ŒêužÏ9ž#ϼÝÝ®Ç᜘wŸß(ÙÏœMå|â¾zÁgorÀ�þØ€&8=9»7ªé~°�€äÞx€æýdž·b·£�QÕp2. ñ�1ÚQƵ¨¥Òâ@M©ã÷ Ë@�—«^‡>A­ìËÙ£c7ªVM®ÿÄ*!1"AQ #2a$3ÿÚÊÊÄ%hçã:°Â¨+ƒ†ÿ�丫 H ä$%d—^d•'ÉCa'¾òûÀçx÷‡÷íʆ' Š œÿÍj†á›¥.]AZ?µåûò$Öxï �j̤(¦Sküg n8•‰Sf¨žª€Þs[¬';ð áÿ«ç/ƳYy<É rvõx$R‰B3xÍßÇyx=Žü2Þ3õœ ö]V Øm¦høbñO±�zPo#õ)Êöwv&ú =ˆì<^^pt0þ³ñ…Žõ ¶ˆ•GÝy¢@ˆ£Ø¡çª¯�{VVPÂk¼äO—dè§ì²$ŸêEœ¥o©Päžd…"•Þ³OET†aЬ³—ÖY¬$Ö>Ôk@ío°ú õÊò ¿ÎJ;^¢ñ±íLÌ ’S0ã XýOxXxËË8èFV09ÅXç¼ø¢7|çYfb1$~Là�Wš¬azQY_œá”yÍ™’Ë;L$ìƒÝà4l‡ˆ*ƒ’/5ãƒ]>@Æ8••¤â:aßC¬‡°÷8|å8p0ÂF/éî³ÓårädEHËÀk,{;*ŽýSæùŠH×ì?¡ó”nÅ߉y(°>`o�{²q$(Ô_�8àn»/€œÖo„—]‘ÞVÊìZðr@G…Œ�ˆ{ì)0€p0å~rðô/:ö?Ò‡œåøÃ„๸ä7Ö›;`ù>0q¾ƒíê�Ì`€Ñ–'­Øij‚r=ß wߌ¿síßµ`Àý,xÉ[>0�ˆˆIÓ�_ê}rÇãÇbR¥iàõ9@(&&AÜËÅyç Þx“ØUjî³ÀÅ7ßµá÷¼/õ Ùã˜üòBh'ÔÙÔ…PÚ(³•YµêPÁõÍý¹6Øq Œ¥ ØúæÏÿ/°bRÕ@ò(Œ¾ýºËþ×íʼÝÿF îÜ Fó’¶+¢·ÛP ªß©eøÐ±°Alvb{äÜH+ÚæÐo„ HÊÞs5A~©5—ÖQÂük¯Íå`þŒ/¬u£ÑE¬OAÿY£´cn-.ÂDœÛÔw¤"1n]|iU‰!RA±ŽC:*<å‘Öüan#®XHUƒ yxÒ ‹|„åeg@à7í$Él²+‹Y¸’0l*®T~…€%Û3ÐÈí”p¥úL›ÜX„S”Ã#°¼èÇ"ºò}¯�YYv1h œ¬¬hÔù¼{¿cdd©ÌVA‘ÞJ-¨Ú ÃqÄ�cšŠ�KÎlHüË_‚i`dÙ”FÃŒ|2ËSnH!Šô­c/1b û1M¶F Bñò1W±×µû�•„÷�*GÛ�ípr=½v=rýHÎXBÇ#Íþ<žW�`ÚÃ#FœWýX€¿$#”zÿÉš–R¸ºê]Œä€+ô¼¨Y°0åY½¤²Ó,^—?2¨Tƒwi �ÚHýw`ÿI/‰§ÞŽ9V'X¢´§_Yºê¢J¨° �Œ`�‡Z3Ñ¥�‰I6˜Ž—\rèÆrDäEJõ³§ù]I'-ñÈ!L…TçÇÛ[_æ�.múp¶#h×íühl Ž0­`FXSò}Š=BÅÖÚ}t—‰*_•uÜì0°ü¤ŒIQ9M7¦Â–°Uqx+n¦ðIbš)äŒýuJMÁ Q© ±‡(N¯ŽÅ2x#g?ö:9Ê_Kj”©žâ`Nó,†ÔçYÿFXÙ•BTQŠÜH9$|Lhd§ífE¯�­ä Æ%,|Ö±VÆK ùÇ×$ mzºãG=4žL¹ %I;d+Á ŒI*žÝÜœYç_rkÁí­ ŽK,« “é�ƒË"¸¸Bg@ÔI‚ÍâÀF–$¶°=¥‹ê ¹°HÍ�Æ 17‘·sr`Wy9tv%º¢VnL0ô1hõž ²ù#K=æƒI$à3±¬� ‹>¢ä@@ô�“ÜG}9ÆQ†G/5 ,ã'È8“ E<_n¥cS§Õ&åõ 㪟öxøœ*·‘DÎ@zÁ{i¤â(~òI�q]ITõ=2$ÅÛ@ +�-Û'ä$« ÝÓ19tôԢ͑§ÈÖOŒÚRиò˜¦VÄ ¨#_ã—’út€©LV$P–Tˆ͈ÞEïˆ GU¹B·²xLs[`H)¯¼=çÄ24Xú J dÎ.ËÈÎiH�q›*$õ(¢Ž¥�h5ä܆©#Û‚SIêËø‡Ë j3:ŸŒúŽä0ÇÁý8‰"µU (”¯¥UXÐôÙ CÄïq0›ÖúÈ,€E$pª7#›Ð÷]3Jzœd²°Œ�A:ûúkî½®²[ž!ÁÛÔ 3»á#ÀTbÀÐW�<ˆE!>3cZ7’ï“H & Ý؈ ðÌ侌Qèæ+'bݰÝL´íš;í ©ª!4­3lMm«+yÂ×àyÁG¢e�Ui¦š=€qŸâIÄÑÖÚ-Y,©–m‰NÁ·X•|úb€zÈ!€pž°/ïóY¼ô><`8ã(ó€r$S ú-Íô*.cḣ²pbõ1©ëŒgŠÓçCÕIó‡>»…B«ƒ·�…¬[ðõ0Ó®P_Û+1g{O!¶øåü@ô\ûœXu|íþLwTùË üm¹†P£%›œ)XµF>A†|E"É5©õeár¹qÐàräTÿ'0öqu’ÍŠ&â>×_’ƒ�ÎK=×ÁdË~–K,LžÃ�u]VÕúåŠ}IC­,Qã^øÉ˜Ö^ºïØ*—Wï†Ò> ZG)î'.ô¡T* Jª~µEÇÙbÿ—qJ0ÇˆŠ•\ÌK'BåǰÕ{˜¦|†_4ܸQÌßËl”<_àòß5-ù.¶Сó,Ê,˜Ê¡½Vzlø]¾«×4T¾xe ¦�¬]ûd„<��‘|îŒF&bp¹çt7(ÆÆàuÏÃÜS7ÎËsgä;—É Q‡*³|î¨[rÙÙtð7>Öl[.+1Qž]Žcl¯y÷hYY*8cžFÐãžÆ4üP¥îb«*�¹/fÎ7Ït]z ss‹ŽHÝy¬ïë“˾.žÞ‚ÿ¯!åqÊáϼÂ�Œ6ðÏþ—?‘â¯sðØ¢�ŒÛäâ)Oóû0¸ÓÀ¼C\4oc§ˆò¿®L¶ÈYßCçšÍ $Ø[æ…›…aFo±ØßGã+Žý1¥ØÝhz>Ý>9,öëØUÛ®á•�sø8{æµÛVå–›½7ëäÜØ¥ü…e&ÿ¬÷¯¥fü¿gÿÄ,!1 "AQ2a#qB0ÿÚö0ìT lKßì½FUÉ£ÌùsvÁ‡“�ñ9GaÜ\Ø•¨/Ä ùŒÜñäÞ±ã|¹(ÿùýIÆã¯âGµ>3ïPöŒÕ;��ŸRË›.EÆr*u9�"ÙÉ€ðäê^T<ÁwA¬ Q`Ü#ö˜Ù¿¯§úfn^a�1ÿâ<ž&UÍ“&WÎÆ?¥kÄ{\¸a¸ÌD�޳Pqrü„­š?ÀÂâ‹ú?ô=;�ÇA˜ó¹#3¿÷þJÛDÊ•p �DôML¼rùx~˜˜�fOVf/ñË Ñ`/LÝ\@À‹ö¹p\½@oË7è82�‚kÈ=—°î½m†u/ÖøÍ–çú“0ê�æP"P&Pº€ncâeÉ}x^’2ÌÞ‰”0S“Ñ[+ŸèI› œ¾ŸÀ\cøøÆÁÅøÛÕqª�–0³sÄd,uð©¿Ô¦$ΠJR [Q½þ<üy°¹lNÙ Û3_’goг6³��ó8Tâa†ÑTXª”Ãcb‹ÔbÍñ·hyÙN>³/!²žÎ[qŽ·²(÷È!ƒé¡wì Õl0'OàߪàOŠÆU`ÐÜ"QöT.~ßGL'tÑ6ÔD:»´íÛ~çÌ?ï˜Iö¤’!ñ "}õ¼h1‘K2œXÖϨù{›�(ƪœ.ë�Ypã\ õÿV…N¿ªªŸô5íR½èBÕô ï蹨F§c[Ï…Þ¢˜1é…ÀÛ²X ˆ;š_Fø‡"œU\ °*Ä'ô>~­BÐ}x‡p�²2aì€Qâ61ز}Љwç ?`Pzg(\¯‹Ž˜E"i…�mO÷ØKú._ÿ�š–È f²*“GÔr04ì@†Éœ?IÍœv>›ééÅS5@Mø‰eÁ%kÞý€úÄ©»ö©R¡ M*hìr²9ዌ¤�àÃòdUª¨*„#[©�mÄ$ÃõíR½Î¥K�âT7æ � ÅþÂ0Z€£\›9Ü%Ë�²áâeÏ—ã_Hà|äȵB B¿Ô RnÁæçæyŸ÷ãØ‚ †T&cfA0hQ÷#öæžÆ5gú)Œ¡…N”³‹À~Æ6:&ºYt¶˜¸�ÑIÇé¸þEøù:}¹°¶6êÕ?ÙB*Ø•¨PA6NèJ÷¡?Ö·˜EÇ£¨1Åã$DÂYªdátb N˜S„uŒ.àßEL8°© R–8' §*( ¸PE°£î™Sã 8Ü`ÈN²–l˜‚f 3*öÓy†kØ{�BO�ƒ%C�Æ�Rf5·ÇÚdfÄK®,­“(ˆ¹*Ž\ä3h¨·Ç�!§Èrñ�…Sò(0åȘÙÜéke…ì!£3Òçœøm_TÊéÔ]€Hãqßs2ª?PJ@¡æc°íð‡£šûVØyÂÁ®Ý­A Î@‰ŒçUR8AX†/ÔO�³@Úe4na̯@òøJ˜ÎUl®ýËÑÐ[­L8QÖÎ\J¢ÔãoǦñ0äÈF^£¿Ë/^÷^ ±ú1‹a|ƒ„`¬yUº‡�çîÅ‘t<ÅŒhhŸ¶zgTì¼ÌŸóZü¹ Âì°l¶NÈ;Sc�ù1öäññfýnAàð3ÞÏ ÑGaƒýª¼VO&‰ N/9¨ü˜_åo·çä" c圳-žÊ�˜­läP¦†,퉉¯Q,Ì“à ¹ÉÊPuN/;6âff²Èú…õ¿xèõ|§lª»³n6Bè,äý;a"ˆË/pâ_P[Æã�à‰ÄFOµ«ñìbäb`â™�1ì/a´k"aaÖ‚°üº¨rFf핌Ûâce¨Ìyšª/ DÌàÉ©êª)7™Æìl/ÍÔSõÆãA6$;Ÿ Ãä'd ñdœ|ŸòP)®‚¢ÖÇ-T@cn}�ƒq` Gj©µÔFoä•,ÖÄÂeK0;DÊjâæ$o›•²2‰”Ó„”½£(>_�F×äÉ�ûüªÃ]„7¹›.2[/r Ⱦ—Çʪ~GÂWÀCæÐdb.àçèB Lg¢˜€�ÆÙß'ìpF¥Å �5Ö�ÁØ—)U;ŠaGø”½cüÈ|äãvîH¹øåægJ¼<¬x2)ËÊ͇'_ˆ·èoÁp#d±@-˜èPÔ B#U(Ôh�fùYƒ�3‰ÆÍæ:²’¬|@Oåñ»›™8워ÿñE²,“BÉewÂ�­ÎK-8Ȭ-¹8‡R§“Ž˜äÁ…–j¦§ ÷ž@ÌÁ‚¸­®Uº�� äcò3ª‡%=¸ãÇû—&Q“!ÈäêX�®)±šV àåO˜ny€KŸˆÌ?Ë—èE· ,[,ÅÀ‹ö:ŠÄèŠ'`.2þEŸjÈ:ì‡Êb"GuPˆlø>%PŠ™ªóì³ä"Þ‚¯V²¤blì$U&0P6H¨ <ˆ ¹bÌm\-pû2ê0ÕʨͽŸö£ùû¾%A½EêRÌÚÜ:$” ÌÄBL'Û°Dø#÷£¸Â‚\¹—ƒ§º¨ä�Áà˜ ˆöTY¨Þj5*Ì¡p(Ûÿ  ÂF'iҪܜ]S´eˆu†TPC/­�Øù�«sä7Á�gIÖÿÄ.!1 A0Qaq�±ð@¡Á"‘Ñá2ñÿÚ ?ÙÈ _ý ãb2Ü”p·5aNÃfx,%õ iþ"ô¿dõ_P0/®Š0á;I>J1½Öó’“¹û,7ÓžB ¶AÜëÀ&!XO¶ÌÍ ²1+U†çó½@=sa²ÒátøW�õ÷Ü¡ÇÁEÈ"ÜÂÅùm2Ö¨BPË(æP¸žh^–¡”uÞŒäj'®`‡>h:×d6a+ eÓ² úTzKÕ�\�´ù[!ô¥—�2]aüˆßMž¤yÇJÀî‹“êÏžËÐ]FO#ÓÝ_õÝ?*ëý;kìL­¤©' †ù)ØŸd þå½7TQ²eù+ tmÚ€ÓÅbü÷Ž«êµõr¾¨#pŠ>-[¬Rx.(º‚V·ۧ²¹A•ù£*ð˜áå=“|þ•›«Ò lQ�”Sê�oê–O–È»!š(ðÿ(JÆ&Ú¬R¦šW o,¯ÑÙ丬L±?JIÑÃvS’ËNz,4êŠblxg§~*xñÖ†—[ÂÄàÉcrñ�Ûˆ,a#‚ÅÑ9fE�+ò Í}(ÇšA!‘e(°!�œý�ÈŠ,QüÀ¿±àö⌣P�*\Gñí\UЭÊùÃU½XÆAAw®WC ÕKðŽ](±7Â0)­ á‚(Ch®Œ£(e7øV¦›!¢Š* ÅAPøL–d3˜Ãn³]* «Œ’7Šh‚l®Èç+ Ce1[îÑ%–©¡¨Éªm�FÈß¾‹JÂ(×JYXÊ22ÜwZVõÓÁžÝ³Úš(FÕ Œ á^º(;wd¿dQWÉ„GOfWAÚµ.Š2£uaB¡©EÛ®n›¶Ò–AΞ †ºÐúSµÑž9‡¥6Z®èíÿÿÙbeetbox-beets-00724b7/test/rsrc/empty.mpc0000664000175000017500000000422415253035401017644 0ustar pieterpieterMP+' \@”7–sÌÿþ ÿÒÅDfÑçüÿÿÜ3Ï?óÏ<óÏ>÷Ì>÷üóÿüsÏüóÏ?EDDþñð>@Èñ_éÒá @ Ñ @;8ºo´è€€Þ ‘ÿE¾|‘_Dä¤È—DDDDù""_ˆˆ|¾ˆˆ""ED""""‘""ˆÈà‹ˆˆP 8ºÑh ½Ñ�¶mÛ¶Óµ]×KÛ¶m^UÕ6ª^õ÷jå/ú{¯ª‹U¯¶m»ò—mkšg{¦KÛ[Ú,H’³mÑ¥çç&ŸÛliÛ¶³smÙ"Ò”(�ªº­lu~傽ÿÝgUÝÓ·õ—U÷U±o Úó5„4ÆiŒß@N¥jT=�’¦SÒ©NÿÿÐÿÿÿÿùD&¼|�/]à½|_þÿ8yèÿÿAWÿÿÿÿ˜üúÿDÀÿüCx/þ‹Ÿàÿ]ÿÿÿÿ@bòÿçyŠÄáï1øëý�Á!ôóé€?A_OØ�ÿÿ?ÿÿÿÿ>Àÿÿºÿÿÿÿýv½ä`oôôyCÀ�Wì€Ážpø öú‚@ŸÀ§ÿÿAWÿÿÿÿЗüûù‚½À /觇~¿žÏè úùv>ßô¿ÿÿÿðÿÿÿ®pñÿÿÿƒùÿÿÿð2."âåß?€/¿‹�ÿÿÿÿøÿÿAW¸uÿÿÿÿüÿÿø EDäÿD@àwðÿÿ@ÿÿÿÿçÿÿ?è ÿÿÿÿtù“ÿ ò¿€ñ "ƒˆ|ùàEी|ÿºÂÿÿÿÿÈ—ãÿ ˆ€�ÿ䀈ˆ|¾ˆnÿÐÿÿÿÿâ?,ÿ" |ù ‘ÿ;€ÀÜÀ€mSº(›ÿ þÿ9öŸ�çìÓgõŒµõ¼ž³|ΟßKŸ÷ñ‹ÀDDÄ"m›vù´kÛ¶Û¦mÛ´ÛvmÛ¶mÛmÛ¦]¶kÛ6Ðà 8ÀxÀРhÐh Ð£oÀ¸Àápи£poÀ"Àá" """""‘/""ˆˆHˆ€ˆˆˆˆˆDDä‹PDD€7€íРð@ènt£ކÀèÝ�p´Ý@ÃÑ׸mÛ¶k¦mÛuÛ.]Û¶]»nÛ®kÛéÚ6mÿÛvÿ¿ÿÿÿ¿ÿßÿ¿ÿÿßÿÿªq*ùN%+ªcEU5�Jª ’ªÂX=W£ýÐsÞ!§Ðçr ýW8yÿÿÿAüÿÿÿ?ˆô^þ�þø]/àä{€@ÿÿÿÿþÿÿÿÿÿÿÿ´àÿè]Ìÿÿÿ?ÿÿÿÝ tŸ£ 8€�î: 8p4tt ÿÿÿÊÿÿÿ0ôíƒ?ß 0ô?Á¯øçû…? ° ×ë ]Ÿÿÿÿòÿÿÿ}Ã__¯ô…»¼ï×èú|‚½q0þü‚¾+àSÿÿÿ þÿÿÿaзK}>@PÈóñ|{<0°Çãú‚Á_PÇ…“€ÿÿtÿÿÿÿò»üÉùÀ‡ß/_ä‹‹€üΠÿÐÿÿÿÿùò'ÿDäË�/âÁ Èù "cÿt…ÿÿÿÿ‘Íÿ€|/_à äË�/ _D{�ÿtÿÿÿÿ€öÎÿwhÀ@Ã�ÐO¸ÿƒ®€ÿÿÿÿ /ùÿ@¿ /8Øûýx¼�//,ùz@ß_±ô*|=.ÐÅLÿÿÿƒðÿÿÿàÞs€8€àáð ÞÀp à AWPËÿÿÿÿ°üÿÿóÔg¡ÁƒÜwðÀ|þîÛ§Ï{íõÐ_>âûoŸ?úÁëGŽÿÿÐÿÿÿÿñß@>Hþù|ù_ÿï¿àÿÿÿàÿÿÿÀÌd¶mÿ`€ÿÿŸÓg“çúŤè[-3þ!‹rtg¼¼(ι¶q]b¥¸úƒÄPEÙ€€ ª°DãÙ‘>JUl3ËA$Ö)i)ƒÀúƒÄA#�€+:3ï`Xa¶™˜ÉùQ;«À±˜ˆèàöƒ¢" „Î Ž× óf{q wZ“Ä 3z¿f#)NÙq'øƒ¢" „kËr½ÙÖ£ g�§ý'”ê )y*¦˜Úö»,°Îµx¡úƒ¢" „r †BXVFìì7nhϦNž|z%ôe0Ue®«Œ œöƒ‚B„_`9åo¢ðJ­Dz0¯)òøáÛ1F8‘ú·åÉ>7t·#‹Uàøƒ¤4#ŒXÛõÞ™¾áàÒ`¸Ž‚Þ×xT†aGˆ~fäHv<ý¶ÁÀúƒÄ`? &ˆ×63Дl:äGàë’ 莵š„ÇÓëåN‚àúƒ¢R#Aש9Ï<³ÔiÇ%Öøê¦—µŠÍÎê®yfžÎôƒ‚T„ `®!�I}uhnV$?‹+ä¡(Z«„Á�¡Üta¥Vi±+±l‰8úƒÄ3#P�0¼ñ•T`’3¹èžÓ#?}¥ÕõÚ»ìÔ‹€úƒ¤Q#Hl`µˆÁ½¥ËK§)Q)E‚ñõ>O²Âô¯SÔ¦úƒÆ"#P ÛdpËŸ¿Û2é­~sÛÈÓï�'Pîì=Í&ü!úƒÄPG<Ž0NÝÍ�Eø™_ƒõ'1…:õ˜‹å\øƒ¢ ˆ,l ƒq¼Ôº<�¬>èðÍ&ïÞ¦J3}•]dQ€€8úƒ¢`F  8I+–¶:aá–;0¥Ç>m>;ßM¾íÛ�Ÿ× ¥/gøƒ¤p>€ÞbSci›”¤L z:~H�5ƒM3©'°A+è&„f ‡Ö(pöƒ‚0!dÀ¢’¯:%¢C°9B³î+]þ3Z†¹ècJr†Â¶�öƒ¤`E€�a,]µ)\BiwÈ,yç@úD¸ù�ü'ħ¥¨Üøƒ¢ ˆÐÀ€0qóà=bžmBÅAwùH°×! šDSª� 8öƒ‚5 !`Â4†§å^ñíª^:$9µÏ…gs`M%…ÊZZtª^U£Y(o€úƒ¢"ˆ¤09œ’#NÑ·#̬zÚW›;t A-1dyß”3¤^ àúƒ¢" "ìFâwì¼ú„,µ¸rŠþ¬js%”ŸÒísÙfžep=¼øƒ¤`G €@ÀãÒ5?à¼`•Ø�ÉÍM²ÈöÆýYB^×;C€øƒ¢`BÈ ÆãiRø—‡iéŽ6ˆ0 9ü¾åÓvë…(ÜÿÿGYJ´…=˜¢oçlÇWøƒ¤3 BÐ3ÜQhLÖÆ$/ê‡b<÷~³µ8ëûÛΚS�­n*jõXeÅ×7’#àôƒ‚"(„@Ø Ad¨*Â`óÙ'ሬÁ®co·>Vûça &µ% øƒ¤`F‚ ¢±äßxã}¸<ëÊüfP[2ÚqXä.Š'Iµpúƒ¢" „¤*ÓØšÖ'êŠÇÉR™z[oÝÓ¬ía‚„¾”XÇS2p'ÀøƒÆ2! éZðÞx²µ¾ùìú$©¿Vn´%j(óVÀöƒ¤`F‚�€öŽ�F†@›c}}ðCÂ2>Û<ÆçO5£!¹QÞ/grD�ðúƒ¤aBàô‡2‰´S(^®Z�dð{¦P�¤Ÿ~‰ÙÛ˜¦‘6 Sºœöƒ¢ „,`¼-1wNÞAÀÍ”XPKh¡wKÛ#0R¬Y±X�-Àøƒ¢`E� "ÅImq¤>w¢È1s5{!ÁXº[¯/æÛ?ÓG�¥xøƒ¢2"%€Xä  aÔž®ŽæÏû©ÆÏç¿÷º�r¯˜LaÀƒì\ªRi"?pƒì\¬ „ô@À\beetbox-beets-00724b7/test/rsrc/image.wma0000664000175000017500000005776115253035401017613 0ustar pieterpieter0&²uŽfϦ٪bÎl³¡Ü«ŒG©ÏŽäÀ SehÄQ€>ÕÞ±��ÐtÐÊ› € € ôµ¿_.©ÏŽãÀ SePÒÓ«º©ÏŽæÀ Se"êËøÅ¯[wH„gªŒDúLÊ”#D˜”ÑI¡ANEpTÌWM/Picture›image/pngalbum cover‰PNG  IHDR6ˆIÖ pHYs  šœtIMEÞ  J™tEXtCommentCreated with GIMPW�IDAT×cüÿÿ?‚9Ñ…'IEND®B`‚3&²uŽfϦ٪bÎl,@¤ÐÒãÒ—ð É^¨PÛWM/Picture¥timage/jpegthe artistÿØÿàJFIFHHÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÄ ÿĵ}!1AQa"q2�‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2�B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?’€?ÿÙ‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104$WM/BeatsPerMinute6‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aTRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aWindows Media Audio V8a6&²uŽfϦ٪bÎl2K‚ ]“‹„ç ç“ÿ@ ÓÃÏ6Ó‚}mà ;€¦Jà$´æ“$�Ü$›ì ?'qU1Ù1%¦4©€` -I$ÀIP�c Ô I¨�R„UI10U5R’I‰¸IjR` Ù$Ę@«JTBTÓI¥1,E4” ¦”�Ò’ÒÒ€I:¢„bf¥1&C›°` �³QR@H@1Všˆ`šˆ †€H “:ÓP@¨þ¥�KÌI^o'�»@*@˜7C²@ •ÂL À$¨Ä %©--¦ši!T€H””¿HEPùj�H@&B4ŠJJÁóä"„0Ò•…ý Sƶ°|µALU2”’k?ßí/¨/ß¿¥,B(âýqôŠ1BÒÐ~¶¶š-ÜKlø¿!+t„H¢�„„å8� H¨‰¡h-Ûߥ)B Ûô-P_”PVéCäQný"—év0{eýIBÒÒ�ª¸�V‚i~·ÆüPè6òµA \@ÑÅA KT¿ÚÛëpã¥k‰¿, ñøRѤ ­¿vÙFPµB(âó^®oã§�Íù»yZÀUÁ”P„ã(À\KYFP…»}¿÷o¤ÓM–Ê?_¥ Rýmøâ·> ·× p?,£ŠÝúð´à*à}Æý–­ËKx)~üþ°óyKïÒoéãýÒ±~ìù¼§(ðƒïΚÆó\yïû§ó¬sXß•?´­-ÿµ´[–¨}BÞSJÒ8øÇ‰9ïùå>Á·÷úýqº_ͧ‹õE¾±øÿ'~ú—è·ÑÄ·ÙH¢š_%úiÝM.Ê]ŸÙK°´V²ž+sô~_§`;t㎟ߛü°c[ŸOšã[t-·A¥ ·?ü¿|T>¡ûúBÒÓêr•¥¡”­ñññ-¿ý¦ÞýÙ·[–Çý>ót~¿'A·Ð„%lÓE(?º0çÔñ­ºi )·Ûé¥òßîÞ·C÷ÉnÀ@­å4qºR#)O½k(ZvÏ¿:< ¿ÊhÀT"±Ÿ-­­y¼¥6úr‘Å@[Á*�XÈù­~뫈3Xöü§=ÿtþ¸¿\n�ÇÇ‚WÜi⦊Æ=©(Y�XùºÇ[[¨Œÿ)ýùº?+{ !öt½/¿Khó\võ³ÇO„Q•+yÊ-�ÀU�‚[ucåYò[Ð0òøqà?5€ÿtà”¥Ä\úÀN‚‡Á§`0þ¸2š2•¥†{Qàx6š>ÀT—ô%ù¤º[þðü_y»{ˆ7öáæí�·ñe)Ê_y â × ºØì¦šàâºÆ|NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç§ ç–ÿ@ˆð%,V,XU2¼�ƒ¢ d†´µ°DôZb`°D€« ’ZÒÄ’XªpÍR/¸I… &`c †²X¬ÀH1…$Œ)1´ÌJI,¡•2"MK¢ ˜A2¢B`’*!&©JADÕ€ë$Ši�–„¤‰ E&®‘(hØ+D¤„¥!¤Á$ˆ‰``:–h&FÄ꤈¸l¶¶ ¬Üô�F”a؈…E„–¹‚Cv[0¤á@™�˜˜00Š&¬“‡)EdìEB��MCQ 3P ¾4R EB( ±JKô¿BPPB0è@„„[‘M/Å¥‰ Û¨J€°¤¬Rü¡`ËTþêOT©QcM¼�°–¿-ZZ¥hÒý nÊ-ôñ:\kaúüÖÓùSÇÅæŸ~¿×OóÔ~Íp; yHZÊ ÿÌ¡q!ÒÆ¸8风ßùÓG®/É ¥¯Én‡ïÿkHóHÀ_µ¼ýõpºZ…§ÂÝ”ºSÄŸÏóãüߥm÷xÂiÊ_;t8ˆµn®§òO8‹êÆ}”ñ~¸Ðit²ÞSŸ¿[¬`ÿ`ª¸pD†¸„såBÞP_× P”Ö=Ž·BÕc'(ã�Õcy®'ÕÁ€ÿoè¡ÿp›cóåÁ^vkL£þ_“÷KWQÆ·‚WØ ­ÛŸ×ÁV}F §=ð_×ÞSBÕ4¾ð‚,¥(À~oóÁ*ÓúǬlù-ÜvǾq�NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“¹Œ„çÕ ç–ÿ@“¹Æ_­mšVÿ b†­°&6¢ H7#@&RI($L™&ú»’@(Ó£" h&gQ‡0c "`éì “†2QyJB%,Dš€&`–ŠÈ¦S„ 2Ì@0’i jH”Ã*J ƒ˜1 (‚i¤”  $¢©Ê ÂJa0BJI%�¥­$X €H–„ëD§ � X©³B «-#@Á!¨JoV ]G@Ðc¼«-TËNÉéªÁ³ ±¥†®˜ªI1Q‘¹BJ…� LÁ’…€À$˜„îši¦¥@“JÄ- .ËôŠQB@~„HDBÕ%4ST�(@JIJØ¡…¥�¡òX¿DS+eóä!/È~•ºBÊ”#ö´r¦„QNâ}Jj—ÁÛ¿·­ÛŸÒ‡Ï‘@vxŠ-£ö4>~mÅÛ-SÄùm%J-ëU_qþü)4&»)ZVô‡n´·H~·ùŽ?ÒVŠÚ?'ã(O©@}ú®È»gÏÒx�·ùÛ­ô¬V�húâ yíúâÍþ5¿É¡a€é·þNÚœ!mú+ŸÝ(óKÏ’HÊCëzVÈB?YHâCÿ4û�ôûЏO›¥mb�Ë•½Òïíß´Ž5¤¾OéÄ>SùÛÿ*P¶ÏÉõª°Ï|€©ókvî%¾/αè¡8Í­Sû§\täKùþ‹¥óÝëq|·B7K­WOçÅÄy¾#û}ùùº_£=Ê“üåÿ›Z¥o(·Óo¬zœCœ÷·þøøÖ¸ü#žÿ¾$ÛÖ–ðéóúÓOšÊy¼rŠÆ[Êx‡šûÊi·×QÇû§Í[¸ÿ!ûü¿^t¶{~ø––‡šÏl‚Kupeµù­QNP·ù¦ªÞ%ù¢ŸÎ¸ ¥€NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç ç–ÿ@üð-TÀ×ß½Gé=õ¶4C $š DΠ&I�:MOü`áÄ´€6 ‚FÈuaÌTAc áA@a@-2E@i0–,P I$¤ÔÀh“:I‰-/�B(, áá´¤¥cRL Љ(H©JMDÉi@š‚ÑIQ¬6  Š†KL’™‰‚PL„ÂJRH4Ë@YP 5€" $†ÀÄ iJH`$°fb`liÌC`)Û¼Àç¿�޶ënæ6€¬Ë ¤†5@Lµ hÃÉ$‚€Ä¦�Š¥`+:H„¬QE dÁŠQA¦…€E-|ù4ýúh B‡ô‹ú(BA@Ú){¡kÍW 8–ò‹cÜCeµ¿ÝEx o)Á1”»/¸«õ€©tÿŸ%câG€€¸¿óvÿ5æ¿o©KêÇ(Ê^NNNNNNNNNNNNNNNNNNNNNNNNNNNNç2 ç–ÿ@b—•aEDØ%�­iBLA2d 5Ôf¬vî‰ �”Õ Kd™ @ :„€&*’’!¤!bÔ"f@‘.%©¢¬‰¨�ÀZ JR a,’CP†! %3U RDI%×Q‚˜ªÂ$HA@“0™(XVPÁ 0�¦¬¦¬,Œ"€*‚°‰@0RK¨вІÔL†„TH‰U% ± (؈ ‚þLŠ¢ÃUkI ͬnTƒbe‚.ÔÈÂT�s!¦éDư€ ¶Z 1`‚ � Ja$¬°Ù k%Ôœ±~ý™5|¤¥m4;jΗéM)$iH ”>R"¢Â“Y ÒE @[¦€Ä)( %ý55–ÖÊ2ƒJ¨·Qý 4!(?·Ð‡ô¦ÞÑ&*>âvÜkOŸ,)BR’µBi ¡i`·JRùú©OÞèEDÒ(ðŠ?K||PýúpñXüD`>'ùN}oãý?Oäè+T-¤Ÿ ·&Þûˆe?¼¢ßúã‡ÅG¸ñRø¾â§óþ OpøUSoÊ-õ(+\h}O〟¿¬rrŽ7AFP¶ÿ">„e]¾[âü‘á,¦�É¥inœ§)â¤V7[Ÿ~¸éE[ø©âGQo|C¥ø�’VÇ¿a÷Q€¿iGëöâÿä]>U¾%·ëeoÀ@Të…o)[[|íèýå'Â%·>óVÇþÎ _`’¸JÛþ+{ˆ®ÁÏtñþíÔ„‹š@óx6’ÿòZ·¥mOïÍ­%kÂ.ŸŸà‘k‰ñZJ|׿+�öSoý­¾£÷æœDqö·æò‹c­Ç÷”å ßy²·ûÊ2šàÛæ©®ÿ’£Â+Vúàʸֲ•ºàÇú[/¿YO|šióTÑOèÓ”S””ñÕ„ç·éin•¿ÊÝ”qÛ‡ínÝáÒr�ùƒûÊi¡6ô�×ê±ß‡mlv{qññå/ß[ió\kYBÖù?4å±ÒµÄùiÿäùBp°IÇù?~µžÈÏn5 œ¥6êÆÊºü펥öQ€©/øŸÛèÀ^iÛÏê‡ùRZ`%ªÆÏ|‚[u¿‹=�|#žß»~Rÿ>J©ý[ò‡ø”-q×óUŒµoÏ5”¦ÝžÎ—·`•–Ê+œš”[–­Ïß¾¬u§mæÿ�ÜNŸ¨®ÚÕÄ;çáÓð}‚QoüÍ»ÍNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“s‹„ ç� ç–ÿ@Äò²AP{õ¶ƒges@� ²ZÕ5¶ÁÉJ ÆØÄ‚Æ„È'´„•Ÿ H5 �„&*N¿ä‚‚’¤T`b J †BRM ’„ÀD/HIª*%t. ˜"ЏA2iT"DH ª™€„’‘†[Q%• Hª-ˆRL€ @hD ¦pB6@À"óe KPI º,DÍB`D@… =ÞÜÛŒA˜UÕdʆb eÄ@D²HiÒBI’�)nä,$JD¡¦—ÉX€ @BL³�4‡È%“)&’”�KúJ%lÓÆH¥ô¡!mÙ‰vÜa4ÑI/‘ ûðø¥n¡¢ªVЊÁ}ÇHCõ¥´-¡ú8Ÿ…¤P‡Í¥õ’ú‚’·Æ„ÐŒŒQEÉK°?°ù ·Ük°úˆ ñ:´-­§�)X>Z[âÊKyO…­QÇKûzÛçÀR•¥�äµEÐ8Ÿ?h·ø“úÊ2—éâA·¾+t¸‚ÊVŸþOÿTÖ„mߢž;z×îØãXÕŠRþ¸E->E»¼±—Ïé·ˆ·¾·›}»ó£ÂÿB„PÿÍ;~%¿7\=¸©£ø_í÷íkò[›ësဩ #=©ÊÚÞ¬ÏÂûu4¾·e."Pr…»}4­­3Ùýpå’›wâ/ÿ+{ünýq-ç½)•¯Øü¿\|x%ü–Ö¼Óçå/«ƒ�;—ÇÍþÖ‹¥�µ”e9C§Þ­?°µnóuÔ۰?´~¸ëLå/¸œC`.7Ï�ýkôégÔWÞ{~­ùGäšáÀb±øÝ/\JÌí½ýpþíÔ­ñV˜[EOËÍ×Mpe6ï[ŸæŸçÉnʳÝk=ò•ªRâ"?_·ø ÍÇ{->tûñe`/7û¬{pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ç¾ ç•ÿ@˜O3  -ð9²ÄÉ×Xá«£Z�¶A�¡’Ö)ƒ:�Õ’T««À%A€�$ªd„!±LA’‰ŠÌD IJÐaIJÀ¤™lˆ¥)% BHLÕ ¢Q%0&ª%0‘I šHX¬RŠQ‡ I4¢RDÐCe IiŠP³‘&Š„S5�$„�˜–š‚²ŠP”‚* e! A;©Ù”š�‡DTMPIh"PfÓ2 ‘†XVy“¶@ �Íæ$À‘`4s�0W–X[$á†HbgD“ƒ½$UlÀ„*$€‰«R’¶DBQBhA4”?&Œ© „¦¬a¿/�šQAD´¤”š"„¡û°þ„-x\‚R*Ð샳IXR툤RA|š_ r‡Ä q¡jßJGJh‡Ô¿¦Š©(·daGHÈâmÄÕBBÕ/¤¬ƒ¶âM¹øZ}VÜ·ÅBhâÍ~IZ)§(ã¢ßM ¡òM [®Ï�­¾ ®Aºÿ’Ý8ö(Z£Š—Ä[ÿTëNƒ€“ûý¿óX Ýnü£óº?/ݹPiM?´Ð) vå®*ë¸B/ݽóühX§õG愾 Iü‚h·×Ïwþz/7ÅûðºÇ ­Û¿vàŸÉ÷…q[ß[ë‚ÞùÀÿ7ù„q¾(â£öù´Œü[¸ð ¿ 0Th·~GÍ%ÿZÊ-þi¬ù&‡ÿ§Þl>[Àoÿ<ý87¿ËÍ¢—öêV¼×€€Ø?ýøGõù"œZeÒø$¥ý¹ý¸Ö7íõpq>q ”g±ã·`•?¬öýWç”çÊú¸2—ÿ´Ð³8·€³Û=ßà7õ�o·ÓÅÅ€­èEcù¬§ò®æ±£�ͺ}¸ðqú ¶ü…¸ ¶êÇÃæŸV™q Xßž® ÷ZÀh‘'äø¸‰ƒjÚÅþ 2•¤á NNNNNNNNNNN çì ç–ÿ@õõ1à E.üÆÍÐwa(,± ­ÇB utL(fcDÁ`�. �‚%�ÉÚI¨€�-”¡ H$�„H’ØI’S&$…RàI,™)¦ZR¬6¢ÄŠ`BÔ”„‚)Am)HF¨(�C&˜MH u�(”ÌÊ�T$‚tH )A((Q5S'üÉ�†ÂAQ¥I”3q†`$QD a·S57$À³-Ð%¦ØÜFØ,ŽË&o­2¼hÌho`…„2I4Èa«’ÈI¥ a楇ŠS‘蔬IªìÕJj!4ˆŠ · $-¥ôBÚ Õ Jj¿ã(ŽFO•ŠPŠV…/¸‹çÉ·„„P_Ë'È¡ij‡îÇþ.$:)âG[H(Z·-:RÔÓÇBÁõ½l[ÐùnßA§ŠÝJÒx–ê%(+@|ÿ)+’]šhZKì%/¸¿e?ºZ vÿÈPµnãÊV+šÂÜé|¥—õŒh§ñ…º€[¸èX i¥õ‘-U¤~­þ$ñ~T¿~µû¯Õc?Ài¥öS”PþßCáNâýù¼2Ÿà­;`>ý¾ð‡R-Î"Û©tsïÐù&ܶÿ)Z[3”¿ÀX%ýq­å/©Mü£öÓùO„Vè9E4å/ßù¤g·›®ùRšá«ùÒÿ(¬l÷|°[.‚•·ÙFUÒùŠ)ÒÈÏj_×êÜ·ÇûÀhðµ«vPµæßWQùºío�ýuÃáX õ»ŒÓ‘.P¶éd~·-׸ù¯6•«vPét~uŽâ'è[“ÅÅù-¥múp.—KìöOêßM¼xA÷ì')E6òâ/š)Ê?#nãvË_«r?\N–}€­Ëx*Ê?UÂø× Ýpº^±Ý-H}XÞn´ÇæéI”çÉžç(¢„eÃæŸþ`NNNNNNNNNNNNNNNNNNNNNN çç–ÿ@ç%ø,H¿A~”’Åð!½�f%°Ö�Åíz ÀXd€ �ˆ$¸uÕ€PÈ- ’P ’� ™©1 ’J ¡!5!µ %‰L€I Œ3 ªDCú¥¨–ja†“¢ª‚œ$˜ `©…T’$–¤„ ´ ™0 ‰ˆ ‡Y(L ™aP2Á-;*j@ É–U2PvÖT@ˆØ€€È&bÉhh €I �Ø´Á*†ZÀº[- �²¡Ä•6I6��É]XD‚Š‚£¬ò�’YC¤¬…� S PxŠPP MRH¦TÚˆ•¤ˆ ¡hJĤPì¾ ¡l-?B—ô»)ÂÙ„�I¦Š�ÿoË ËúM (¡&š2…¤>-%+eb”ñ?ã§Šßú¢“JÃ(ÅÇ/ß­/Ú]—Ë|r)¡ FRý%`éz™Yž4')¢š-ç�"Šx¿Iâ¡úÇÅnÀAñZZAl>}C÷èn[ý-£ô‚´°?§á÷Rùÿ.7õ_å?’+Íe  ¿Ê8‚ßhóU�Äø>ÇGì>À_—ê±–gV’·GçûÀT£`'ß–SO·þÏðSæ²…¼öý?ýe9A£ò|!Çæê­äIn¬d»wëC‰§ôýòÞPµ@JŸåÿn!Ý,µ”-¾ãüÖg_ñÒ_  ”[Ñ\cÍq`*-öà2Šm�ÁR8ðKæ�š[ãüÿ'ùí€ßÖ3ˆ©óO¨~´|"·ù­Q”q¬g_~O‘àT¤V6 (BÞ{ y·?¦ØàJŒ¤[ÿ+{¥�_Ïß-V7êÜœ¥6ÿËŸ¡Æÿ>Jk�+Oÿ/ÎÝÄýó¥¼ÀÝÅ€Ý/ù× ½ilà,Æé~,øF‹xüë(§)§�)A£´þ––¼Ýce.—ZÁ"NNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“-‹„ çIç–ÿ@˜_×I°Æ44¢{ˆ`ÙRAL—TĨ�É€RÆK@*L)H-`‚ Lfgb*T 1 DÄ)0™„IEC%0"0¶üeé@v%þv+"”�TÀ$Œ9J*T‰dDÌJBh%aˆuÉ5)(5!"ê l"©’Pƒ„[´ ¡%ÖM!¤Í I(©8A•Ih5jBN�  ™è‰Ñ æ[T4oa€ïLl�ÑÀ“ÛNκ0fÁ‰$�3¶‰)‘TÅ‚H¨v4B*0�DJ)(Ja"­C@�˜(`)!4‚iJA|²‡ôÃó oÀ‚Š˜tÔ,_ÑJè¡I|„RâùÛSCäÒ�A)|ù)¢”ºRíÿB_ÒJ·n[¥in(¥n—Öþ:V“”>|ú©6íSúL­»)EDÓù V–ø�±ð»z4?|µGå”Ón«s÷Ï©[GJ€RƒÇæÿ€þ±‘NR] _ªÆ·~ø€âJßêŽ4­>|‹u (·­#)¬oÍ÷çEo–ðV¶2Š*üÕ4º ý:RÐRø$~ŸÛ’þ¸ÿ^k‹‰÷q;ZvüKKOÿT¾[¡.�à|h·~Ñ~‰âqö„QX߯ßçn£¸‚âýþU�”q­,¿Í¡múÞSNSùQ”W (Ê?*Ç¡o=ߺ2Ÿ`‘nßNZã[Ïgë\HJßš}”V2ж_-Ûß­­"� ¢´Å¾›v �–¿+rÕÿF±íÃ=ò•§Þmý!5Àò‡ùC±ƒm¹Ä:?o¸“Ç€²—ôþNƒ‚JÇýþßÍÄU¯Í––ÿèüÂ×…-à;cÂÆ)â§õ�Gï)·Û³ÚªÛúmÁ4x +vúÓ—çæÿ.*”¾?¿åV=EJà|û‹ŽØïÉbšàý~¨ãt°NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçwç•ÿ@5øYà J•þ{l¯¿¢Í*ƒ'þX¾ 4ݵ2ˆ€ ƒ¦I €Öl�(‚ˆØCœ8 A’tMY$Rœ3(IK“N’ɨÂA: ƒ,LLAiÔ(&BAÃ2€Ð0PU( “LÕaI@$B+2„’š€ª %™(š*U$Å&I5R€�DЍ%Òì‘%!¨B�‰‚P!'¥R„Š£Ä % 8S!AAAfXPµF†F�PÒ"Û:Ëš¤9Ê�¡—¶&H*–b ¨iB@HBH ÂH@4”¬àUv@j0@@ %‰h„PýúI¥òÚ(¥Ø«I¤…´Š$Ë÷áÓDЍGªÝ?[&•¾7d»4%nÞŠ*Ò”¢� Ïí`…‹þ*_¤Ð¶8Òýihq­¡inÝú lZ¥ÿð´­->©ÅEº¢(é㦈HJxÖèâ[åªSJñ$£ˆú„q->·ÓOï÷o}æŸäKK÷ÿ™E/ŠÒmëOÿ>4SMøéJ×ìeHN¥ú]ÝF –Š?5µ«sëz_Ñoói âBº c­›}pùºP�Óñú¥Ð+Íe#)üŸŒ¢Ü´¶ü¾þ:ý McÛÖÐûŠ”[ÿiFRµGïõXùíOäŸ7žé Æ—áÿš[ã ãZBmâÝû·»o5žä?ñ'õùþo¿OòŠp?•6ñlzkR‘æÏ們Y[Â\DüËêà¬t&±Ÿñeå¿Ë¾ûÍçµ.–AÊk÷›t³ü"þÞÿôx°é÷›ýù¼÷/‘Åùà.?×å€ÿ\IÊ-î—[¢Üÿ�àðŽPúšÆ}Io>L¦ƒžô×Êû®H×ÉÁ/šÀUÃ\5�ù`<£xBŒ”~ÿvÇ‚éoÎÝ€­Ø%t¹ÀN!ÿ_µ¯ËÂÎ{eíÇZak=‹ìHNç¦ç–ÿ@bð#ÕØòsg¡uÍ"HÚ›]²ËÃ&;b&#`�™�¦‰,n€h$Õ«±I"%2C̘ Âpà5;� ¤™I&jÁhh@I-5¥0¥ „HJ" ©‡EM”ÊHÈKeÕ)(4Õ‰TH"”dVDˆK ¤B@NA¦fU€�d¤‚RN’dP–¥«B`È„¤ÄˆI %’Ì&\’K"Ú°7 T¨lžî…XK™¸HøcR%Q¡…›É1 !&bZLƒ@YÀ¤“2ÒHJ*! ™šP±Á¤¤¢“ XÒPL>J""¡ „�±4ÐE¤Rš( „>4Õ4¦‚�ùlñÐ’°©Ä”Rú i Kô? ‘ BÓõº2˜KñRšh[âÐJVç(¾¸Ÿ~ÎPP„~Ëêˆ}o¥ÙâD”¿(£ŠÜìRšÎx�±|ì%Ðic\ XŠGR·FD¥ð[êÇvÔÛËô[ÊRì-ñþ’þßBQGíij_~O�…º)Ïk}?°ù9M5QÇo¡Ø~‡é¬z´¶´ýñÅGä< mÏзÅot¤óÑñQáúMâv¼(Ûßþ¿IZZHÊ0(}‚»~®Ñ æ©Ê,Xëv÷ëyJGéiþ�•ª?<hÊ_å6ì÷âãÀyFãü’kƒk~$;/¸°çù`ÙúÏ{w¹Û~UŽÿõ\[\Ö5¹þ -ô,Ê Â| _—Ζý-§(Zü–�ÿŽÝ‘- ¸Ÿ~b¯?;u¸øEóðú‹aÂÒÖS€¿KKK3–÷HÚ;}pøCò[¢±¸ß罺ܵ斖ø°·>£òýà4>¬t?Æ¿*x°KûOïõ”:~ÏwÞoµÂ·ƒe¥¥«çKþÏ…­ø+_ÀãZ®ÈNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçÔç–ÿ@ïð*|¨ßW¯!¢e‚Bª( �+ÚlIƒ¶D5"ÎÀ2AVT˜ÑH10dACDÁKpŠhê[$NÑ Ú€I*ÔBI"Ä ¥¨‚F©ª  DÌ  [ (¡a ¡PH/é‚$È2PA�‰I(A‚@! „§¬[Q`L‚° @¨·PDU �ÁI Ñ”…I $A2CZLÈ2‘ I€2bR©Z4n¾Îúu†††BªÙ`›•l)"[«£¸Â@’&!bL8`¥¦PH1NØR”Ø:ŠKö @¥ Th%úLÕE, JP]‡eZ|è¡­¾vô"�àq>?› TZãvôš8¨4~°î‡ô Š/ÖŸ¢ŸÛ·|“\/ÊÚÛê Ó÷ëX*(JÚ”ñ!úKo�‰ BÝÆíé4¥úÕ?¥¸À\Aò\?¯È Ò”[‘A·Ûß­åOR+… T¡â§÷”бý~T[¿_§ütùºEGô­Bmÿ¤¾}n·~x �[|ž$V5ºŠ–¼#ÅžÏݶ -Ö÷ÖêQ\ À´·æ­éZZ¢ßKþ5¿ÊßnÊ¿'ÕŽì­e)[üÐþŸÕ¹ØoŠÝGæ|ÞPµ\Û¨Ê?дýnÝžéýqдµùà”Qá×¼>üòšàÀ^j�Ï"9jÜúž:áÊ~–“”ù£žØ ?—åùå6ÿÚÝ¿­$'ôŠÇ·­[¿h¥k=ÿ4W„<Óˆ«T£Ž‡ï³äâ[¢Ÿ×ë=ë¸Uݹõ¿ÍÖ1ý8‡Áµ$Zq _¾® zاͭҊkÞýÐV’ýn±«„Q”yº_× ÏpûÍþ°Là'Òú…¿~te/ÝŠàÁ¶¸2€NNNNNNNNNNNNNNN‚ ]“ç‹„çç–ÿ@tÇ€€ +WÕ7÷ Žø;!¥„@è˜$I¬Ó*ÆÎÚ–€Â�„bálˆ.dD”P"ˆKa$Š¡!¤È0Xˆ„È�€X„� I" RQ)&DÓ J ‚V “`RÑÂ(EIL��ÒVx1TÔAL A& €°BeˆØÙbDP³„¬@T¤¦$ÀÙd´B!"¢V0:5Du¸"J$CH’@f¡�›$LôÖImELG`ã™,h,fö¼I!®»€„f‚„j2‚� B Ã’�P@ªtŒ*•Z)4&Zù&¬P�V)JjP‡ácBÚ’ ”>&‡È ¢ªÔ—d-¡ù¤Ð•ŠêŠ)ã~VñÛÓÆ¥ùã¥ð BP?r‡ô5JØã~„SQlˆ|�•µªVðTÿ#;4-”¨@ '‹ŒCê´¥õ!ÛÒù&šhã„~T}~ÓoÁRÆš8Ò‹zݸ¦€_,S”[Ÿ~Ö²š8¸íÖ쥨£Í¿K÷öÿÍÐ(·à'ïÿ+æëò)óO©Zt·›4­%#öù AÐVoy¥¤þgŽßXÉâ6즜ö§"T5ùù´qÛðKJ­?·‡ß¿Ì¿[üÂ+�$£~k_�)ýqe ¢Ørú‹tà/Û¥Åð¹oo‹õ¿ÏòtýnÁXÕÞþh×p>ótþht»ü£œ^n¢0šB+¸�?øFœ¡(¥òßš¥.–�áà8¸xèMc­y·ÉOš@NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç1ç–ÿ@ð*ÿ—ÚÞÅѳò.ÔcÕ� Ãgm ʳ53($”²2A!²0Á«!—6–ȆÀEI  Ë SwT$,D¤T€KÔŠ¤0 ¶€)‚”¡´@!² hM@‰¨Ó„ Âp’u Š’ "“%5@�HHË‚BP†msI€Ù )HAЈÃu²RÂ@:%�AJ˜p H%¦"MÚd¶a¬ÙDÉ`$À�¹a[¡F64\á­¹�cPeI$’Ð�ˆ-iI „¥(¨„:BA€±BBP/Â#dЄÒþh ÑCåˆJh¥»*,@|ˆ—A)ãM)BÔ"”ºM.ÉYë\KA# ñ4%ÙÊúV�CO…—ÆÞ•ˆ[E+ð( [–ß"ÞµE¹Ðq[Ðû(¤Û²”ºš xÜ•¤Ð_Úi}ûZÏ|?ñ%«zÚ?hM¯Ý N–~ýiõcÛÊÞ{RýjÝùû¦š“n®?ñ?5Œ+±�mØ cæé·-¿À®$Ò¿t`‘ù.�HZÊV¨ý¾ý-!."e%kB ïË�/òŸÕ£Â+nƒ‚JÇâ¨)}nªú˜·qñ‡ët% £�ò„‚;n7ÔåÉ Æ•«pM å°(C°ì¡4�&…º <`R·\CJméK· Ò‡ø+·%ù·?|¶EKv “ÅÅRßù�ìŸÕ OÊÙ@Ê)"šr…¯7Jh|µM¾„۸lj¸ãñ-P•¥¥´¾·å!ý!h`*àý¤ŠršàGî…¾%®1úÊ2‘û|—ÞjŒƒh}oZ⦗Ͽvëy}æ�x°꜠g·P•µ‡¿òóYFXþIYœG€€xÒ¶¶·G÷ÙM¿�ÿä ?iÊ0æK§þ$[©q”¦‡k�úM±Ã�/ø¨·à>5™Ûr-ÕŽ�ßä‹zݾ‡ôñ—åm (ÀX6 Ö7cà0þØ÷Ëo–©ó_¯Î—Kñ­¿Ê2œ¢ß€�,·‚ZõÆŠà·çµ([F{-ƒì¥Ø­1E¿=¸‹ˆ¸$tµ»ùòmôÿ>é{zE9­ŸÓÿ­çºÛ¥’þ¸ršátÿ\"Üxß¾üÝ,@â}lu¾Ý”qþéFQ‚L§šá[ZHNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚]‚ /‚ç¼ç–ÿ@ ®q~&<ñròX$é|N¶t 2æîò³²Y ÁÂ- ºfC«¶ˆIE@A &L$�"©  &`j”Š‚ªJ ()J&¤CHJ*˜�%W 2P’d B¬Ua P(!%"ªID%!ÔA0SQ2LH!-~Ij¤ƒDT‚$ƒ0t€€Â „à±*‚�,H�ÐÁ!Öš¡°Êº©-“ÈÙBvƒ2u²DÁ ­ªÐÐ –ÁÖ¤‰�jf*F¾ êR€ ™|ÊJHK* š„$Ê[Q(X„€™Z(€)% 4Š©AL Òü‘8TÓV~•‰¡@I \O€)…·š•M)JSJh¥|I¡l%ÿ²�K÷Å)ÓÇE%nÍ©%õ%&ß–)+UiK²’x’±·ÓKÿÚßõ®4¦ÞOé+o�„­H¥+gˆññCïÒü¿Ó”¥öSÄ´ý4ÓÆE4AZKôå?—Qo·%+iâ6ôÛÖÔ·å$ÒCÿ7€íëa>mk�òã[¤ÅÇú¦Šxß`.?Úk…m+x (}”->Êù­þ_¡ú|�‘*×¾œV=+’Þ¼è/²•¥¯Ù¥_¿Ï‰ÐV²•ºá[·'tÑ”?·à<§ÍþN–t¶Qù[üÕ¸¾ý!jP)G›@æíÜ·ÖúÆÊ|_’Û¥ÿ_µªhŽ*¿·e¼ß6ãæ–ü#ÇÆþÞ—ÜyM;86-SùþKtSCô¡ú_ÛŸ8†Á-›¥“oæ­Î”µÀü¦¸?Võ¾>3Oç€�›ýºYOº—Ô¿|’Œ«Š_¬kƒùçüž r„xAv_·H¤-,iª  R…¡ —Á/ÍeO¡úÀ¦š ô…ªiKòM4Û�(ª´ÑA AâKñB-ï¥ñ|$#ö¶€V¨©üÊŠj?hãýÓJRVݲÑK²ì% k@P´¶û÷ò´ŠR—A+i·­ÑžÉ¥qŸÐÊ)ÀVü÷}…” å(~•·ô~c‹=íÈ¢œ‘Xè'ŠšÆýŠ_>¬jÓ+O°ñžé 8 Š�ÿ(§Íe/Êò” QCäÒµZf‡öûwÛî,û)}û£‹õúEõ¯5\4£ŠØî/ óyGçBOço·~Yïžÿ¯ÖÊ<ÞS”þ_“ˆ¼u�XöÿÕc'‰."šÆº0ÖÊKˆ¦¸-é/³ä§=¿YJ8‘Xÿª+†ßXÔ8†¢±ø’ùmÄ7NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNbeetbox-beets-00724b7/test/rsrc/unparseable.dsf0000664000175000017500000001217315253035401021006 0ustar pieterpieterDSD {\fmt 4+data ID3TDRC Oct 3, 1995beetbox-beets-00724b7/test/rsrc/image.m4a0000664000175000017500000001334615253035401017477 0ustar pieterpieter ftypM4A M4A mp42isom ŠmoovlmvhdÄLé_ÄLï¬D¸@�trak\tkhdÄLé_ÄLï¸@mdia mdhdÄLé_ÄLï¬D¸UÄ"hdlrsounÓminfsmhd$dinfdref url —stblgstsdWmp4a¬D3esds€€€"€€€@xú€€€€€€stts.(stscÌstsz.22""'-+1/+&0''&%)(-,*).)(*%)-4&6.*,$,3/'& stcoÆé •udta �meta"hdlrmdirappl°^ilst7covr«data‰PNG  IHDR6ˆIÖ pHYs  šœtIMEÞ  J™tEXtCommentCreated with GIMPW�IDAT×cüÿÿ?‚9Ñ…'IEND®B`‚„data ÿØÿàJFIFHHÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÄ ÿĵ}!1AQa"q2�‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2�B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?’€?ÿÙ©cmtdatacommentfreefree(mdatЃì\«11;Ä<Àøƒ¤4„ `I�fàe—^àï�P0#Ü·›�Áb˜Ä»VOØÙ(*¾J€q8òƒ„q©-@>Ťè[-3þ!‹rtg¼¼(ι¶q]b¥¸úƒÄPEÙ€€ ª°DãÙ‘>JUl3ËA$Ö)i)ƒÀúƒÄA#�€+:3ï`Xa¶™˜ÉùQ;«À±˜ˆèàöƒ¢" „Î Ž× óf{q wZ“Ä 3z¿f#)NÙq'øƒ¢" „kËr½ÙÖ£ g�§ý'”ê )y*¦˜Úö»,°Îµx¡úƒ¢" „r †BXVFìì7nhϦNž|z%ôe0Ue®«Œ œöƒ‚B„_`9åo¢ðJ­Dz0¯)òøáÛ1F8‘ú·åÉ>7t·#‹Uàøƒ¤4#ŒXÛõÞ™¾áàÒ`¸Ž‚Þ×xT†aGˆ~fäHv<ý¶ÁÀúƒÄ`? &ˆ×63Дl:äGàë’ 莵š„ÇÓëåN‚àúƒ¢R#Aש9Ï<³ÔiÇ%Öøê¦—µŠÍÎê®yfžÎôƒ‚T„ `®!�I}uhnV$?‹+ä¡(Z«„Á�¡Üta¥Vi±+±l‰8úƒÄ3#P�0¼ñ•T`’3¹èžÓ#?}¥ÕõÚ»ìÔ‹€úƒ¤Q#Hl`µˆÁ½¥ËK§)Q)E‚ñõ>O²Âô¯SÔ¦úƒÆ"#P ÛdpËŸ¿Û2é­~sÛÈÓï�'Pîì=Í&ü!úƒÄPG<Ž0NÝÍ�Eø™_ƒõ'1…:õ˜‹å\øƒ¢ ˆ,l ƒq¼Ôº<�¬>èðÍ&ïÞ¦J3}•]dQ€€8úƒ¢`F  8I+–¶:aá–;0¥Ç>m>;ßM¾íÛ�Ÿ× ¥/gøƒ¤p>€ÞbSci›”¤L z:~H�5ƒM3©'°A+è&„f ‡Ö(pöƒ‚0!dÀ¢’¯:%¢C°9B³î+]þ3Z†¹ècJr†Â¶�öƒ¤`E€�a,]µ)\BiwÈ,yç@úD¸ù�ü'ħ¥¨Üøƒ¢ ˆÐÀ€0qóà=bžmBÅAwùH°×! šDSª� 8öƒ‚5 !`Â4†§å^ñíª^:$9µÏ…gs`M%…ÊZZtª^U£Y(o€úƒ¢"ˆ¤09œ’#NÑ·#̬zÚW›;t A-1dyß”3¤^ àúƒ¢" "ìFâwì¼ú„,µ¸rŠþ¬js%”ŸÒísÙfžep=¼øƒ¤`G €@ÀãÒ5?à¼`•Ø�ÉÍM²ÈöÆýYB^×;C€øƒ¢`BÈ ÆãiRø—‡iéŽ6ˆ0 9ü¾åÓvë…(ÜÿÿGYJ´…=˜¢oçlÇWøƒ¤3 BÐ3ÜQhLÖÆ$/ê‡b<÷~³µ8ëûÛΚS�­n*jõXeÅ×7’#àôƒ‚"(„@Ø Ad¨*Â`óÙ'ሬÁ®co·>Vûça &µ% øƒ¤`F‚ ¢±äßxã}¸<ëÊüfP[2ÚqXä.Š'Iµpúƒ¢" „¤*ÓØšÖ'êŠÇÉR™z[oÝÓ¬ía‚„¾”XÇS2p'ÀøƒÆ2! éZðÞx²µ¾ùìú$©¿Vn´%j(óVÀöƒ¤`F‚�€öŽ�F†@›c}}ðCÂ2>Û<ÆçO5£!¹QÞ/grD�ðúƒ¤aBàô‡2‰´S(^®Z�dð{¦P�¤Ÿ~‰ÙÛ˜¦‘6 Sºœöƒ¢ „,`¼-1wNÞAÀÍ”XPKh¡wKÛ#0R¬Y±X�-Àøƒ¢`E� "ÅImq¤>w¢È1s5{!ÁXº[¯/æÛ?ÓG�¥xøƒ¢2"%€Xä  aÔž®ŽæÏû©ÆÏç¿÷º�r¯˜LaÀƒì\ªRi"?pƒì\¬ „ô@À\beetbox-beets-00724b7/test/rsrc/empty.wma0000664000175000017500000005607015253035401017657 0ustar pieterpieter0&²uŽfϦ٪bÎlú¡Ü«ŒG©ÏŽäÀ SehÄQ€>ÕÞ±��ÐtÐÊ› € € ôµ¿_.©ÏŽãÀ SebÒÓ«º©ÏŽæÀ Se4êËøÅ¯[wH„gªŒDúLÊ”#D˜”ÑI¡ANEpT3&²uŽfϦ٪bÎl"@¤ÐÒãÒ—ð É^¨P‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104$WM/BeatsPerMinute6‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aTRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aWindows Media Audio V8a6&²uŽfϦ٪bÎl2K‚ ]“‹„ç ç“ÿ@ ÓÃÏ6Ó‚}mà ;€¦Jà$´æ“$�Ü$›ì ?'qU1Ù1%¦4©€` -I$ÀIP�c Ô I¨�R„UI10U5R’I‰¸IjR` Ù$Ę@«JTBTÓI¥1,E4” ¦”�Ò’ÒÒ€I:¢„bf¥1&C›°` �³QR@H@1Všˆ`šˆ †€H “:ÓP@¨þ¥�KÌI^o'�»@*@˜7C²@ •ÂL À$¨Ä %©--¦ši!T€H””¿HEPùj�H@&B4ŠJJÁóä"„0Ò•…ý Sƶ°|µALU2”’k?ßí/¨/ß¿¥,B(âýqôŠ1BÒÐ~¶¶š-ÜKlø¿!+t„H¢�„„å8� H¨‰¡h-Ûߥ)B Ûô-P_”PVéCäQný"—év0{eýIBÒÒ�ª¸�V‚i~·ÆüPè6òµA \@ÑÅA KT¿ÚÛëpã¥k‰¿, ñøRѤ ­¿vÙFPµB(âó^®oã§�Íù»yZÀUÁ”P„ã(À\KYFP…»}¿÷o¤ÓM–Ê?_¥ Rýmøâ·> ·× p?,£ŠÝúð´à*à}Æý–­ËKx)~üþ°óyKïÒoéãýÒ±~ìù¼§(ðƒïΚÆó\yïû§ó¬sXß•?´­-ÿµ´[–¨}BÞSJÒ8øÇ‰9ïùå>Á·÷úýqº_ͧ‹õE¾±øÿ'~ú—è·ÑÄ·ÙH¢š_%úiÝM.Ê]ŸÙK°´V²ž+sô~_§`;t㎟ߛü°c[ŸOšã[t-·A¥ ·?ü¿|T>¡ûúBÒÓêr•¥¡”­ñññ-¿ý¦ÞýÙ·[–Çý>ót~¿'A·Ð„%lÓE(?º0çÔñ­ºi )·Ûé¥òßîÞ·C÷ÉnÀ@­å4qºR#)O½k(ZvÏ¿:< ¿ÊhÀT"±Ÿ-­­y¼¥6úr‘Å@[Á*�XÈù­~뫈3Xöü§=ÿtþ¸¿\n�ÇÇ‚WÜi⦊Æ=©(Y�XùºÇ[[¨Œÿ)ýùº?+{ !öt½/¿Khó\võ³ÇO„Q•+yÊ-�ÀU�‚[ucåYò[Ð0òøqà?5€ÿtà”¥Ä\úÀN‚‡Á§`0þ¸2š2•¥†{Qàx6š>ÀT—ô%ù¤º[þðü_y»{ˆ7öáæí�·ñe)Ê_y â × ºØì¦šàâºÆ|NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç§ ç–ÿ@ˆð%,V,XU2¼�ƒ¢ d†´µ°DôZb`°D€« ’ZÒÄ’XªpÍR/¸I… &`c †²X¬ÀH1…$Œ)1´ÌJI,¡•2"MK¢ ˜A2¢B`’*!&©JADÕ€ë$Ši�–„¤‰ E&®‘(hØ+D¤„¥!¤Á$ˆ‰``:–h&FÄ꤈¸l¶¶ ¬Üô�F”a؈…E„–¹‚Cv[0¤á@™�˜˜00Š&¬“‡)EdìEB��MCQ 3P ¾4R EB( ±JKô¿BPPB0è@„„[‘M/Å¥‰ Û¨J€°¤¬Rü¡`ËTþêOT©QcM¼�°–¿-ZZ¥hÒý nÊ-ôñ:\kaúüÖÓùSÇÅæŸ~¿×OóÔ~Íp; yHZÊ ÿÌ¡q!ÒÆ¸8风ßùÓG®/É ¥¯Én‡ïÿkHóHÀ_µ¼ýõpºZ…§ÂÝ”ºSÄŸÏóãüߥm÷xÂiÊ_;t8ˆµn®§òO8‹êÆ}”ñ~¸Ðit²ÞSŸ¿[¬`ÿ`ª¸pD†¸„såBÞP_× P”Ö=Ž·BÕc'(ã�Õcy®'ÕÁ€ÿoè¡ÿp›cóåÁ^vkL£þ_“÷KWQÆ·‚WØ ­ÛŸ×ÁV}F §=ð_×ÞSBÕ4¾ð‚,¥(À~oóÁ*ÓúǬlù-ÜvǾq�NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“¹Œ„çÕ ç–ÿ@“¹Æ_­mšVÿ b†­°&6¢ H7#@&RI($L™&ú»’@(Ó£" h&gQ‡0c "`éì “†2QyJB%,Dš€&`–ŠÈ¦S„ 2Ì@0’i jH”Ã*J ƒ˜1 (‚i¤”  $¢©Ê ÂJa0BJI%�¥­$X €H–„ëD§ � X©³B «-#@Á!¨JoV ]G@Ðc¼«-TËNÉéªÁ³ ±¥†®˜ªI1Q‘¹BJ…� LÁ’…€À$˜„îši¦¥@“JÄ- .ËôŠQB@~„HDBÕ%4ST�(@JIJØ¡…¥�¡òX¿DS+eóä!/È~•ºBÊ”#ö´r¦„QNâ}Jj—ÁÛ¿·­ÛŸÒ‡Ï‘@vxŠ-£ö4>~mÅÛ-SÄùm%J-ëU_qþü)4&»)ZVô‡n´·H~·ùŽ?ÒVŠÚ?'ã(O©@}ú®È»gÏÒx�·ùÛ­ô¬V�húâ yíúâÍþ5¿É¡a€é·þNÚœ!mú+ŸÝ(óKÏ’HÊCëzVÈB?YHâCÿ4û�ôûЏO›¥mb�Ë•½Òïíß´Ž5¤¾OéÄ>SùÛÿ*P¶ÏÉõª°Ï|€©ókvî%¾/αè¡8Í­Sû§\täKùþ‹¥óÝëq|·B7K­WOçÅÄy¾#û}ùùº_£=Ê“üåÿ›Z¥o(·Óo¬zœCœ÷·þøøÖ¸ü#žÿ¾$ÛÖ–ðéóúÓOšÊy¼rŠÆ[Êx‡šûÊi·×QÇû§Í[¸ÿ!ûü¿^t¶{~ø––‡šÏl‚Kupeµù­QNP·ù¦ªÞ%ù¢ŸÎ¸ ¥€NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç ç–ÿ@üð-TÀ×ß½Gé=õ¶4C $š DΠ&I�:MOü`áÄ´€6 ‚FÈuaÌTAc áA@a@-2E@i0–,P I$¤ÔÀh“:I‰-/�B(, áá´¤¥cRL Љ(H©JMDÉi@š‚ÑIQ¬6  Š†KL’™‰‚PL„ÂJRH4Ë@YP 5€" $†ÀÄ iJH`$°fb`liÌC`)Û¼Àç¿�޶ënæ6€¬Ë ¤†5@Lµ hÃÉ$‚€Ä¦�Š¥`+:H„¬QE dÁŠQA¦…€E-|ù4ýúh B‡ô‹ú(BA@Ú){¡kÍW 8–ò‹cÜCeµ¿ÝEx o)Á1”»/¸«õ€©tÿŸ%câG€€¸¿óvÿ5æ¿o©KêÇ(Ê^NNNNNNNNNNNNNNNNNNNNNNNNNNNNç2 ç–ÿ@b—•aEDØ%�­iBLA2d 5Ôf¬vî‰ �”Õ Kd™ @ :„€&*’’!¤!bÔ"f@‘.%©¢¬‰¨�ÀZ JR a,’CP†! %3U RDI%×Q‚˜ªÂ$HA@“0™(XVPÁ 0�¦¬¦¬,Œ"€*‚°‰@0RK¨вІÔL†„TH‰U% ± (؈ ‚þLŠ¢ÃUkI ͬnTƒbe‚.ÔÈÂT�s!¦éDư€ ¶Z 1`‚ � Ja$¬°Ù k%Ôœ±~ý™5|¤¥m4;jΗéM)$iH ”>R"¢Â“Y ÒE @[¦€Ä)( %ý55–ÖÊ2ƒJ¨·Qý 4!(?·Ð‡ô¦ÞÑ&*>âvÜkOŸ,)BR’µBi ¡i`·JRùú©OÞèEDÒ(ðŠ?K||PýúpñXüD`>'ùN}oãý?Oäè+T-¤Ÿ ·&Þûˆe?¼¢ßúã‡ÅG¸ñRø¾â§óþ OpøUSoÊ-õ(+\h}O〟¿¬rrŽ7AFP¶ÿ">„e]¾[âü‘á,¦�É¥inœ§)â¤V7[Ÿ~¸éE[ø©âGQo|C¥ø�’VÇ¿a÷Q€¿iGëöâÿä]>U¾%·ëeoÀ@Të…o)[[|íèýå'Â%·>óVÇþÎ _`’¸JÛþ+{ˆ®ÁÏtñþíÔ„‹š@óx6’ÿòZ·¥mOïÍ­%kÂ.ŸŸà‘k‰ñZJ|׿+�öSoý­¾£÷æœDqö·æò‹c­Ç÷”å ßy²·ûÊ2šàÛæ©®ÿ’£Â+Vúàʸֲ•ºàÇú[/¿YO|šióTÑOèÓ”S””ñÕ„ç·éin•¿ÊÝ”qÛ‡ínÝáÒr�ùƒûÊi¡6ô�×ê±ß‡mlv{qññå/ß[ió\kYBÖù?4å±ÒµÄùiÿäùBp°IÇù?~µžÈÏn5 œ¥6êÆÊºü펥öQ€©/øŸÛèÀ^iÛÏê‡ùRZ`%ªÆÏ|‚[u¿‹=�|#žß»~Rÿ>J©ý[ò‡ø”-q×óUŒµoÏ5”¦ÝžÎ—·`•–Ê+œš”[–­Ïß¾¬u§mæÿ�ÜNŸ¨®ÚÕÄ;çáÓð}‚QoüÍ»ÍNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“s‹„ ç� ç–ÿ@Äò²AP{õ¶ƒges@� ²ZÕ5¶ÁÉJ ÆØÄ‚Æ„È'´„•Ÿ H5 �„&*N¿ä‚‚’¤T`b J †BRM ’„ÀD/HIª*%t. ˜"ЏA2iT"DH ª™€„’‘†[Q%• Hª-ˆRL€ @hD ¦pB6@À"óe KPI º,DÍB`D@… =ÞÜÛŒA˜UÕdʆb eÄ@D²HiÒBI’�)nä,$JD¡¦—ÉX€ @BL³�4‡È%“)&’”�KúJ%lÓÆH¥ô¡!mÙ‰vÜa4ÑI/‘ ûðø¥n¡¢ªVЊÁ}ÇHCõ¥´-¡ú8Ÿ…¤P‡Í¥õ’ú‚’·Æ„ÐŒŒQEÉK°?°ù ·Ük°úˆ ñ:´-­§�)X>Z[âÊKyO…­QÇKûzÛçÀR•¥�äµEÐ8Ÿ?h·ø“úÊ2—éâA·¾+t¸‚ÊVŸþOÿTÖ„mߢž;z×îØãXÕŠRþ¸E->E»¼±—Ïé·ˆ·¾·›}»ó£ÂÿB„PÿÍ;~%¿7\=¸©£ø_í÷íkò[›ësဩ #=©ÊÚÞ¬ÏÂûu4¾·e."Pr…»}4­­3Ùýpå’›wâ/ÿ+{ünýq-ç½)•¯Øü¿\|x%ü–Ö¼Óçå/«ƒ�;—ÇÍþÖ‹¥�µ”e9C§Þ­?°µnóuÔ۰?´~¸ëLå/¸œC`.7Ï�ýkôégÔWÞ{~­ùGäšáÀb±øÝ/\JÌí½ýpþíÔ­ñV˜[EOËÍ×Mpe6ï[ŸæŸçÉnʳÝk=ò•ªRâ"?_·ø ÍÇ{->tûñe`/7û¬{pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ç¾ ç•ÿ@˜O3  -ð9²ÄÉ×Xá«£Z�¶A�¡’Ö)ƒ:�Õ’T««À%A€�$ªd„!±LA’‰ŠÌD IJÐaIJÀ¤™lˆ¥)% BHLÕ ¢Q%0&ª%0‘I šHX¬RŠQ‡ I4¢RDÐCe IiŠP³‘&Š„S5�$„�˜–š‚²ŠP”‚* e! A;©Ù”š�‡DTMPIh"PfÓ2 ‘†XVy“¶@ �Íæ$À‘`4s�0W–X[$á†HbgD“ƒ½$UlÀ„*$€‰«R’¶DBQBhA4”?&Œ© „¦¬a¿/�šQAD´¤”š"„¡û°þ„-x\‚R*Ð샳IXR툤RA|š_ r‡Ä q¡jßJGJh‡Ô¿¦Š©(·daGHÈâmÄÕBBÕ/¤¬ƒ¶âM¹øZ}VÜ·ÅBhâÍ~IZ)§(ã¢ßM ¡òM [®Ï�­¾ ®Aºÿ’Ý8ö(Z£Š—Ä[ÿTëNƒ€“ûý¿óX Ýnü£óº?/ݹPiM?´Ð) vå®*ë¸B/ݽóühX§õG愾 Iü‚h·×Ïwþz/7ÅûðºÇ ­Û¿vàŸÉ÷…q[ß[ë‚ÞùÀÿ7ù„q¾(â£öù´Œü[¸ð ¿ 0Th·~GÍ%ÿZÊ-þi¬ù&‡ÿ§Þl>[Àoÿ<ý87¿ËÍ¢—öêV¼×€€Ø?ýøGõù"œZeÒø$¥ý¹ý¸Ö7íõpq>q ”g±ã·`•?¬öýWç”çÊú¸2—ÿ´Ð³8·€³Û=ßà7õ�o·ÓÅÅ€­èEcù¬§ò®æ±£�ͺ}¸ðqú ¶ü…¸ ¶êÇÃæŸV™q Xßž® ÷ZÀh‘'äø¸‰ƒjÚÅþ 2•¤á NNNNNNNNNNN çì ç–ÿ@õõ1à E.üÆÍÐwa(,± ­ÇB utL(fcDÁ`�. �‚%�ÉÚI¨€�-”¡ H$�„H’ØI’S&$…RàI,™)¦ZR¬6¢ÄŠ`BÔ”„‚)Am)HF¨(�C&˜MH u�(”ÌÊ�T$‚tH )A((Q5S'üÉ�†ÂAQ¥I”3q†`$QD a·S57$À³-Ð%¦ØÜFØ,ŽË&o­2¼hÌho`…„2I4Èa«’ÈI¥ a楇ŠS‘蔬IªìÕJj!4ˆŠ · $-¥ôBÚ Õ Jj¿ã(ŽFO•ŠPŠV…/¸‹çÉ·„„P_Ë'È¡ij‡îÇþ.$:)âG[H(Z·-:RÔÓÇBÁõ½l[ÐùnßA§ŠÝJÒx–ê%(+@|ÿ)+’]šhZKì%/¸¿e?ºZ vÿÈPµnãÊV+šÂÜé|¥—õŒh§ñ…º€[¸èX i¥õ‘-U¤~­þ$ñ~T¿~µû¯Õc?Ài¥öS”PþßCáNâýù¼2Ÿà­;`>ý¾ð‡R-Î"Û©tsïÐù&ܶÿ)Z[3”¿ÀX%ýq­å/©Mü£öÓùO„Vè9E4å/ßù¤g·›®ùRšá«ùÒÿ(¬l÷|°[.‚•·ÙFUÒùŠ)ÒÈÏj_×êÜ·ÇûÀhðµ«vPµæßWQùºío�ýuÃáX õ»ŒÓ‘.P¶éd~·-׸ù¯6•«vPét~uŽâ'è[“ÅÅù-¥múp.—KìöOêßM¼xA÷ì')E6òâ/š)Ê?#nãvË_«r?\N–}€­Ëx*Ê?UÂø× Ýpº^±Ý-H}XÞn´ÇæéI”çÉžç(¢„eÃæŸþ`NNNNNNNNNNNNNNNNNNNNNN çç–ÿ@ç%ø,H¿A~”’Åð!½�f%°Ö�Åíz ÀXd€ �ˆ$¸uÕ€PÈ- ’P ’� ™©1 ’J ¡!5!µ %‰L€I Œ3 ªDCú¥¨–ja†“¢ª‚œ$˜ `©…T’$–¤„ ´ ™0 ‰ˆ ‡Y(L ™aP2Á-;*j@ É–U2PvÖT@ˆØ€€È&bÉhh €I �Ø´Á*†ZÀº[- �²¡Ä•6I6��É]XD‚Š‚£¬ò�’YC¤¬…� S PxŠPP MRH¦TÚˆ•¤ˆ ¡hJĤPì¾ ¡l-?B—ô»)ÂÙ„�I¦Š�ÿoË ËúM (¡&š2…¤>-%+eb”ñ?ã§Šßú¢“JÃ(ÅÇ/ß­/Ú]—Ë|r)¡ FRý%`éz™Yž4')¢š-ç�"Šx¿Iâ¡úÇÅnÀAñZZAl>}C÷èn[ý-£ô‚´°?§á÷Rùÿ.7õ_å?’+Íe  ¿Ê8‚ßhóU�Äø>ÇGì>À_—ê±–gV’·GçûÀT£`'ß–SO·þÏðSæ²…¼öý?ýe9A£ò|!Çæê­äIn¬d»wëC‰§ôýòÞPµ@JŸåÿn!Ý,µ”-¾ãüÖg_ñÒ_  ”[Ñ\cÍq`*-öà2Šm�ÁR8ðKæ�š[ãüÿ'ùí€ßÖ3ˆ©óO¨~´|"·ù­Q”q¬g_~O‘àT¤V6 (BÞ{ y·?¦ØàJŒ¤[ÿ+{¥�_Ïß-V7êÜœ¥6ÿËŸ¡Æÿ>Jk�+Oÿ/ÎÝÄýó¥¼ÀÝÅ€Ý/ù× ½ilà,Æé~,øF‹xüë(§)§�)A£´þ––¼Ýce.—ZÁ"NNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“-‹„ çIç–ÿ@˜_×I°Æ44¢{ˆ`ÙRAL—TĨ�É€RÆK@*L)H-`‚ Lfgb*T 1 DÄ)0™„IEC%0"0¶üeé@v%þv+"”�TÀ$Œ9J*T‰dDÌJBh%aˆuÉ5)(5!"ê l"©’Pƒ„[´ ¡%ÖM!¤Í I(©8A•Ih5jBN�  ™è‰Ñ æ[T4oa€ïLl�ÑÀ“ÛNκ0fÁ‰$�3¶‰)‘TÅ‚H¨v4B*0�DJ)(Ja"­C@�˜(`)!4‚iJA|²‡ôÃó oÀ‚Š˜tÔ,_ÑJè¡I|„RâùÛSCäÒ�A)|ù)¢”ºRíÿB_ÒJ·n[¥in(¥n—Öþ:V“”>|ú©6íSúL­»)EDÓù V–ø�±ð»z4?|µGå”Ón«s÷Ï©[GJ€RƒÇæÿ€þ±‘NR] _ªÆ·~ø€âJßêŽ4­>|‹u (·­#)¬oÍ÷çEo–ðV¶2Š*üÕ4º ý:RÐRø$~ŸÛ’þ¸ÿ^k‹‰÷q;ZvüKKOÿT¾[¡.�à|h·~Ñ~‰âqö„QX߯ßçn£¸‚âýþU�”q­,¿Í¡múÞSNSùQ”W (Ê?*Ç¡o=ߺ2Ÿ`‘nßNZã[Ïgë\HJßš}”V2ж_-Ûß­­"� ¢´Å¾›v �–¿+rÕÿF±íÃ=ò•§Þmý!5Àò‡ùC±ƒm¹Ä:?o¸“Ç€²—ôþNƒ‚JÇýþßÍÄU¯Í––ÿèüÂ×…-à;cÂÆ)â§õ�Gï)·Û³ÚªÛúmÁ4x +vúÓ—çæÿ.*”¾?¿åV=EJà|û‹ŽØïÉbšàý~¨ãt°NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçwç•ÿ@5øYà J•þ{l¯¿¢Í*ƒ'þX¾ 4ݵ2ˆ€ ƒ¦I €Öl�(‚ˆØCœ8 A’tMY$Rœ3(IK“N’ɨÂA: ƒ,LLAiÔ(&BAÃ2€Ð0PU( “LÕaI@$B+2„’š€ª %™(š*U$Å&I5R€�DЍ%Òì‘%!¨B�‰‚P!'¥R„Š£Ä % 8S!AAAfXPµF†F�PÒ"Û:Ëš¤9Ê�¡—¶&H*–b ¨iB@HBH ÂH@4”¬àUv@j0@@ %‰h„PýúI¥òÚ(¥Ø«I¤…´Š$Ë÷áÓDЍGªÝ?[&•¾7d»4%nÞŠ*Ò”¢� Ïí`…‹þ*_¤Ð¶8Òýihq­¡inÝú lZ¥ÿð´­->©ÅEº¢(é㦈HJxÖèâ[åªSJñ$£ˆú„q->·ÓOï÷o}æŸäKK÷ÿ™E/ŠÒmëOÿ>4SMøéJ×ìeHN¥ú]ÝF –Š?5µ«sëz_Ñoói âBº c­›}pùºP�Óñú¥Ð+Íe#)üŸŒ¢Ü´¶ü¾þ:ý McÛÖÐûŠ”[ÿiFRµGïõXùíOäŸ7žé Æ—áÿš[ã ãZBmâÝû·»o5žä?ñ'õùþo¿OòŠp?•6ñlzkR‘æÏ們Y[Â\DüËêà¬t&±Ÿñeå¿Ë¾ûÍçµ.–AÊk÷›t³ü"þÞÿôx°é÷›ýù¼÷/‘Åùà.?×å€ÿ\IÊ-î—[¢Üÿ�àðŽPúšÆ}Io>L¦ƒžô×Êû®H×ÉÁ/šÀUÃ\5�ù`<£xBŒ”~ÿvÇ‚éoÎÝ€­Ø%t¹ÀN!ÿ_µ¯ËÂÎ{eíÇZak=‹ìHNç¦ç–ÿ@bð#ÕØòsg¡uÍ"HÚ›]²ËÃ&;b&#`�™�¦‰,n€h$Õ«±I"%2C̘ Âpà5;� ¤™I&jÁhh@I-5¥0¥ „HJ" ©‡EM”ÊHÈKeÕ)(4Õ‰TH"”dVDˆK ¤B@NA¦fU€�d¤‚RN’dP–¥«B`È„¤ÄˆI %’Ì&\’K"Ú°7 T¨lžî…XK™¸HøcR%Q¡…›É1 !&bZLƒ@YÀ¤“2ÒHJ*! ™šP±Á¤¤¢“ XÒPL>J""¡ „�±4ÐE¤Rš( „>4Õ4¦‚�ùlñÐ’°©Ä”Rú i Kô? ‘ BÓõº2˜KñRšh[âÐJVç(¾¸Ÿ~ÎPP„~Ëêˆ}o¥ÙâD”¿(£ŠÜìRšÎx�±|ì%Ðic\ XŠGR·FD¥ð[êÇvÔÛËô[ÊRì-ñþ’þßBQGíij_~O�…º)Ïk}?°ù9M5QÇo¡Ø~‡é¬z´¶´ýñÅGä< mÏзÅot¤óÑñQáúMâv¼(Ûßþ¿IZZHÊ0(}‚»~®Ñ æ©Ê,Xëv÷ëyJGéiþ�•ª?<hÊ_å6ì÷âãÀyFãü’kƒk~$;/¸°çù`ÙúÏ{w¹Û~UŽÿõ\[\Ö5¹þ -ô,Ê Â| _—Ζý-§(Zü–�ÿŽÝ‘- ¸Ÿ~b¯?;u¸øEóðú‹aÂÒÖS€¿KKK3–÷HÚ;}pøCò[¢±¸ß罺ܵ斖ø°·>£òýà4>¬t?Æ¿*x°KûOïõ”:~ÏwÞoµÂ·ƒe¥¥«çKþÏ…­ø+_ÀãZ®ÈNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçÔç–ÿ@ïð*|¨ßW¯!¢e‚Bª( �+ÚlIƒ¶D5"ÎÀ2AVT˜ÑH10dACDÁKpŠhê[$NÑ Ú€I*ÔBI"Ä ¥¨‚F©ª  DÌ  [ (¡a ¡PH/é‚$È2PA�‰I(A‚@! „§¬[Q`L‚° @¨·PDU �ÁI Ñ”…I $A2CZLÈ2‘ I€2bR©Z4n¾Îúu†††BªÙ`›•l)"[«£¸Â@’&!bL8`¥¦PH1NØR”Ø:ŠKö @¥ Th%úLÕE, JP]‡eZ|è¡­¾vô"�àq>?› TZãvôš8¨4~°î‡ô Š/ÖŸ¢ŸÛ·|“\/ÊÚÛê Ó÷ëX*(JÚ”ñ!úKo�‰ BÝÆíé4¥úÕ?¥¸À\Aò\?¯È Ò”[‘A·Ûß­åOR+… T¡â§÷”бý~T[¿_§ütùºEGô­Bmÿ¤¾}n·~x �[|ž$V5ºŠ–¼#ÅžÏݶ -Ö÷ÖêQ\ À´·æ­éZZ¢ßKþ5¿ÊßnÊ¿'ÕŽì­e)[üÐþŸÕ¹ØoŠÝGæ|ÞPµ\Û¨Ê?дýnÝžéýqдµùà”Qá×¼>üòšàÀ^j�Ï"9jÜúž:áÊ~–“”ù£žØ ?—åùå6ÿÚÝ¿­$'ôŠÇ·­[¿h¥k=ÿ4W„<Óˆ«T£Ž‡ï³äâ[¢Ÿ×ë=ë¸Uݹõ¿ÍÖ1ý8‡Áµ$Zq _¾® zاͭҊkÞýÐV’ýn±«„Q”yº_× ÏpûÍþ°Là'Òú…¿~te/ÝŠàÁ¶¸2€NNNNNNNNNNNNNNN‚ ]“ç‹„çç–ÿ@tÇ€€ +WÕ7÷ Žø;!¥„@è˜$I¬Ó*ÆÎÚ–€Â�„bálˆ.dD”P"ˆKa$Š¡!¤È0Xˆ„È�€X„� I" RQ)&DÓ J ‚V “`RÑÂ(EIL��ÒVx1TÔAL A& €°BeˆØÙbDP³„¬@T¤¦$ÀÙd´B!"¢V0:5Du¸"J$CH’@f¡�›$LôÖImELG`ã™,h,fö¼I!®»€„f‚„j2‚� B Ã’�P@ªtŒ*•Z)4&Zù&¬P�V)JjP‡ácBÚ’ ”>&‡È ¢ªÔ—d-¡ù¤Ð•ŠêŠ)ã~VñÛÓÆ¥ùã¥ð BP?r‡ô5JØã~„SQlˆ|�•µªVðTÿ#;4-”¨@ '‹ŒCê´¥õ!ÛÒù&šhã„~T}~ÓoÁRÆš8Ò‹zݸ¦€_,S”[Ÿ~Ö²š8¸íÖ쥨£Í¿K÷öÿÍÐ(·à'ïÿ+æëò)óO©Zt·›4­%#öù AÐVoy¥¤þgŽßXÉâ6즜ö§"T5ùù´qÛðKJ­?·‡ß¿Ì¿[üÂ+�$£~k_�)ýqe ¢Ørú‹tà/Û¥Åð¹oo‹õ¿ÏòtýnÁXÕÞþh×p>ótþht»ü£œ^n¢0šB+¸�?øFœ¡(¥òßš¥.–�áà8¸xèMc­y·ÉOš@NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç1ç–ÿ@ð*ÿ—ÚÞÅѳò.ÔcÕ� Ãgm ʳ53($”²2A!²0Á«!—6–ȆÀEI  Ë SwT$,D¤T€KÔŠ¤0 ¶€)‚”¡´@!² hM@‰¨Ó„ Âp’u Š’ "“%5@�HHË‚BP†msI€Ù )HAЈÃu²RÂ@:%�AJ˜p H%¦"MÚd¶a¬ÙDÉ`$À�¹a[¡F64\á­¹�cPeI$’Ð�ˆ-iI „¥(¨„:BA€±BBP/Â#dЄÒþh ÑCåˆJh¥»*,@|ˆ—A)ãM)BÔ"”ºM.ÉYë\KA# ñ4%ÙÊúV�CO…—ÆÞ•ˆ[E+ð( [–ß"ÞµE¹Ðq[Ðû(¤Û²”ºš xÜ•¤Ð_Úi}ûZÏ|?ñ%«zÚ?hM¯Ý N–~ýiõcÛÊÞ{RýjÝùû¦š“n®?ñ?5Œ+±�mØ cæé·-¿À®$Ò¿t`‘ù.�HZÊV¨ý¾ý-!."e%kB ïË�/òŸÕ£Â+nƒ‚JÇâ¨)}nªú˜·qñ‡ët% £�ò„‚;n7ÔåÉ Æ•«pM å°(C°ì¡4�&…º <`R·\CJméK· Ò‡ø+·%ù·?|¶EKv “ÅÅRßù�ìŸÕ OÊÙ@Ê)"šr…¯7Jh|µM¾„۸lj¸ãñ-P•¥¥´¾·å!ý!h`*àý¤ŠršàGî…¾%®1úÊ2‘û|—ÞjŒƒh}oZ⦗Ͽvëy}æ�x°꜠g·P•µ‡¿òóYFXþIYœG€€xÒ¶¶·G÷ÙM¿�ÿä ?iÊ0æK§þ$[©q”¦‡k�úM±Ã�/ø¨·à>5™Ûr-ÕŽ�ßä‹zݾ‡ôñ—åm (ÀX6 Ö7cà0þØ÷Ëo–©ó_¯Î—Kñ­¿Ê2œ¢ß€�,·‚ZõÆŠà·çµ([F{-ƒì¥Ø­1E¿=¸‹ˆ¸$tµ»ùòmôÿ>é{zE9­ŸÓÿ­çºÛ¥’þ¸ršátÿ\"Üxß¾üÝ,@â}lu¾Ý”qþéFQ‚L§šá[ZHNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚]‚ /‚ç¼ç–ÿ@ ®q~&<ñròX$é|N¶t 2æîò³²Y ÁÂ- ºfC«¶ˆIE@A &L$�"©  &`j”Š‚ªJ ()J&¤CHJ*˜�%W 2P’d B¬Ua P(!%"ªID%!ÔA0SQ2LH!-~Ij¤ƒDT‚$ƒ0t€€Â „à±*‚�,H�ÐÁ!Öš¡°Êº©-“ÈÙBvƒ2u²DÁ ­ªÐÐ –ÁÖ¤‰�jf*F¾ êR€ ™|ÊJHK* š„$Ê[Q(X„€™Z(€)% 4Š©AL Òü‘8TÓV~•‰¡@I \O€)…·š•M)JSJh¥|I¡l%ÿ²�K÷Å)ÓÇE%nÍ©%õ%&ß–)+UiK²’x’±·ÓKÿÚßõ®4¦ÞOé+o�„­H¥+gˆññCïÒü¿Ó”¥öSÄ´ý4ÓÆE4AZKôå?—Qo·%+iâ6ôÛÖÔ·å$ÒCÿ7€íëa>mk�òã[¤ÅÇú¦Šxß`.?Úk…m+x (}”->Êù­þ_¡ú|�‘*×¾œV=+’Þ¼è/²•¥¯Ù¥_¿Ï‰ÐV²•ºá[·'tÑ”?·à<§ÍþN–t¶Qù[üÕ¸¾ý!jP)G›@æíÜ·ÖúÆÊ|_’Û¥ÿ_µªhŽ*¿·e¼ß6ãæ–ü#ÇÆþÞ—ÜyM;86-SùþKtSCô¡ú_ÛŸ8†Á-›¥“oæ­Î”µÀü¦¸?Võ¾>3Oç€�›ýºYOº—Ô¿|’Œ«Š_¬kƒùçüž r„xAv_·H¤-,iª  R…¡ —Á/ÍeO¡úÀ¦š ô…ªiKòM4Û�(ª´ÑA AâKñB-ï¥ñ|$#ö¶€V¨©üÊŠj?hãýÓJRVݲÑK²ì% k@P´¶û÷ò´ŠR—A+i·­ÑžÉ¥qŸÐÊ)ÀVü÷}…” å(~•·ô~c‹=íÈ¢œ‘Xè'ŠšÆýŠ_>¬jÓ+O°ñžé 8 Š�ÿ(§Íe/Êò” QCäÒµZf‡öûwÛî,û)}û£‹õúEõ¯5\4£ŠØî/ óyGçBOço·~Yïžÿ¯ÖÊ<ÞS”þ_“ˆ¼u�XöÿÕc'‰."šÆº0ÖÊKˆ¦¸-é/³ä§=¿YJ8‘Xÿª+†ßXÔ8†¢±ø’ùmÄ7NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNbeetbox-beets-00724b7/test/rsrc/no_ext0000664000175000017500000011052615253035401017227 0ustar pieterpieterID3TIT21 Second of SilenceTPE1Anar Software LLCTALB Blank AudioAPICimage/jpeg‰PNG  IHDR88ìl�bKGDÿÿÿ ½§“ pHYs==•U¶tIMEß 1ov IDATxÚìÝ{”UeÝðß0 7/(ꀉW,S°4±¢2o�V*Þ5MQ3i•¦¦¨yëâ-5¯¤¯€šËÔ4 CY½–y)¼¤drÑ�a¸ŒóþÑ[ œ™sΞ9gæ<3ŸÏZïzkïg?{ïß³Ïpηgï]õ�°NJ¤NÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀ$OÀA«Úl³Íbâĉ1tèPÅ h*"¢^h {î¹gÜ|óÍÑ¿ÿ¨©©‰Ã?©`4ÿ7h˜ÁA TVVÆO~ò“=ztAí�:ꨘ1c†ÂÐ,Š®S§Nqà 7ĨQ£ ÞfΜ91bĈX½zµ�™[T(º /¼0Ž>úèLÛôéÓ'>üðÃøãÿ¨€dfEuòÉ'ÇÅ_ܬm׬Y#FŒˆ7ß|S!ÈÄkb)šý÷ß?&NœØìí»téÒ¢íè¸Ìà (vß}÷¸ï¾û¢{÷î-îëK_úR¼òÊ+Š @ÁÌà Å¶Új«¸ãŽ;ŠnDDŒ7NQÈÄ Z¤S§Nqß}÷Å^{íU´>ëêêâ3ŸùLÌŸ?_�(ì÷©Ð§Ÿ~zQÃ�ˆˆÊÊÊ8í´Ó€‚™ÁA³íºë®ñÈ#�DUUUÑû®­­�=÷Ü3–,Y¢ÐäeÍÒ­[·¸þúëKnü§ÿ¯ýë @A4ËùçŸÛo¿}I÷1jÔ(…  2ûÂ¾ßøÆ7J¾Ÿ=öØ#ª««€¼dRUU—^ziÑû]ºti£ËÍâ 29öØc‹>«â™gž‰Ï}îs±hÑ¢ë9äE /ëÑ£Gœyæ™Eí󡇊#�<2/^S§Nm°~È�!±ÝvÛ)>9 8(Ø7¿ùÍØl³ÍŠÖß3Ï<ãÆ�‹5kÖDDÄäÉ“£¾¾á[‹Íâ éÓ§OŒ;¶hý-]º4ÆŽuuuÿ]öÖ[oŬY³´1b„ 'ùÖ·¾½{÷.Zgžyf¼óÎ; –?þøã –}⟈®]»š$à ¯þýûÇI'�T´þn»í¶FƒŒˆˆiÓ¦5XVUUŸøÄ' Mp�ר±c£[·nEéëÝwß�Ë/¿¼Éõ³fÍjtfÇž{îi h’€ƒÜH§N1jÔ¨¢õ÷ÓŸþ4>øàƒœm›Ý!à çïW% —½öÚ+ú÷ï_”¾Þxã�˜2eJÞv�Æ 34IÀAN#GŽ,Z_?úÑ�bݺuyÛ=ýôÓ±jÕª –m²É&±í¶Û%à I•••qðÁ¥¯gŸ}6{챂ڮ^½:^|ñÅË?õ©O%à I{ï½wlºé¦Eé뢋.ÊÔþ•W^i°l�=ö0(4JÀA“9ä�¢ôóÈ#�ÄsÏ=—i›—_~¹Á²�%à Q�;wŽƒ:¨Åý¬[·..½ôÒÌÛ56ƒc«­¶204JÀA£öÙgŸèÛ·o‹ûùŸÿùŸxóÍ73o÷Úk¯E}}ýË ``h”€ƒFã�ž+V¬ˆ«®ºªYÛ®^½:Þÿý –uïÞ½(¡ í�€ƒFíºë®-î㦛nŠÅ‹7{û¥K—6Xæ6#à QC† iÑök×®�_þò—-êcÙ²e –¹M€Æ8h OŸ>-zè¡X²dI‹úh,à0ƒ€Æ8h`ðàÁ-³7"">øàƒË4FÀAýúõkÑö³fÍŠçž{®ÅÇÑØE4FÀA-}SɤI“Šr›o¾yƒežÁ@c4Ð’Ë–-‹x (DZÙf›5XÖ³gO@èÓ§O³·½û¶¶¶ÅÇÐ¥K—èÝ»wƒå�;w6@4 à �ÊÊÊfmW__wÞygQŽa»í¶+ê±о 8h`åÊ•ÍÚnúôé1gΜ¢Ãþûïßèr�pÐ@sŽb¼ö?<ðÀF—»E€Æ8hàƒ>ȼÍܹsãÉ'Ÿ,Êþ·Új«øøÇ?Þè:�pÐ@sfpLž<9>üðâìÿ ƒjr�[ThŒ€ƒšp<öØcEÙw�=bìØ±M®pÐ d½EeΜ9ñ�ü£(û?~|ôïß¿Éõ#à �¬38¦M›V”ýn½õÖqÚi§ålã4FÀAYgp<þøãEÙïyç�]»vÍÙ¦XÏù }pÐ@–555ñ§?ý©ÅûÜsÏ=cÔ¨QyÛ-Z´ÈЀ€ƒÞyç�¨¯¯/¨íôéÓcݺu-Ú_EEELœ8± ¶ÿú׿  8h`õêÕ±pá‚Úãù‡vX|ò“Ÿ,¨í‚  8hÔœ9sò¶Y·n]LŸ>½EûéÑ£Güà?(¸½€€Æ8hÔܹsó¶ùóŸÿ555-Úϸqãr¾ö£4FÀA£ 8^ýõíc«­¶ŠÓO?=Ó6žÁ@c4ª�[T–/_Þ¢}\yå•Ñ­[·LÛ˜Á@c4jÞ¼yyÛ´$à8î¸ãbĈ™·pИÎJ@c ™Á±lÙ²fõ=pàÀ¸à‚ 2o·fÍšxï½÷ Ъ***š½,kÛB·_·n]|øá‡g=Žõì´ÓN±ãŽ;¶Ê…[ªí[úaZymmmÎ[Hvß}÷èܹs¦}UTTĘ1c¢G�™ÇgÁ‚qâ‰'–ä\Ëe\Ëáj)ö•¥]JçšÒu•Ê5è\Ûç筭Ǫ\ϵcÕÞ¾‹8WßE|ñ]¤\>åèä“OŽG}ÔùõÇ4"ê•áß&L˜&LPÊÚ)§œ�<òˆB¬Ç Ž"Y¼xq£·lÔ×7žeYžµ�¦dí»ºº:z÷îÝd ,ˆÅ‹|ŒÝºu‹vØ¡ÙIéìÙ³ãý÷ßoÖù·Å8¤0Æå\“TÇ2ë>‹qž)Œq¹ÔÛç5Œ±Ï«±ì@ߌ±±lß¡:ò÷û8 Æ�×äúN�}º�:·¨d§"ä4oÞ¼X¾|y“ë 8Î9çœ>|xQöÇwä�šÐÞxÈhv*B^¹fq|4à8øàƒcìØ±EÙïªU«bêÔ©èpÌàÈNEÈ+×s8Ö8W]uUÑö{ÿý÷GMM�:œ|‡‡Œ6ÔY È'WÀ±ÝvÛEeeetïÞ=n¿ýöèÙ³gÑö;iÒ$Å:$38²SòÊptéÒ%ª««ãª«®ŠÁƒmŸúÓŸâ•W^Q| Cpd§"ä5wîÜœ·Š\~ùåqðÁuŸ7Þx£Â–‡Œf§"ôÁz饗š\¿ï¾ûuO=õTL›6Má€ý;,ç�yGÚ(…Èu›J1­[·.Î?ÿ|:4·¨d§"$׫b‹éöÛo�Ù³g+8С 8²S Ò38/^?ûÙÏèðÙ©yóÍ7cÅŠ%ÝÇ¥—^šóa¦…€#;¡à×Ë/¿\²þ_|ñŸçž{ ïï86$àèè@çÎqíµ×–ô¶”çŸ>Æ�Ÿ÷ À¿¹E¥¿o• ãªªªŠo¼1:è ’ícÞ¼yqâ‰'Fmm­‚e¥±Û<šºõ£XË mÛ¹sîŸëކE2lذX½zu› ]^UU£G�ŽvØ¡d5©­­�‡~8?üðfŸcÖó,å£rËr¬I)ϳœjU.ÿP¦:Æ©~^ÛÛû¼KclŒýã;aGøNØ 8%3räÈ9r¤B¬§[·n1vìX…(2GCŽ"Y¼xq,[¶¬ÁòÆž;ÑÔ³(ZÚ¶)ë·­¨¨ˆ�F�=JZ�yóæÅÒ¥KK^‡,µiͱ(×s+‡óÍrn©�¥skýã5–έ½�›ïÚ×¹ù ¦÷=Ågй•Ó÷”¾}ûƽ÷Þ+àp´¾ë®».n¹å–²>ÆÞ½{Ç”)SJnDD|ðÁ±dÉ@3l²É&9× 8©‰t ýúõ‹ûî»/öØc�VÙ_kí =ò•ìT¤èÝ»wÜ{ア뮻¶Ú>‡®ðÍ$àÈNEÚ¹nݺÅwÜ»ì²K«îWÀÐ|ùž-Ò‘ÞS(G;Ö¹sç¸é¦›âÓŸþt«ï{§�vŠM7ÝÔ 4ƒÙ©H;UQQ?ûÙÏb¿ýök³ý›ÅÐ<ŽìT¤�ºð ã°Ã+é>fΜ555M®ßwß} @38²S‘vhüøñqÊ)§”tÏ=÷\œxâ‰ñ׿þµÉ6€æÉpTVV*ÒG8Ú™/~ñ‹qöÙg—t¯¾új{ì±±råÊxþùç›l·õÖ[Ç Aƒ @F2š�€£8p`üüç?/é…>wîÜ8úè£cùòåñ /älï9Ù¹E%;i'ºuë·Þzkl¼ñÆ%ÛÇ¢E‹â¨£ŽŠ… þwY¾€Ãm*Ù 8²S‘vâòË/�!C†”¬ÿššš8ꨣbΜ9,÷Ýwã­·Þjr»}öÙÇÔ)€ŒòÝ¢"àh¤&J�¾ã�?>Ž8−õ_[[Ç|¼úê«�®Ï5‹£_¿~% ^Ú«\³8�ÔD Ò¶Ç{ÄÅ_\²þ×­[§žzjüùÏn²�ÛTŠ/WÀa¦|CŽ„uéÒ%®½öÚ¨ªª*Iÿõõõqæ™gÆO<‘³]®7©DxÐ(@s“5ùcÞ Ž†5Q‚t�?>>ö±�•¬ÿþð‡qÿý÷çm7kÖ¬X·n]“ë÷Úk¯’…0íU]]]Ó?æ k¢iÚvÛmcüøñ%ëÿç?ÿyÜvÛmµ]µjU¼öÚkM®ïÞ½{ :Ô d�ë•ÊÊJúG¢®¸âŠèÒ¥KIúþýï—_~y¦mòݦâ9ÙxG6�• =_ûÚ×Jö\‹7ß|3Æ�—÷�ËõüóÏÇqÇ×äúáÇÇ�ü㈈Ød“MbÏ=÷Œ]vÙ%úõë}ûöÝàÿ÷éÓ'V®\K–,‰Å‹ÇâÅ‹ÿûŸçÎ�3f̈eË–¹€vÍ[T²p$¦wïÞqá…–¤ï>ø ¾ñ�oDMMMæm_|ñÅœëwÛm·øÙÏ~ŸúÔ§ znHÏž=cóÍ7ot]]]]<ûì³ñøã�Ç´iÓâ�7Þpa펇Œf#àH̹çž›nºiI>8gœqF¼þúëÍÚ~öìÙ±bÅŠèÙ³g£ë»téGydQ޵²²2öÚk¯Øk¯½âüóÏ�7ß|3{챸ùæ›cáÂ…. ]0ƒ#IÈ Aƒâ˜cŽ)Iß×\sM<úè£-úàå›ÅQ*Ûn»mœ~úé1sæÌ?~|ÉžMКÙ¨HBN9å”’\ÄO<ñDüä'?iööqÄGÄàÁƒÛ´>m´QœsÎ91cÆŒ8ðÀ]0@ÒÙ¨H"6Þxã=ztÑû}óÍ7ã[ßúV懊þÇ.»ì>ø`\}õÕ±Å[”E­·Ýv[Ü{ï½±óÎ;»x€$y‹J6ŽDwÜqÑ£G�¢XÎ8ãŒf=T´W¯^qñÅÇï~÷»6lXYÖløðáñØc�ÅGá’ã!£Ù¨Hªªªâä“O.z¿7ß|s<÷Üs™·ûêW¿O?ýtœ|òÉQYYYöµ»úê«c„ .$ )nQÉFEpÈ!‡Dÿþý‹Úç?ÿùϸòÊ+3mSYY—^zi\ýõM¾Âµ\M˜0!®ºêª¨ªªrAIÈp”ûÿØÜ 3fLÑ?$ßùÎw¢¶¶¶àmz÷îwÝuWœxâ‰ÉÖqôèÑq×]wE¯^½\T@Ùó Žlenøðá1dÈ�¢öyûí·Ç³Ï>[pû�Æo~ó›øÜç>—|=÷Ýwßxà�Š># ØÜ¢’�Š”¹¯~õ«EíoΜ9qÙe—ÜþÓŸþt<òÈ#±ýöÛ·›šî¼óÎñË_þ2ºuëæÊ–‡ŒfÓY Ê[±gM|÷»ß�U«VÔö“ŸüdL�:µ]»í¶[\uÕUqú駻Ȁ’kj*y1–g�¦^Œ¾Ûâ|ŠqžåtÜÅ8ÏŽ»=]³m1–¹ž!(àp”Ì�Ûl³MQ?o¼q 0 hÇ8þü5jTŒ5*ï±ôìÙ38à€v=Ëá�C‰ÁƒÇßÿþ÷vý�V9ýñ÷�Vûùb’ê-clŒý0òoL[ý�(6G#—#¢;)d IDAT^þm„ ^' @Ù[¸paì¾ûî ±38ŠäÕW_�¹sç6XÞØ=SMÝGõÑåÆ +ÚÃ0çÏŸ/¼ðBÞcˆø÷s7¶Øb‹3vk×®�Ç<–-[V”q+eÛ¦”âZû|³Ô \ÇǹuÌs3–Î͹ÿß•öüô÷ʹN�[–¶O<ñDl·Ýv�¶7ƒCÀQ2wß}wÜrË-E믪ª*^yå•¢ý€?üðÃcÞ¼yyÛNœ8±C…ÿ©õ®»î_øÂbåÊ•.f ,ÔÕÕ5¹NÀÑHM” < :46Úh£¢ôu×]wnì½÷ÞqÊ)§tÈzWWWÇgœáÂÊF®×ÄVVV*ÐG8ÊÔg?ûÙ¢ô³råʸúê«ó_�:Åĉ;tÍO;í´4h�‹( ^›�Š”©b½öÞ{ï�wß}7o»Ñ£GÇ®»îÚ¡kÞ¥K—òå#× orjHÀQ¦vÚi§¢ô3yòä¼mzöìgŸ}¶¢GÄ~ûí_üâhs¹38©‰”Ÿ^½zE÷îÝ[ÜÏ_ÿú×xùå—ó¶ûö·¿›m¶™Âÿ¿‹.º(ªªªhSŽlT¤ m¾ùæEégÊ”)yÛl¹å–öÁ¢MÙvÛmãÔSOU M 8²ñšØ2Ô¿ÿ÷±råÊøõ¯�·Ý¨Q£¢K—.mrž¯¾újÜzë­Q]]Œêêꨮ®ŽM7Ý´ÍÇ`̘1qóÍ7ÇÚµk]�@›pd#à(CŸ]䡇Š+VämwðÁýøëêêâÉ'ŸŒ¾}ûÆÐ¡C›l×§OŸ˜:ujƒåƒ ŠcŽ9&F�ÝfaǦ›np@üæ7¿qAm"×[Tó™ÏÄã�?Þªã°Ï>ûÄ Aƒ\�@›pd£"e¨¥Ç_þò—XµjUÞvx`‹öSSSçž{ntÐA�βxíµ×òö±ýöÛ´¯¹sçÆ‰'ž'NlµçbTTTıÇë‚ÚD®€#BÈÑ JP~Zz‹ÊÓO?�·M¿~ýbï½÷nö>~ÿûßÇg?ûÙ˜4iRÔÕÕ5Úfþüù±råÊœýäšÁñQõõõqÓM7Å!‡óæÍk•±=z´WÆmBÀ‘�j”¡–Îà($àØo¿ý¢²²²Yý_{íµq 'Ä¢E‹r¶«¯¯�Ù³gçl“%àø�_|1¾üå/·Ê@7Ùd“8à€\”@«Ë÷,BÝ�€£�yÿý÷ãÅ_ÌÛnÛm·ÍÜ÷Úµkc̘1qùå—çMÿ#ßm*Í 8"þ}{̘1câî»ï.yM÷ÙgÐêÌàÈF5ÊÐâÅ‹›½íßÿþ÷&oY_ß¾}3÷}á…fž5‘ïA£[o½uôèÑ£Ùç{öÙgÇsÏ=WÒñØc�=\”@«pd£ehÉ’%ÍÞö�7Þ(¨]Ÿ>}2õ{ï½÷ƤI“2O¾1xðàfŸïš5kâ›ßüf,\¸°dã±ÓN;E÷îÝ]˜@«pd£e¨%Ç?þñ�‚Úe™Áñ·¿ý-¾ÿýï7ëx y“JsoSù�… ÆÉ'ŸkÖ¬)ÉxtîÜ9vÛm7&ЪÙ¨FjÉ-*Å8–,Y'Ÿ|r¬^½ºYÇóöÛoÇ|�³MKŽˆˆçŸ¾Ù!L!ܦ´6ÍFÀQ†Êé• &ÄÛo¿Ý¢d¾çp#àˆˆ¸çž{â÷¿ÿ}IÆDÀ´¶|GsߌÙ^ 8ÊPsgp|øá‡1wîÜ‚ÚöîÝ;o›yóæÅã�?Þâó)Õ›TsÓM7•dLvß}w&Ъܢ’�j”¡ùóç7k»+Vĺuë j»téÒ¼m¦L™’71,D¾€£ºº:ºvíZ”ÚÍœ93^~ùå¢�IÖ‡²´”€#Õ(C/¿ürAÄG-[¶¬à¶óæÍ˹~ݺuqÏ=÷å|ò�:uŠí¶Û®hõ+Å,Ž.]º¸0€V%àÈF5Êô"~úé§3o·|ùò‚Ûæ›%òÄOíÕ«­ñ&•õ=øàƒñÎ;ïuL*++Ýß´*ÍFÀQ¦f̘‘y›,G¾guüö·¿-Ú¹,X° ÞÿýœmŠp¬]»6n»í¶¢�‰Y@k2ƒ#Õ(SÍ 8Šy‹Ê‚ Šz>­õ&•ÿ˜КÙ¨F™ú׿þ³gÏδM]]]ÁmóÝ¢Rì[<æÌ™“s}1ŸÁñï°§%¯·mL±„ PG6ªQƲÎâèׯ_ÁmgÏž�ó�+‹-*ê¹ä»%f›m¶)zý yöG¦‹?@+pdüͦåëÉ'ŸÌÔ>KÀQSSÏ<óL£ëV­Z•÷™Yå»%¦G�±É&›uŸÅ 8Ö­[‹/vQ­ÆCF³p”±§žz*ÓmYŽˆˆiÓ¦µÚ‡$ß ŽˆâÏâÈ÷Ü�,Þzë­œ3^Š-ß ozÜ�€£ŒÕÕÕÅwÜQpû¬3 š 8ºuë›m¶YQÏ¥�€£ººº¨û,æ Ž|Ï(6·¨dÓY ÊÛ”)Sâ»ßýnAoðèÒ¥Kl´ÑFñÁÔ÷¼yóâÕW_��wÞ¹Áºm¶Ù&Þ}÷Ý¢�ÇÂ… cÍš59Ïcë­·.jífÏžõõõE™‘òæ›oº€iì;ISßSе¼T}—ò¸‹qŽ)ŸOk�e[]›®ÙÂÚ÷éÓGÀ!àh}x`£·Xã3oÞ¼»ÑY -9ŸÚÚڜǑGÛo¿}Q¿$¬\¹26Úh£�ïСCãúë¯Oò�y9ý‘ïÈ_@R>ŸŽüÄû’é‡QÇú7¦Ô×@±ù;ô‘zDD½2üÛ„ b„ @ÙÛo¿ýâå—_VˆÿgG‘¼ôÒKñÆo4XÞØSo›zn®¶#FŒ(è!¢K–,‰éÓ§g:†½öÚ+¸Áú¥K—þ÷Í9ÞÆ–ï¹çž±Ã;4yì555ñÐC­f‡vXôìÙ³Åã{Ï=÷ÄŠ+ŠR‡ÖjÛ”r=Þ,Ûg©AJçëÜÒ=·öúÌrn®SçæÜÒùûb,�›skÛs˲ýe—]'œpB“ÇâGIüêW¿Š[n¹¥dýõ«_mò‰õõíÛ7.¸à‚X¶lYÁ}ï¸ãŽ1}úô ¦7õíÛ7~üãÇ¿þõ¯¢�Ø1câ‚ .hr}×®]ãûßÿ~¦?.ùŒ9²ÅÇ믿ßùÎw\ä@«ò�ÑlT#>ø`¼úê«ù´S§øìg?›©ï×^{-{ì±Ë÷ßÿ¢žC¾7©tíÚ56ß|ó¢î³G�-îcÆŒ.@ Õåû©‡¤áÃ?Œ‹/¾¸ ¶#FŒÈÜÿÕW_Ý`ÙI'�TÔ÷*òªØb¾IeÀ€ѽ{÷÷#àÚB]]]îôŽ ë¡éøÃþO=õTÞvûí·_æö³fÍŠÉ“'o°l»í¶‹C=´hÇ?þü¼mª««‹¶¿Ýwß½Å}¬Y³&þ÷ÿ×Å´:·¨d£‰¹è¢‹ò^äýúõ‹ã�?¾Y}¿ýöÛ,ûþ÷¿_ÐÃM ±bÅŠX²dIÎ6åpüùÏŽU«V¹ð€V'àÈF5óÊ+¯Ä}÷Ý—·Ýé§ŸݺuËÔ÷ûï¿ßýîw7X¶õÖ[ÇgœQ´ãŸ7o^ÎõÛl³MÑöUŒ€ãþûïwÑmÂ38²Q�]qÅQ[[›³Íæ›oÇ{læ¾g̘·ß~ûË–.]Z´cÏpkG÷îÝc·ÝvkQ‹/pmÆ38²Q�-X° ®»îº¼íÆ�]»vÍÜÿøÃ¸çž{þûßßzë­¢{¾�ë!£_ùÊWZü•;î¸#Ö¬Yã‚ÚD¾[T***i=ŽD]wÝuñ·¿ý-g›þýûÇ1ÇӬф bÒ¤I±fÍšÏåh‰|ÇV[mU”òÈ#�lÑökÖ¬‰;ï¼Ó…´ÏàÈF5µnݺøö·¿�w†Áøñãcã�7nÖéÜsÏ�!C†Ä /¼P´ãÎw‹JUUUl±Å-ÚÇ Aƒb¯½öjQ¿þõ¯ãÝwßu¡mFÀ‘�j$ìµ×^‹+¯¼2g›þýûÇÕW_Ýì}|ðÁ±zõê¢s¾-ÇèÑ£[4UkíÚµqà 7¸À€6%àÈF5÷‹_ü"þò—¿äl³ÿþûÇ©§žZÇ»`Á‚X»vmÎ6-y“J¯^½šu[Îú~þóŸÇìÙ³]\@›pd£íà‚?ãŒ3bÕªU9Û�{î¹EymjKÕÕÕå}¦GKfpL˜0!6ÝtÓfo?{öìÍx(æï½œ?èÖC Ò7gΜ8ÿüós¶©ªªŠ_üâÑ»wï6?Þ|Ïáhî›TvÜqÇ8餓ZôÇ㬳ÎÊ;à5xMl6ªÑNL™2%&Ožœ³Í6ÛlS³ò=‡cÀ€Íê÷â‹/ŽÎ�;7û¸&MšÏ=÷œ‹ ( õõõ¹Ð 86¬‡´?øÁâùçŸÏÙæ€ˆK.¹¤M?ùŽæÜb2räÈ>|x³�饗^ŠË.»ÌE” ·¨d£íÈÚµkã›ßüfÞ×›žtÒIqã�7F—.]Úä8óÝ¢²Ùf›eêoÇwÌû6™\æÌ™ÇsL¬\¹ÒE” ·¨d£íÌ;ï¼cÆŒ‰uëÖål7räȘ:uj›<“#ß Ž~ýúüAÝj«­bêÔ©±ñÆ7ëX.\GydÞP µå›ÁQQQ¡Hëp´CÏ<óLœsÎ9yï×Ú{ï½ã׿þul±Å­z|ùŽN�:E¿~ýòöÓ·oߘ:uj³�¿¦¦&Ž>úè¼3JÚ‚gpd£íÔäÉ“ãÜsÏÍÛnç�wއ~8vØa‡V;¶šššX¾|yÎ6ùnSéÞ½{Üyç�1xðàfÊ+â„NˆW_}ÕÅ”%ÏàÈF5Ú±_þò—… ˆßüæ71f̘¨ªªj•ckɃF S¦L‰¡C‡6kßsæÌ‰¯|å+ñ§?ýÉE”-ÏàÈF5Ú¹I“&rôêÕ+.¸à‚˜1cFì¿ÿþ%?®|GS38=ôИ>}z|úÓŸnÖ~g̘x`¼þúë. ¬™Á‘�jt“&MŠóÎ;¯ ¶ƒ ŠI“&ů~õ«Øe—]JvLóçÏϹþ£38z÷î7ÜpCÜpà Í~0êM7ÝÇ{lÞÛcÊ�€#Õè n¿ýö8ÿüó n¿Ï>ûÄ´iÓâ'?ùIæ×¶"Ë ŽÏþóñä“OÆ¡‡Ú¬}ÕÔÔÄøñãcâĉy§x” G6�• ã¸í¶Û¢¢¢".ºè¢‚ÚwêÔ)Ž>úèøú׿O=õTüîw¿‹'žx"-ZÔâcÉp <8N;í´8ꨣbûí·oö~xà�¸ð ‹rÌ­IÀ‘�€£ƒ¹õÖ[ãý÷ß�‹.º(zõêUÐ6]»v�ýöÛ/öÛo¿¨¯¯�çŸ>¦M›Ó¦M‹×^{­YÇñî»ïæ\¿ÿþû·èY ÿüç?ãì³ÏŽ™3gt IŽlÐ=÷ÜO=õT\qÅñ¥/})Ó¶1tèÐ:thœsÎ91gΜxüñÇ㥗^Š9sæÄܹsóΖ¨¬¬Œ®]»–äÜV¯^×^{m\ýõ±f̓ $KÀ‘�€£ƒZ°`Aüññµ¯}-¾÷½ïEuuu³ú4hPœrÊ),[¹re,X° V­Z«W¯ŽÚÚÚ¨­­�ªªª¨®®Ž­¶Úªè¯£­­­�©S§Æ�7Þo½õ–’—/ਨ¨P¤õ8:¸ûï¿?|ðÁ9rdŒ7.† Òâ>{ôèÛm·]«MMMLš4)n½õÖX²d‰Ú 38²puuuñÀÄ<ŸÿüçãÔSO�áÇGçÎå{y,\¸0n¹å–¸óÎ;cÅŠhwÙ8ØÀþð‡øÃþýúõ‹<0FŽŸùÌgÊ"ìX±bELŸ>=}ôÑxôÑG=ch×êêêr®plHÀA£Þ{x mæ½÷Þ˹¾G�Š@A´™ÚÚÚœëJÀA›Y»vmÎõm´‘"Pm¦¾¾>Ö¬YÓäz38(”€ƒ6µzõê&×™Á@¡´)Å à MåºEEÀ@¡´©\38ºwï®@DÀA›ÊpTUUEUU•"�Wg%h?ªªªb×]w�Ýwß=>þñ�GïÞ½£K—.ѵkר©©‰¹sçÆ¼yóâÙgŸ�W^y¥,Ž9WÀÑ¥K—¼¯“G;0xðà8í´Óâë_ÿztíÚµ mþùÏÆ<·ÜrK,_¾¼ÍŽ=×38""jkk 0y¹E%a[l±EÜ~ûí1cÆŒ8úè£ 7"">ö±�ÅYg�3gÎŒÃ?¼ÍÎ!× Ž5kÖD]]�� /G¢FŒO<ñDpÀQQQÑì~6Ùd“¸æškâšk®‰N�ÊërXµj•�  Ž�;6îºë®èׯ_Ñú<üðÃãÊ+¯lQXÒ¹^»råJƒ @A‰9ꨣâ¼óÎ+IqôÑGÇØ±c[õ|rfpP(GB¾øÅ/Æ•W^YÒ}œuÖY±õÖ[·Ú9õìÙ³ÉufpP(G"zöì?ýéO£²²²¤ûéÞ½{\rÉ%­v^nQ ‰øö·¿›o¾y«ìëË_þr 8°UöÕ£G�&×¹E€B 8°Í6ÛÄ©§žÚªû5jTÉ÷Ñ¥K—¨ªªjrýÒ¥K >p$àˆ#ŽÈ”¡‡Zò}äº=%"⥗^2øðìÝyxLwãÿÿWöØb‰ˆ]‚ÖÒ­ª¶Zµ/µöc�]‹¢ÔUEÑâ¦Ö¢µ–u«¥ª”›Ú÷ÖÞµoµTmA"%I~ø™¯1Kf’™˜Ãóq]½*ç=sΙsÎÌ9çuÞ ‡p@F„ �+Uª”BBBܺ {ŒJÒÁƒÙù‡px¸^xAÅŠ{"Ë.Q¢„[ço/àHIIÑáÇ9!àðpåË—bËvwÀa¯#ÓóçÏ+66–àþÄ–]²dI·Î¿T©R6Ëhžp‡‡+Z´è[v¶lÙÜ:{ ÀÎÝ}ÚçÖù—.]ÚfÙ�Øù‡px8w‡ öܾ}ÛmóPXX˜Õ²èèhíÛ·��p‡‡{’mº3\yþùçåããcµlÍš5JJJbçFÀááÜY‹"5ÇŽsÛ¼íu0úË/¿°ãN!àðp‡~"˽{÷®¶lÙâ¶ù—)SÆêô›7ojçÎ�ìx€S8<ܶmÛžÈr7oÞ¬øøx·ÌÛ××W 4°Z¶víZÝ¿Ÿp ‡‡;sæŒ.^¼˜áË]±b…Ûæ]³fM›£ÃÐ<�°yóæ ]Þ‘#G´jÕ*·Í¿U«VV§ÇÄÄhûöíìp€Ó8 `Μ9JIIɰå iÒ$Ý¿Ÿ H3úà0 ï¾ûNuêÔI÷|._¾¬ˆˆ·ÖÜ(Uª”–-[¦   «å»wïV“&M2t”ÀÓ‡€Ã€‚ƒƒµyóf…„„¤y'OžTDD„®\¹â¶õlÚ´©ÆŒ£L™2Y-���WµjÕtþüyv* ]h¢b@ÑÑÑêСƒþùçŸ4½ÿÇTÆ ÝnøûûkìØ±š4i’ÍpC’ÆŽK¸p jpØÛo¿­ùóçËÏÏÏá÷lÛ¶MmÚ´QRR’[Ö©D‰š}º|||~Ïž={ôá‡*22Òeë‘3gN}úé§j×®]ªë²k×.EDD(!!�p ICÙ Æuúôi]½zU5kÖ”———Cï)X° š5k¦³gÏêÌ™3éZ~`` :tè Ù³gëõ×_—··ýVO‡VDD„îܹÃθ 58ž5kÖÔ”)S”-[6§ÞwôèQMžø@»wïfÇÜŠO±àà`õïß_©vþéJ»víÒÈ‘#µoß>v Cp<^|ñE 6L¯¿þºÛ–‘˜˜¨mÛ¶iΜ9Ú²e �¡8ž!%J”PãÆ�Õ¸qc)R$ÝóKJJÒÎ�;µ|ùr­^½Z111ldÀAÀñŒzå•WÔ¸qc•-[V Thh¨Ýf,))):wîœ>¬Ã‡ëСC:|ø0¡À#p@’äçç§üùó«`Á‚Êž=»nß¾­Û·o+66V·oßVLLŒîݻdžx$`xÞl`tÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`x®| IDATÀð8€ápÃ#à†GÀ Ï—M�º¬Y³*88X¾¾¾º~ýºbcc•’’†ÀCpð8~~~jÞ¼¹^yåݽ{W{÷îÕÊ•+¹‘€Ç§AAAÊ–-›Íÿ‚‚‚”5kViøðáºrå Î@û÷õ×_WµjÕT¥J…‡‡Ëßßßì5‰‰‰ŠŽŽÖîÝ»µvíZmÙ²E·oßNuÞÍš5Ó»ï¾+Iš9s¦vîÜéÔºeÏž]-[¶TéÒ¥uñâE­\¹R'NœpjÊ–-›²fÍj:^ýw–,Y̦oݺUË–-ãÀx4/IÜ1à™ªmÛ¶f}‡ ¦… >õû%$$DóæÍS™2e̦oÛ¶MíÛ·×½{÷8xŸsçÎUÅŠ ³¾·nÝÒ믿.IÊ•+—öïßoq³›š*UªèÔ©Sì|êÝ»·BCC�zobb¢–.]ª¯¾úÊf˜U¢D ­]»V’¤Þ½{kñâÅ/£téÒš;w® (`švïÞ= 8СsÄ믿®üQ~~~N}¶É“'kÔ¨Q �F <³¼½½d˜õÍ�;÷3±_ÆŽknHÒ;ï¼£O?ýT#GŽäà} äË—ÏPß¿L™2™þíåååt¸cxóÍ75nÜ8………Y”ݼyS—/_Ö�7”’’¢��åÉ“G¹rå’———¤áHË–-Õ¸qcÍž=[“&M2«Ñáïï¯iÓ¦™Â�‡ç"GùûûkúôéfáÆÃé£F�ÒáÇuøða»óðññq:ÜÀ(8ðÌJJJÒÅ‹ͦùùù)Ož<¦‹UG$''ëòåË¿>(((M7vFºL«àà`Õ®]Ûfy£F�8žÎÏÉÉÉÚ³g�Î�;§Ë—/ËËËKÅŠÓ»ï¾ëPЧŸþYgÏžUbb¢òå˧B… ©jÕª¯‡ŸŸŸüüü”˜˜¨û÷ïëØ±cN¢¾¾*T¨�YcjÓ¦�FŒavó©Ù³gkÓ¦M:qâ„Õfr¡¡¡ªY³¦jÕª¥jÕªÉÛÛ[���êÑ£‡êÕ«§®]»šB‡�ªT©R�ƒ£ªT©¢âÅ‹Û>^sæÌIµMôÑ£GõïÿÛépC’tæÌ}÷ÝwjÑ¢…6l˜jµâg!à8sæŒÝò¿ÿþ›pã)‘-[6»å‡VíÚµ5a›}œ?^?ýô“ÝùüòË/VÃ�‡ßõeË–©F�š?~ªëœ%K›e'OžTûöíµ}ûvv®Á´lÙÒ,ܸzõª6l¨iÓ¦9ÝçÏÃã }ûöŠ‹‹“ô ùȈ#ôý÷ß[­%áL•Ôj Ú:ÖSóÏ?ÿhâĉ0`€€xíÛ·Ïnù† \¶¬ÿýïª_¿¾V¬Xaó5ÏBÀqëÖ-»Û`éÒ¥˜O�,Y²Ø}j½wï^5lØ0ÕÀK’Ξ=›®BéAM‘~ýúiüøñv_—5kÖTç5nÜ8v°�”/_^£G�6ý«V­ZéàÁƒéšï† Ô¨Q#]ºtÉ4ÍV¿ÎÛ·o×­[·l–¯\¹2]ëýã�?Z4ÝÀH8âããí–ÇÆÆºty‰‰‰êÑ£‡Í ÔÔžx?-¨ýû÷[L_·n�&MšÄ�ù°w,Ÿ>}ZíÛ·WBB‚CóJ­F�3OàÇ�ow {58b”]y{k„ fý¸ôîÝ['OžtÉü�?®F�éúõëv_çL•ëׯëã�?6ÕyÔŒ3´zõêt¯7Ç0ÀÈèƒð IIIêÛ·¯^{í5‹á íõ3ð4¹qã†7n¬ÿû¿ÿSÙ²eu÷î]íٳǥ5fðdÙ:–ïß¿¯®]»*&&扭ۀôæ›oZí“Ñ·nÝRBB‚Ù(ðLMš4ÑsÏ=gú{ûöíZ»v­K—qùòeuéÒE‹/–¯¯õK.géAí�*Uª¨U«VzþùçuåÊ­[·N»vírÉ:[ O0 ÀÃÄÆÆê³Ï>Óœ9ș? MT½Ñ]¼xqªý À˜lÕà˜;w®Nœ8ñD×-11QC† Ñܹs-Ê©Á!‰~b ÀÇÇGŸ|ò‰Ù´ï¾ûÎ-ËÚ½{·¾üòK :Ôj¹3MTº|ùrªMªxÑDð@ëÖ­³hþ,xºY«ÁqëÖ-}õÕW±~6lÐŽ;,¦;RƒÆP®\9)RÄôwBB‚¶nÝê¶åÍš5ËlhV³ 1o.ÅpΪ€‡úöÛoÍþ ´ÙI`$Öjp,Z´ÈåýÚ¤ÇìÙ³-¦9Zƒž¯Zµjf_ºt)Õ~—Ò#99YC† ±Zæl`à¡V­Ze1µ8ð4xü8NIIѼyó:\,MTžqqqV§wïÞ]¹råÊ�åïÚµëÿ]ˆÑD—ᬠd bÅŠ9ýžýû÷›þM <  8>ìÑëzìØ1Ó¿ 8ž¶†# ÒÔ©S3d8î�7šþM \‡€È@eÊ”qú=üñ‡fÍš¥Y³fYtNÑ£5‘ <ÑÉ“'Mÿ¦‰ÊÓ!>>^W®\±ZöÎ;ïhΜ9Ê�;·[×áÑ€ƒ¸Ž/›È8U«Vuú=wîÜÑàÁƒz­¿¿¿²fÍjõ¿,Y²(kÖ¬Z¸p¡þùçŸT礂 šþ»ÿ¾¢¢¢tþüy�8qB))).Ù&^^^Ê”)“2gÎlú¿­_¹rEk×®uÉrË•+§:uê(<<\yòäQHHˆ|}}¥ëׯëÒ¥KÚ²e‹~ûí7Ý»w�ƒ×…ÖDJJJÒ©S§Õ¯_ßjYµjÕôÛo¿iòäÉZ´h‘YGÏ®rþüy }:]Ëòóó³z>|øïlÙ²iåÊ•ŠŒŒtè»ñðûY°`AIÒõë×uáÂ9rDÉÉɶ ÃÃÃU§N•(QByòäQhh¨²gÏ®˜˜ݸqCÇŽÓž={ô믿Úlš•žmúÆo¨J•**T¨�òæÍ«à×§Ÿ~ªš5kÚlöõüóÏK’7n¬�êܹsš3gŽþóŸÿèþýû-§iÓ¦:t¨²eËæÐ¹1**Jÿýï­_,ûúªN�:êØ±£Þxã ›óˆ‰‰ÑæÍ›5a§ÎÎ TçÎ�Õ¤IÓvz\þüù%I•*URçÎ�« hÚ´iŠŽŽN×ò ( O?ýTuëÖµ9²[ñâÅMÿîÛ·¯þþûoÍŸ?_Ó§O7ë`8ƒòññÑçŸî–y)GŽ¿¾D‰‡———zôè¡nݺ)gΜ©Î#$$DmÛ¶U³fÍ4zôhýûßÿvj�³gÏž!�ù=úùš4i¢Aƒ)44Ô¢sÛww̘1Nm� hÆŒz÷ÝwÕ³gO‡oöR¬�ªeË–¦c_’îß¿¯mÛ¶éĉŠŒŒTöìÙõÜsÏ©zõê¦-/¼ð‚¦N�ª6mÚhàÀ�fÍz<ÕòåË5tèPØ}�¿¿¿Þ{ï=½÷Þ{JHHÐo¿ý¦_ýU;wîÔ‰'Üö´ÞËËËêo•‘eΜYü±>üðC³À!%%E{öìÑü¡«W¯*S¦L S­ZµLç£ððp 6L­ZµÒÀ�µgÏžT——%K§Î3%K–´p´nÝZ}úôQÞ¼y:·½÷Þ{jР�f̘¡‘#Gº´¶cãÆ�5hÐ S€ñ¨äädSÍ—9r(44Ô´�ƒ‚‚Ô­[75kÖL}úôц œ^¾¿¿¿ºwﮞ={ZŒD´oß>íÛ·OW®\‘¿¿¿Š)¢5j(Ož<’¤B… iÀ€jÙ²¥ ¤­[·ra€€0²¾}ûª|ùòn™÷�4oÞ<¨páÂ*]º´Í§*ŽGeÍšUS¦LQ­Zµœ^v`` †ªüùókèС¿ïÊ•+¦*«ÞÞÞ¦PÁüüü4yòd5lØÐlzRR’–,Y¢ùóç›�T#I¡¡¡jÑ¢…:uêdº@óóóÓ| :uê(""Bþù§Ýå^¾|Y±±±v÷Åã’’’tòäIS€b¯vÙ3gôçŸ*$$ÄáÎg###S]odŒŠ+jòäÉiÁ5j¤ÀÀ@½ÿþûé¾É.Uª”-Zd1tõ¼yó4~üx]»vÍâ=™2eR·nÝÔ«W/SM�7ÞxCkÖ¬QÇŽ=~tœ˜˜-Y²D­[·vø=ªQ£†jÔ¨ašÇîÝ»µk×.íܹSÇŽsYà‘’’bÖ4ÎZm#É›7¯~üñG=÷ÜsfÓ7lØ !C†èüùóV»Þ?ü-Uª”–.]ª¾}ûê‡~°»Ì“'OjÞ¼yòóóSÁ‚U²dI»}«<~nôóóÓ¨Q£áüŵ¯¯zôè¡‚ º$ˆ ÔôéÓ­ž§7lØ ~øA›6m2«áëë«úõë«W¯^*Y²¤$)wîÜš;w®¾üòKM›6ÍáåçÊ•K .´¨Ù¹}ûv}þùçV›úøøè½÷ÞÓ�!Cl ª.\¨aÆiúô霸…—¤6`©I“&š+vîÜ©† Ú Ò2eʤ¶mÛ:½.���š6mšE¸±téR§Â éA‡��?‰õõõÕ¤I“ܸҞ={Ô¾}{‡úÕqV‰%Ô³gOmÞ¼Y«W¯VÛ¶m�êTÙ–¸­“YWòòòÒ7ß|cnìÛ·Ï©pCzöïßßbú˜1cœ®�c«s×€€iÀ€¦pcÖ¬YªZµª–,Ybuô±;wîhÑ¢EªV­šÍNE½½½Õ³gÏ4mÑ#GZ­ÅõñÇ;nHÂLkŸ·W¯^vßgí:æÔ©S�ìöÐåË—Õ«W/‹ÚC† Qxx8'€' UéÒ¥Íþ{î¹çlµöAF³5¬^Ö¬YÕ½{w5lØP)))êׯŸ&OžìÐГçÎ�Sûöím¶3oÞ¼¹Í^ñ�áÌ…›5*TPŸ>},¦oÚ´)M�«ÅÄÄhäȑӋ+æð͸¸8Mš4ÉjY®\¹ôÖ[o¥{»=ÚÎûþýûúâ‹/ø¢z�1cÆ(sæÌJIIQÏž=5g·ÞwëÖ-Óˆ>Ö´hÑÂêÓ|{lQå<>>ÞêqîˆÉ“'[ŒøS´hQ·u®ìJÛ·oWµjÕ´}ûv·-£\¹r3fŒvíÚ¥öíÛ;<*Š-‡öøíÚ¹sgU©RÅbº3ý5=jùòåͳgÏît3‡3gÎØlVѶm[uëÖM’4a <Ø¡‘ž¢¢¢ÔªU+ݽ{×jyõêÕ-šè¤æÿþïÿÔ¤I‹éGõqT�lž êׯo³—æÍ›[­É3lذ4 U½eËmÚ´ÉlZ¦L™4iÒ$y{s;€€xâkö_ZNúîe³ìaÕÒÿûßZ°`�Só=xð Í'¼™3g¶h'œéÆÎËËKcÇŽµzÃ7a„4Ï÷—_~ÑÑ£G-¦7mÚT¯¿þºCóøá‡tãÆ «e}ôQº·Û£OJ׬Y£ .ðEõ ›¥Lœ8Ñé!U/\¸`³I[hh¨©AG”/_ÞjS¯Ÿþ9MÃ>Kúí°ÖB»vílÉìI®\¹¢æÍ›«C‡éXí Õ¨Q£´dÉSÆi]_Oª�ZLßµk—C}Ùb­ÏŽ*UªØºõqwîÜQ\\œÕ²‡ëüË/¿hܸqN­ÛÅ‹mvÜéíííTˆ�#G«áyrr²Óµ_š4i¢Ì™3[- T¾|ù,¦iøðáÓ�?®Í›7§yÿYq­|ùòª]»6'À“6fÌ•,YÒì¿"EŠè¥—^RÛ¶mµ`Á‡žü¸‹½Ž¿¼¼¼tîܹ4w|6wî\»7OORõêÕ­Vé=qâ„8�®í¹páB«e©Uó}(>>ÞfÓ¡Ê•+륗^J×gô"ß‘Îã�ñ8àô�ÓC ,0YãQ��n`O×®]­N_ºtiº>ÛãOg¥}Ø8Ó1ð“¶~ýzÕ¨QC­[·ÖúõëÝZ¿öÚkZ·n�KaOÔ©S'«5Ò{ŒmݺÕêˆ$ï¿ÿ¾KÖÛËËK7nÜЀÒôþùóçÛ¬áè̾nß¾½ÕŽd7mÚd³v¦-uëÖµ[nm¨ä6mÚX]~z÷ßîÝ»­ÖDëÔ©'€'JNNVtt´6mÚ¤¾}ûªråÊn­öœS¦LIssðàA]¼xÑjÙãÃf´îÝ»[�¾eË—ÜüXS¥J‡Ã‰ï¾ûÎfSk£í8*{ö즀ãÈ‘#Ú»w/_HôÍ7ߤy(Ñ›7oÚ é^|ñE‡æQ¸pa«7<ÑÑÑÚ½{wº>Û‰'¬>�ˆˆ°zå©RRR´eËuèÐA*TÐÀ�µuëÖt÷“ó¸ÐÐP-]ºT*TxªŽñÌ™3«]»vV˙Ǟ¸¸8«}ÖÔ®]Ûe5…æÌ™“æZ„‘‘‘úý÷ß­–Ùê(ØZà`ë†?-M,þùQ÷ïß×¹sç̦ùúúÚ Œœickyüñ‡ÅôJ•*9U 8€'äï¿ÿV›6mÒU¥ÓnݺåtùÇ:tÈæ�ö“R¬X1›ÍE¶mÛ–îù_ºtÉfõõÖ­[;4�˜˜ÍŸ?ßjYýúõÓÜ1mË–-MM ¨½á™ÎŸ?¯�7ºå{gk‡ÇµmÛÖjó­ãÇ�§:Ü£#ÁÀõë×-¦çÌ™Ój‡¿FpõêUýç?ÿQDD„^xáuéÒEK–,±èo$­üüü4cÆ ‡÷Ÿ4jÔÈêyàÒ¥KºuëVºço­£kÕ«W/Ýó¾ÿ¾Íßçô~GsäÈáÐû7nl3”HËÑ[V¯^mÜÕªUËj³•¸¸8— }l«£ò p’@ÀÁ½{÷ôÑGéæÍ›³NÛ·oW|||ºæakäG/âÜÁÚ°¸�ÞÀ¹‚­ù8Ó¾zÆŒVŸ{{{›:¸s†———Ú·o/éÁ“øåË—óÅó@Û¶mKwˆ`ëÆ:((È¡÷Û:N]5Œ©­ÚIåÊ•3üþ‹‹‹Ó/¿ü¢^½zé•W^Ño¼¡Þ½{kÑ¢EOÁ�‘7o^M™2Å#:§v…·ß~û‰c/¿ürºç}øða›£]eÔ¹ÑZǬ҃€(-ÁÚèÑ£­v~zýúu«¾Úú�°7Ú“+öß+¯¼ÂI`·nÝrº§wwJO'oÙ llõÈžÞ|óM«ÓcccívºêŒS§NY�^´hQ‡‡+¼zõªÍ¶Ì-Z´pºóÁ*Uª˜j~<é¾_`›+†?¶ÕI­µöò�Ëš5«Í¦,¶šœ9ËÖ±û4Þ¼üõ×_Z¼x±>Äp} IDAT>ùäUªTIåÊ•S×®]5gΧ�wÞyÇæï—ÑØªEçîċ;Ï�kØ¥¦bÅŠV§ÿùçŸiZŸóçÏ«nݺڲe‹îÞ½«Û·okݺuªY³¦ÕÀÄÝûÏÖy²\¹rOMÈ€€x&üôÓO.oÃ�VÇŽK÷|xª7øõêÕSÖ¬Y }Œ»ó Ò×_m÷8²Öw„‘Î�ö:«vE Ф¤$»ÍäŠ/n³Ez÷_–,Y4vìX»!”†”àù|Ù@Æ9xð jÔ¨‘¦÷öîÝÛÔÛþ¼yóÒµ®¸áOo_®f¯}ó�;w\¶{Oçœ}z8eÊ«#Z©]»vš:ujªóh×®�¼½dÕt.êÙl ñê ß‘¡C‡ªoß¾išo`` C7&9räðˆš_ 4�¯¯¯îÞ½«¯¿þÚíambb¢¾ýö[­Y³FóæÍS±bŬ¾îáÓí­[·ö·wŒ½ÿþûjÒ¤IÚ.V}}U¨P!Óo�«~ƒÝp¤‡½Îf]Qƒ"=û¯yóæi¾~ñññQ¡B…R­iö$;)@À Ž=šæ÷>ÿüó’ E›ÞB=­ö…»/Ì\Q5ú!{a‰³×ÐŽ;¬vŽÚ¹sgÍœ9ÓîM±¿¿¿Zµj%éAçx¶†'RûŽØªïêå_¹rÅc¶G¦L™ôÒK/iÿþý²¼óçÏ«~ýúZ±b…Íšùóçj�±àà`·�“Þä'}n´w¹}ûö]~Μ9Ó ¹{ÿ€DÀd¨´6 5�ø]Yáibo [ý¤…½y9:’Å£¦L™b5àÈ“'�š7onwÈÂF�)W®\’¨½�ôݼ$&&º½V–£Í®2Òk¯½–a‡ô ™RÛ¶mµiÓ&eÉ’Å¢<½M,ž4{Çýû÷•œœüÌcÎxø{nMFœûíí¿¤¤$—žK­1z-ž�€È@i½@y´Ó/WÖFxV¶­+ÛþgΜÙfYZöͶmÛtäÈ«£[tïÞ] .´ySðphØëׯ34,Reo„‚îÝ»kÕªUÏÜ6yë­·4}úô ]æ… 4}útõéÓÇ¢Ì臽&$cÇŽÕ”)Sø"Úa-ôzÈÑQXÜõ1cÆ }ùå—ì$ž.bçÆ�Z·n�Ö­[çÔÈ•+W6ýÛG/ñ”m›–PÂYöæeoì±uѦzõêY-+S¦ŒièÍùóç?ñþàùìõ/ðLn“wÞy牄 óçÏ·ZcÆèC_Ñ¢Eµzõj;vÌT#БýW«V-—ÞŽ;jܸqÚ¿¿Ú´iÃ�4€t#à<ÔØ±c­vÊFÀa[JJЦOŸnµìÑ¡vÓªjÕªV§:tH[·nuÉg˜9s¦Õ!_½½½õå—_ªZµj’¤yóæÙl+ ØòÓO?ÙìëåáÈ<®R£F 5iÒD’góÉ´§ðòòÒÌ™3ÝRË µÕK—.iñâÅOÅ1¶sçN›ÍÚµkç²þ�¤AÑÇ,IJNN¶ÙLÑHìý¶¿÷Þ{.Ù~½{÷–···2eʤ?þøÃ¬ìرc6Ïg­Zµ’¿¿¿Ë>k¡B…L5§¼½½]R2sæÌòòòÊøªÿ{> ™2ez"Ÿ àà°V­Z©AƒVËh¢bßÒ¥K­ÞÀ/^\¯¼òJº.^l=]š4i’ËÖÿÚµkúñÇ­–U­ZUÞÞÞJLLÔ¼yóØÙpÚ½{÷ôïÿÛjÙ[o½å²'ìÙ²eÓØ±cM>Üjpçi‚‚‚4oÞ<åÎ�ÛmËÈ›7¯:wîl6mܸq†Ø>Žš2eŠÕé… Ö|à’eøøøh„ ¦~!&M𔿑¬<ÉÕ«Wm†]E‹U«V­Ò5ÿððp½÷Þ{’¤#GŽèСCï¿àà`S ä ãÇ�7 ½>sæÌ4÷cååå¥nݺi×®]:}ú´Nœ8¡Ù³g»õ{üPXX˜.\¨“'OêÏ?ÿÔÎ�;Õ¬Y3·/×ËËK�;wÖÎ�;õçŸêäÉ“š3gŽBBB8Ñ�€ƒMx–:˜Ý<îîÝ»l¤TnàFŽiµ¬W¯^ižoƒ T´hQ‹é;wî´[¥7-¾ýö[%''Û,ÿå—_Ö“O¬Þž}jýþûïmŽÖ0nÜ8åÊ•+]óÏ’%‹fÏž­¼yóJ’V®\©U«Vfÿ.\X?þø£E®º)9r¤é¦Nz0òÈ’%KžªïÀÚµkmv€<`À€t×’yn”+WN’tàÀ͘1Ã%ûÇ�7¤Žš:uªÍÀë³Ï>Ks‡¸¾¾¾=z´iXäqãÆY}ÝÎ�;mÖâèÙ³§^~ùåto‹/¿üRo½õ–$éôéÓ?~|šç7mÚ4}ñÅ*R¤ˆ¼¼¼”-[6Õ­[Wk×®ukçÁ/½ô’Ö¯_¯*Uª(K–,òòòRXX˜&Nœhê7Ë]&Mš¤ýë_ “———²fͪڵkkýúõ}·$)ÕË\} !C†häÈ‘¦‹km¢b¯·sWŒgoëê 'ÖÅ‹kÙ²eÓkÖ¬©7ÞxÃéùeÍšUýû÷·˜~íÚ5uëÖM))).]ÿóçÏë—_~±YN碎ß4øúúfèúdÏžÝf‡š®¸Ð¶õýÊž=»Ã󈋋S×®]­Vƒ ÑĉMÃ;+GŽZ¼x±éÆåÂ… êÛ·¯áŽ«R¥JiÍš5zóÍ7]:ßÁƒ«N�:¦¿£¢¢Ô±cG%%%95[2ºâx·pÙ;/=.%%E~ø¡nݺeõ\7mÚ´4iþþþš9s¦é)ùíÛ·Õ½{w§šìÙÚNî<7fË–ÍáæçϟנAƒlÎΜ9ij*òÕW_™ú™Ù³g�Ö¯_oóµ={öÔÕ«W­n»)S¦˜Ì´„,'NT§N�$=AìÃ?LóÛfÍšÙì›$þü2dˆ[~#üüü4yòdeÍšÕjyß¾}­>q…Æ�›šÿ=.44TC‡åâ,¥ÖÙœ«†¼óööV³fÍ´}ûvuíÚ5Õ×;ÚDåá“-kÒûôÅÛÛ[Õ«W·Zâ²!YÓ£ÿþÕ]½¼¼4mÚ4§«­Ž5Ê4rÉCIIIêÖ­›¢¢¢Ü²þ¶ª8p@û÷ïç úÿ{íµ×ì–gD �ª]»¶Í²’%K¦;̱õ½+\¸°Õ>{l9pà€† fµ¬zõêZ¶l™Só{ø›¸lÙ2ÓïËÍ›7Õ±cGÅÆÆâX:wîœÙ÷9W®\Z´h‘>þøãt�ãçç§#F˜ýÆß»wO�:uÒåË—�ž_ÅŠm ¦y=³e˦_|ÑjYݺu� ö/]º¤^½zY €_xá­^½ÚéïD¾|ù4þ|SHtïÞ=uéÒEýõ—Ãó(Q¢„;Ò{n”lw¤êå套^zÉáù,X°@‹-²¹ÿgΜéðÈ1>>>0`€Z´h!éÁƒ’>}úØ}Ott´>üðC«ÃÖ†‡‡kÍš5No¯��Íž=[M›65�G?úè#?~<ÍÛûasýf¦× /¼`÷:ÐÏÏÏ%�›§å3רQƒ‹p0?2Äì)›5Mš4QË–-�ÞËËK9sæT­Zµ4zôhíÙ³G'NT�zj58¼¼¼ôÖ[oiôèÑ6_óÉ'Ÿ¤ùÄ[²dIM�:U•*U²¹ü±cÇ:üyÜ%..NÍ›7×™3g̦‡††ê§Ÿ~rèÉŠ¿¿¿ÆŽkñ¤äîÝ»úàƒÜÚ¡Ý‘#G´mÛ6‹éÔÞxÀ××W•+WÖ»ï¾k÷u�7V›6mœþž:ËÇÇG-Z´ÐðáÃm¾¦wïÞ*_¾|šæŸ?~M˜0ÁT3ÂÚò¿ýö[§šUÌž=Ûfµð²eËjݺuêÞ½{ª5OŠ/®iÓ¦ióæÍ*Q¢„¤#µlÙ2]7.)&&F­[·VõêÕµe˳ã¬ÿþÚ¹s§š7ož¦š{eË–ÕŠ+Ì:q�‰‰Q»víl6ã°wÜwìØÑfM^^^êß¿šž*THS§Nµ¹¿ÃÃÃ5pà@§ì�7ê“O>±Z»¢páÂZ¹r¥ú÷ïostª‡òæÍ«#Fh×®]¦ï@bb¢:wîlõwÒ–W^yES§NµYþþûï«AƒiÚÏEŠш#l>Y—¤aÆ9º0@6l°¤lܸQÕ«W·»¾o½õ–Ö¯_o6*ÛgŸ}¦³gϦºü½{÷êÃ?T||¼EYhh¨~þùg {Æ ížßzë-Íš5ËæMWRR’¶lÙ¢Ó§Oëòå˺~ýºòçϯððp…‡‡ëÕW_5«E¥Î�;kïÞ½6—™5kVÓðÝ~~~Ê—/ŸÍæÖ~/®^½jª19fÌ‹ ¡jÕª4h�|}}•/_>eË–ÍácðÖ­[ŠŒŒ45MjÚ´©Õæ<Òƒ“ƒV—.]lÎïÊ•+Z»v­þúë/EFF*oÞ¼zþùçUºti•-[Ö"d±5Ú˜½`è?ÿù�ÍÚ�ÉÉÉÚ¾}»Ž?®Ë—/ëÚµk Uxx¸é7âÑk‡˜˜uïÞÝìZ&­-Zdw”´+W®¤9X¶§|ùòZ¹r¥Ý×ôë×OóçÏwù²çÍ›g·fJTT”Å~ž%¾l<³¿¯¯J—.�îùdʔɡ$ßUo¢�æÏ‘9sf³'Ö.þ‚ƒƒÓ4ÿG#I.¹)O˹7nÜPÓ¦MÕ»wouéÒÅts�5kVõë×O}úôÑÙ³gõ÷ßëÎ�;*X° Š+fõbuùòå6l˜ÕvÉî°cÇ8pÀT øY6[¶l.ùŽ>üž+VÌærÒ¢D‰N7ã�ôŸðh ÖúS(\¸pš¿wyóæ5kŸZ ºdÉ�={Vÿú׿¬Þª~ýú©.;99Y‹/Ö�!CtûömÃg#GŽ4«�’’¢3fhåÊ•êÑ£‡"""L7× TÇŽÕ±cGÝ»wOW¯^Õµk×L¿ ¹sçVÞ¼y­žâââ4gÎMœ8ѡ߲ôÿ�¯Ã£ýK,X0Íóöòò²¨…�ZÿÛ·oWݺu5tèP«M8|||T£F ‡ªÖoذAýû÷OõwØÇÇ'ÍŸ1 Àì黵Z-Ù³gOóüsäÈa6O{ßÑääd :T‡Ò Aƒ¬ÖvÉ—/_ªÃ<ÇÇÇë‹/¾Ð‚ œ^ßýû÷«nݺ3`4Q &-7ùO‹›7o¦y›�9R•+WÖŠ+Ìz§÷ññÑsÏ=§jÕª©~ýú*W®œÙ oJJŠvíÚ¥ ¨{÷înÇ=åX}óÍ75lØ0§†ÃMIIѦM›T«V­4…]ºtI]»vU½zõô믿ÚéËšßÿ]:tPóæÍ]nHÒœ9slÖ¨>^ °ÚApJJІž¦þuñý÷ßÛlÞvþüy»M”�gMTx[MTÆ�Ÿ®¡äÊš5«ªU«¦Úµk«hѢʓ'�©iRtt´®]»¦ .hóæÍÚ¸q£Û:MM¾|ù´k×.ùûûkéÒ¥fm¨w*R¤ˆjÖ¬©Ê•+«@� Q®\¹”’’¢ØØXEFFêàÁƒúßÿþ§5kÖ˜5‰ñtS§N•���nß¾­Ï?ÿÜj³%[ .¬·ß~[•*URþüùMµÔ‚‚‚¯èèhEGGëêÕ«Ú½{·~ûí7;vÌå#-= òäÉ£5j¨Zµj*T¨�òäÉ£àà`y{{+..Nׯ_סC‡´ÿ~­Y³F—.]b£=¼x÷òRÙ²eU½zu½ñƦm—#GÝ¿_111:}ú´vìØ¡•+WêôéÓ._‡\¹r™ö_XX˜i|}}uûömݸqC‡Ö�´víZ—†�ó÷÷WÏž=Õ A…‡‡+22R›7oÖ—_~©¸¸8·î‹—^zIŸ}ö™Ê–-«L™2éøñã?~¼KšßØãçç§=z¨Q£F*Z´¨"##µuëV >ÜP!3@Àà™Ð¯_?õîÝÛbzŸ>}ÌúMqõ£$�º=z´Úµk'IªS§Ž:ÄÁ�'ÆÛÛÛé§¶Ï §‡z…1~‡ùŽ:·ÿ¼¼¼žø:<©ãçI-ûI~fÀÑ�c«#ºßÿÝmËô´‹ƒB… ©U«V’´Y&ÜÀ“F¸aáÆÓù;ÌwÔùý÷¤÷á“\þ“Z6ßÀ}pð8ÖŽèèh�•Á>ùäÓ“&Mâ RAÀÀãX 8~ûí·gæó‡‡‡«iÓ¦’¤hûöí@*h¢ÀãXzÓ¨#ˆøùù©D‰’¤S§N™�àbË AƒLÃ.Ž1‚p€ “?~µjÕJ ÔîÝ»µnÝ:ݺuËì5*]º´Ù´ãÇ�k÷î݆û¼µjÕÒøñã,éÿ ³·ÿ~›ï©ZµªÞ}÷]IÒ† ´sçNÀŒ¢ C¼òÊ+Z°`�²gÏnšväÈÕ­[׬ƒ¾W_}U+V¬0{o×®]µråJC}ÞÐÐPíØ±C™3g6›~ùòe½ñÆJLL´x�¿¿¿¶nݪ°°0%$$¨F�:sæ àúààv>>>úúë¯Í IzñÅÕ¡C³io¾ù¦Ùß+V¬0\¸!Iï¾û®E¸!=¨ÅR¼xq«ïéׯŸÂÂÂ$="–pp· ÓsÏ=gµ¬qãÆ¦gΜYï¿ÿ¾éïk×®iÀ€†üÌ… rêõÍ›7W÷îÝ%I;vìÐÌ™39p'pp»|ùòÙ,+W®œJ—.-oooõéÓG!!!’¤þùGíÛ·×Í›7 ù™ÿúë/›eW¯^ý?ÂÞÞêÝ»·&L˜ IºpႺvíªäädÀ t2 Àíì5µðññÑÿû_]ºtIÏ?ÿ¼$)11Q;vÔÁƒ û™÷îÝ«””yyyY”õèÑC{öìQ‰%aj–rýúuµoß^7nÜà œD'£2ĦM›TªT©T_wéÒ%õèÑC{÷î5üg:t¨ºtéâÐkÏœ9£6mÚØ­ùÀ6ICÙ ÜmïÞ½jܸ±­–'&&jÉ’%êÔ©“Ξ=ûT|æ;v(gΜz饗äím½Eà½{÷4mÚ4õìÙSQQQ(@Qƒ@† RçÎ�U¶lY*THwîÜÑßÿ­C‡iñâź~ýúSù¹K•*¥¦M›ªxñâ Sll¬.]º¤mÛ¶iýúõŠŽŽæàÒ‰€£¨Ã#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€0<`xÀð8€ápÃ#à†GÀ �€Àÿ׎�úÿº�Î`Op{‚ØÀžàö°'8€=Áì `OšÑIDATp{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{‚ØÀžàö°'8€=Áì `Op{Ø—Õpî®ÕIEND®B`‚TCMP0TPE2Anar Software LLCÿãÄ aüGHÜ—ðÞ@ÿóÿÿÿü©ÿ= ÅŸIÝÝ鸇>P1nˆAÀŇiŸúíÿ÷Oÿ¿ÿÿÿ×ÐöJ«õÿãÄËf �L)ÑQP€ÊŸ1*;š]�Í[ªõ¿ò&Œv^MkG[±eÿ_¶Ÿíïü­y$Bº:Äd}ëFŸ—† G‰)ÿãÄ* ƒf�Lòù)ì™Ëã>¨Ã¢Dsÿÿÿþyÿ™œ6e÷]‹¨iCA"Ô­a„ß÷—2ÿ¢ùOçË÷ÿÿÿÑqÿãÄ; »^GH4PÁÄ`‹z¥“ŒE•Ûýÿÿ÷ÿÿÿd~—JÒ’Ȫî¢E�º7ôúbc%sª ½ŸÏ¾YÎ_å?ÿãÄOÓf MLÿÿÿÿ)_ú_‘Ž`5%’=ä�ô€@2söÿ}6¯_þÿÿÿÿöѵEgC•#š…QK/é84âf‘ÿãÄf ^(�k q�ÏmÕ6íõëíÿÿÿÿü÷tqLÌ…;ÎÉÅÔÎr¥ l¦!YL¿É^J¿÷ÿîíý‘ï'ÿÿÿüÿãÄ€ûj MNîîäe½U%F=Š¥ùò˜QÏ!Ò"c§=¿Ÿ¾ýÿÿûö®¾S¥ÔZk36WìçIC zèfÊβÿãÄ— ³b �M¬ô–ÁÑ”�ŠõÛ÷û%5vOï§ÿÿÿîŽ�案QJÎ, B1Zm&ÒŽLØe4$�†Uõÿÿ¦ÿãÄ« kf$™hîü™ñ×ZVŽZÿÿë™™ÙÚo½µsîÃŒ²‘‹-û�¨ÿ4BB¨xKBÊb*¥$Ó¬ùè7¿�ŸÿÿãÄÀ +b �M_û5H²ÿÿ÷÷ò¯1ÍÒÊ:M³F,™Œ¦”m „¡¢2é,a­ÿ?ŸÙæZê|ùÿÿÿÿãÄÒ [n$Sdç§iyúOë9·vÎÑj–#o’©a|wI Œ±QéTh;nËŽÇÁð≈*¬œ,™…˜rdÈL!âD(PÿãÄã b “O˜|Ô„‰ÿüå§-µë[mo­k-QsßÓY¯­‰vºÓص ”úÕ¤”:ËLAME3.98.2UUUUUUUÿãÄñjY.UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.98.2UUUUUUUUUÿãÄô ÓjSHUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUÿãÄû jYHUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUÿãÄÿ;eìYIUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUÿãÄýHUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTAG1 Second of SilenceAnar Software LLCBlank Audioÿbeetbox-beets-00724b7/test/rsrc/unparseable.mpc0000664000175000017500000000435415253035401021013 0ustar pieterpieterMP+' \@”7–sÌÿþ ÿÒÅDfÑçüÿÿÜ3Ï?óÏ<óÏ>÷Ì>÷üóÿüsÏüóÏ?EDDþñð>@Èñ_éÒá @ Ñ @;8ºo´è€€Þ ‘ÿE¾|‘_Dä¤È—DDDDù""_ˆˆ|¾ˆˆ""ED""""‘""ˆÈà‹ˆˆP 8ºÑh ½Ñ�¶mÛ¶Óµ]×KÛ¶m^UÕ6ª^õ÷jå/ú{¯ª‹U¯¶m»ò—mkšg{¦KÛ[Ú,H’³mÑ¥çç&ŸÛliÛ¶³smÙ"Ò”(�ªº­lu~傽ÿÝgUÝÓ·õ—U÷U±o Úó5„4ÆiŒß@N¥jT=�’¦SÒ©NÿÿÐÿÿÿÿùD&¼|�/]à½|_þÿ8yèÿÿAWÿÿÿÿ˜üúÿDÀÿüCx/þ‹Ÿàÿ]ÿÿÿÿ@bòÿçyŠÄáï1øëý�Á!ôóé€?A_OØ�ÿÿ?ÿÿÿÿ>Àÿÿºÿÿÿÿýv½ä`oôôyCÀ�Wì€Ážpø öú‚@ŸÀ§ÿÿAWÿÿÿÿЗüûù‚½À /觇~¿žÏè úùv>ßô¿ÿÿÿðÿÿÿ®pñÿÿÿƒùÿÿÿð2."âåß?€/¿‹�ÿÿÿÿøÿÿAW¸uÿÿÿÿüÿÿø EDäÿD@àwðÿÿ@ÿÿÿÿçÿÿ?è ÿÿÿÿtù“ÿ ò¿€ñ "ƒˆ|ùàEी|ÿºÂÿÿÿÿÈ—ãÿ ˆ€�ÿ䀈ˆ|¾ˆnÿÐÿÿÿÿâ?,ÿ" |ù ‘ÿ;€ÀÜÀ€mSº(›ÿ þÿ9öŸ�çìÓgõŒµõ¼ž³|ΟßKŸ÷ñ‹ÀDDÄ"m›vù´kÛ¶Û¦mÛ´ÛvmÛ¶mÛmÛ¦]¶kÛ6Ðà 8ÀxÀРhÐh Ð£oÀ¸Àápи£poÀ"Àá" """""‘/""ˆˆHˆ€ˆˆˆˆˆDDä‹PDD€7€íРð@ènt£ކÀèÝ�p´Ý@ÃÑ׸mÛ¶k¦mÛuÛ.]Û¶]»nÛ®kÛéÚ6mÿÛvÿ¿ÿÿÿ¿ÿßÿ¿ÿÿßÿÿªq*ùN%+ªcEU5�Jª ’ªÂX=W£ýÐsÞ!§Ðçr ýW8yÿÿÿAüÿÿÿ?ˆô^þ�þø]/àä{€@ÿÿÿÿþÿÿÿÿÿÿÿ´àÿè]Ìÿÿÿ?ÿÿÿÝ tŸ£ 8€�î: 8p4tt ÿÿÿÊÿÿÿ0ôíƒ?ß 0ô?Á¯øçû…? ° ×ë ]Ÿÿÿÿòÿÿÿ}Ã__¯ô…»¼ï×èú|‚½q0þü‚¾+àSÿÿÿ þÿÿÿaзK}>@PÈóñ|{<0°Çãú‚Á_PÇ…“€ÿÿtÿÿÿÿò»üÉùÀ‡ß/_ä‹‹€üΠÿÐÿÿÿÿùò'ÿDäË�/âÁ Èù "cÿt…ÿÿÿÿ‘Íÿ€|/_à äË�/ _D{�ÿtÿÿÿÿ€öÎÿwhÀ@Ã�ÐO¸ÿƒ®€ÿÿÿÿ /ùÿ@¿ /8Øûýx¼�//,ùz@ß_±ô*|=.ÐÅLÿÿÿƒðÿÿÿàÞs€8€àáð ÞÀp à AWPËÿÿÿÿ°üÿÿóÔg¡ÁƒÜwðÀ|þîÛ§Ï{íõÐ_>âûoŸ?úÁëGŽÿÿÐÿÿÿÿñß@>Hþù|ù_ÿï¿àÿÿÿàÿÿÿÀÌd¶mÿ`€ÿÿŸÓg“çúñ…ÿ· xnÞ@ÿAÿGŒ]�ÎÀç Ìsž€~Ã�¯\RqÑ¥úÆü€s°yFüŒs°À$‡;üäs°ÀAã þ<9Ø?AÖí³©T…€Ý€Œ]nÞ@™ú¾òû‡;Ö0�ÎÆìÿ€9Fü1t€Ò0�ÎÀé¹O@þc­Ï@^vTFhR5•Oø LÉÜÉÿ('ü4¥»øR›KeußãÉÊ ÿU¿�ø|ˆæR´R�¨.²ØŠ„! DRJ…B¡R•)½É!ê‘×'&J(‚ZÄ ‰@¤,¨T3”¤�¸�™DV*ð×ù3’AĨŠS'l‘*SÀÕ�…["(+�‚9¨BPP%1"!A›þNw’#�)‰"I R™.P!ÁS"*”r �I²±(BSÀ ‡À $Çü�òêD«…)ºÀ JSÀ S]r#¿àr'·ü¶xäBSÀïøˆõþ þ ýr!C¿àÓcþÐT;“#À¦Oø ÌÒoø}û’Mÿá‘Ô&wðÒŠ?à'üxåv§ü¾ÿ‚‘pbeetbox-beets-00724b7/test/rsrc/min.mp30000664000175000017500000003102415253035401017207 0ustar pieterpieterID34COMengiTunPGAP0TENiTunes v7.6.2COMhengiTunNORM 80000000 00000000 00000000 00000000 00000224 00000000 00000008 00000000 000003AC 00000000COM‚engiTunSMPB 00000000 00000210 00000A2C 000000000000AC44 00000000 000021AC 00000000 00000000 00000000 00000000 00000000 00000000TT2minÿû`À F=íÉ‘A#ô‰¹ÿÿÿÿF0ÃßÿC ÿ_ùïÿÿÿÿóÏ£)çÚa”2ùŠz<‚žyõ=xù=O `ÐÊÇ�  ¥à�Æyé>`øÜá ÐÀXè" z)ãBœ"À$)‚ �A„ ÿÿÿÿÿøÿ×?ÿûÿÿÿÿþ¾Ývb£×B�¬¦ ³4Àã°²+¸µÂ¤Ír¹Á�ÔR°Ä%;�îR£Q[ÿÿÿïÖÜîÿ³¾Ú7UW6dTUT!ub8´Çø çèx?ñ.Ì€ˆˆˆˆ�ÿÚÚ¢³<ŒaeŸDY/ÿÿÿ½ÿPœ¼·$D¬(躡ïPŒi§ÿû`À€Š9à… éâH#4•¸‹RÒAbÉuÏ&Ž ü:=ÄÝL´2!Ô¶#9îŽÔ#"5¿ÿÿÿú­ÿfE$ìȉ,ª1HËez²1’ª!ĨR ˜‰Ì§)¢((â¢,Êc°š)ÄÜX¢¬,qE„T9N@øˆtÿÿÒþ÷ÿ?ÿû`À ò= mÁ¸È#t�¸¿ÿÿóËäܯðÉ÷IN¡æiÞÿ{ÞžYg§S—ÜëdE/'ÿÿÿÿÿÿÿçþ§Ì¸g Wëï&%ÍirÄDuñ6.ÝítÜ‘mtP&ê,Ž�«¢’Duhâb¨D›ÀN±ÿÿÿÿÿý`Zÿý{ÿÿÿÿÿçÌímÞó¥/Þj¾GH„<&ñÎC¥ÿü„žl÷ÿÿÿÿÿÿÿýþÿçJÎÉP��1•¥I’òÔä»ò9£3³ZHFÊ;ŽÔr/viƒÃ�1  Ü‰…£2‡ ìÁ�ÿÿÿÿÿÖõÿþyÿ?ÿÿùz\¨Û+dDΪ�1ˆÆckTIw˜ÿûbÀ æ% „MɬH#t‰¸™¨…¶R²¶Í´öÿÿÿÿdÝꓳÐ÷1êr© ÊϳîÒ»³lÖ• lΆmC‘Uê÷c,ì$(tÈ4BKÿÿÿÿÿëåý²ëZSÿÿÿÿü¹QRÅ­ÝŒ‡>³Ìl®®è§1Œ¨ˆËf:V¨m&¾åDGB;?ÿÿÿÿÿù­RÌé+ƒ9‡}•+ϳ+±ÍUÐèÊbPSú;1Œ%Ü; Š…R•Ìwt”€Î9Bÿÿÿÿþ¶ƒÿëÿ•ÿÿÿÿäìúRwó5�lª„s>ʸõ#ÌäºuFlëÐêɕћÿÿÿÚÿ³«ÔªFJȪyŒEus–ÿû`À" ? „­Á¬Æ#t•¹a2ft*3άVwVl̸â•êc�@@Ç‚o2ÇåQÇ;> ¢£€?ÿÿõ�sÿÿÿÿÿü»µ®å:=¨îïv:ºº•VB/Îlêèö-ÊZ$Û™5OÿÿÿþÍ'*MD£�'» È.–z¹›S«”ÌêW!„Ça溡Z!3#NǞ#!ƒ¢âcH5VA¸ò¨`†`±�óõùþ¿ÿÿÿÿ®•g;RWT�ÙUÕ½ÔÝQeÑÑTľÎB%OÿÿÿõùÑgêÕ9F F‘�T‡j9"Î(cJb#!Ç�xˆÕ3³ ªEÿû`À, Ú= „­É¯È#4‰¸vcœqL8áaàÊPq¢�Ñ2$48ÿÿÿÿþÖ¯uÿºÿÿÿÿÿ?£‘Ý”„5›Rl›ogGÐŒªöi7ºÕŽ·ìKwÿÿÿÿÿÚÒ"1Ý_™Ü§8¤T„Dg�ä;YƒœFä%PìÆ \ÈäRŠF €‚äS3: ÁÈQBªà•Ü(ÿÿÿÿþÍ�—ÿ/ü¡ßŸõÿÿÿo‘œíbnYØz(‰‘ëu×J:ä·Id£ïZÐÔÙÿÿÿÿÿþŸJ'»Jƒ Ff®ï©Ne+ È 8ä*&*†q2 0�Ì AŠAD…0’�Q!2ª”¥A§aQEÿû`À6€ ¶A „­Á¬E£t�¹0ÿÿÿý°/ó׿ü¿ÿÿÿÿò]s¹œÐô… 仪Dþ9FzÓ¦[7‘t¥+M¹2ä³ÿÿÿÿÿÿÿéÿ9æÓ*FE‘D‰»ë2³×r™9“Ò·I­|¼UèÊã±Áz°spÂ+† JÛØ8ÿÿÿÿþ��©ü¼ògRfÒÏåÿÿýþ•$íc1üý§º!Yz:d÷#ê×*º%Pú?{¯ÿÿÿÿÿèɦ·5\ÎR£¾ì‚ŠTv{˜Ä$A™ RkÑi†ˆ!£±ÅÊ�Ö(|¨rˆ˜pðé¢î<ÂÁÀ+)�h0À5�"ü¿ÿÿÿÿÿdîÿûbÀBVA „­ÁÄÇ£4•¹�F±:¼Û>yê­)Ý�ì¬åºQò²+7cfTÿÿÿëÙ[óÉW£•hr¿ÿÿÿÿ�iO‰�&�׊aÒ¶§ö’ѺkL“ÔW0÷?ÜpµpÝÿÿÿÿÿÿÿ1ÿ×ýúÚuz÷¤sò8ë›~9�çˆ^;Ž’˜…ìar:¦hZ—Ro|†AwÚÖìXòo®Ü**>@Ö0ÿÿÿÿÿëËWuûJ�FÑYìîåˆòYÙræ\ˆîjí»*"±Hßÿÿÿÿ~î‰m¨—g*:˜…+"ofi•ÞÂ#E� �¨²)JçWACê,$aqÊÇ)„€p1Œ"Pè‘ÅH‡(Ñ¡`8�ÿûbÀo€5 … ɽH"Ì•¸3èòÿ¯ÿÿÿÖ×Ýzè¼ì×»Èr/È¢ Ê®”d£3Ñ—yN¤qÿÿÿ÷ä{"Zåu#ÌeR ¸ñŽÄsî®e-ESi‘�pÕ( ›0“�„bŽ3‡Àãs�†�yNEr”ÓŠˆ¨€� ŒÀÿÿÿÿÿí�yïÿéßÿÿÿýz.¥1,o5ä+9·Ežuvf±Îõ¹v}ÈÈ–NÿÿÿÿDû}l³µ+3UTŠCo¼¥>%èOyS!�XŒ‡‘Æi;�\ê8#)Ń:‰cÅ•Êt(P‘À?ÿÿÿÒÿùÿóÿÿÿÿù´š÷fÿû`Àx 9 ­Ù¤G£t‰¹b$„vºftgdû©kU-™œèƤÆVäfÛÿÿÿÿìŸêR>Ó­ÕK5(i5; Îñ“•ÑŠwiÇ*¹ˆ¤"âŠ*.*1â¦c´x´çRH@“ˆ#•bÀÿÿÿö@¿ÿ-»<ŽÄjµ=]ÖÓTª¤®Æ96Kä<îäsn³¼ó—ÿÿÿýv"Ñõ{Ñ]LëgR�g©ªF5ŽFuõZÇQ3�QÓ ‡Ç°›”a‡¨Ô ˜µÌ.tP‰GQCå<ÊÿÿÿÿÖþ]ÿþ«¯ÿÿÿþÞˆy‘žr3ÚÛg§Ÿ¤m4U++!d“Ö¶_J´Í{ÿû`Àƒ nA „­ÁªG£4¹ÿÿÿÿÿÿÿÿöù7ÈqyiHsC0¤Er_?* –gÐNP�‰îF¸v#UCªˆ9ŽB!* jè�A‡1Y(0ÿÿÿÿý`_óòþ_ÿÿÿÿüßíÑžïzJ_¹K&´išôE3Šeu!&>ˆˆþFÿÿÿÿéÌý<ˆs±Q#•ÞcÚï39’Àœ“Ùœ[%ÜÑÝÄÇ8s¸Îd†; áXä …C0­ƒÿùZõº�Výi ­b¹*ªOf3U§,ÍD=®E%^ÝËÿÿÿÿóHêí³=Uή¯­]�™žØâ®ª9ÕŒfd#9ÿû`À� òA „mÁžÈ#t‰¸Ñ�Ô�¤C»Tˆpø…Å”HƒbÈ s‘� E,*Qÿÿÿÿÿý`9oËêkÿýýÿÿÿÎë"åE§KQîÖÝ�Jî·<†aG TGȪW›F}]iÿÿÿÿêÞªú#f«¢Ì¨ÅUTH̵Eç̪·;f¤€ÜâÀÙÑÕN]Dœr¬¨qNÈaÝ(ÿÿÿþ²ûçþ}~_]ÿÿëïôìÌÇûèw.šQÞrØÌÌäb-lzèÒÒšÿÿÿÿßé­ÝíSUÐæg«DL†îB�ÓœxÝ� ¶QE§™ˆc±îD €Ñ3‡PƒÃ¡ÿûbÀœ 2A €­Á²H#4‰¸$)Ÿ1Qd‚ £ýÿçÿÿÿÿýÖþ—tÍT!˜¦ÈwS5îêëfº�ÐÅ*”�lý؈ŠßÿÿÿÿôºµYÊÊKžÓÊÄB²¢�Ïvj±•QXÌB *”a”£¤q3”Á7 áº¡b±Îƒ!¬k **�6Hÿÿÿÿ¶ü¿¿Ëå_ÿòùß%é,«¿uÜöeæBÊìöJ¹Mwº®í­]Õr«7ÿÿÿû¢Ú®d+Tµ#!•ˆDeœ‡æ)Øì…F•®q`³�QËÊ·K ‡!:ÁÎÂÃ�ur‹C˜®àÿÿÿÿú@¾_âüÿû`À©€ ž; „­ÉÁG#4•¹¯ÿÿÿÿçïÿ%2ó¥xzžõËa©—ÝßÈͶMŸšÃ™);þe­Ûÿÿÿÿÿÿÿÿù~~KrS¬[uvzŸzYq¢ñ òlQ�wÑß#}¨\‰jZ |‹T �¸Ä!ÌéÀÀàÿÿÿÿÿ�Ÿž Øç —Ne9Ÿÿÿç eR!áçÖVê¢õœ}!wÂOí3UUÚZWU>ÑÿÜWÿÿÿÿÿÿÿÿ?íñó÷+kLÖÃùŽ*Øëk‘s*—gJ�4`ž¹EÆÇviF"‡$˜z©†9‚XõÂa�Ë”9pèP·XT]Çÿÿÿÿÿc`qîyÿû`À²€ .A „MÁ­G£t�¹‰#±’¿%¾§ÿþY¸tûîú㙬ꙉy¥˜†ýwŠõÚ©¦÷ÞÒ¥©S»éºæÿÿÿÿÿÿÿþÿ¿ÿû¿Ž¹šk¯«YO›­²<6<’±…&TÉ눢Æ!wB±E2ˆ ¸ö³J‡4\V…K1`°’ކ6Ëq1Š@ÿÿÿÿý±ƒÍ#˜Wå¿Ì«ÿÿÿý:*\Ȫuo™��H(έb+JB{1¨¦î·±•jjÿÿÿþ�7¥®·tT2+9#ÝÖ<–ºœÈ©*­ ayŒQ1§3•Ú&=¥B�:``ë‘‚¢§Š ‰Zpð[JQÿû`ÀÀŠA … ÂÈ"´¡¸ €k?ýþ½ÿÿÿÿÿþÕdR•¨É¿WDJ2oR›±ÎÓêUd©Šf3¦Óo5ŸÿÿÿÿòKk­Ê„y™bêìêt3–S’È5‹Ž «�,† 1 áòŽr�JâŠ0¢„#(@Xêè$,�âŠ�8Š4xD*…„ÿÿÿÿÿ’Ëäû×ÿÿÿÿûνey5v}úº*±K÷U2‘ÖgR™–tK"µoEÿÿÿÿÿéîíLÊŒE:2+Ù’}Hî8†fc ‹³)†ÅÌîìBˆaÇds¸“!…„XPr˜xñÊ,Š($0<*5 †4lüÿû`À³€²A „­ÁÛH"ô•¸Ö|ÿÿÿÿÿÿôM‘Û[VÛ²NI”¬ÚÖçbk3›ß¢ªÕ‘Z~¿ÿÿÿõ¡j‡»µ¶g*•Ø”ssB«¥r”¬QGª‰ ”„)å1˜0‚ädÆw<)]Ì($aE8pj‡ÐhÀ³˜À¢¦‰€ÿÿÿÿþ��ßüÿF—=ÆÚþ¿ÿùå®›±÷õÌk*"§f5§¢*YÕC^bºê§»LÜÕ²ÿÿÿÿÿëî‰wcª¦UÎ<Ê;0Ô=QÖ«žŽ¤�:³ó¿ÿÿÿÏé¹&q…+T©µ'ÙTU•ŒgeR á‡B32)—ýž·D|ïÿÿÿÿÓ]«Mɺ+YŒ[Ö¦0Ò)ÊbŽ¥Ž5EQ„ÄEa!˜\h˜AÂ!ذ ³BÃîg À(ñá‚ÂC &P 8|DV&Qÿÿÿÿÿû`À´€ÂA „­Á×Ç£4•¹ÿéä^¤–ú,‹ÿŸÿÿžÒ÷f»‘×d[Òº½ V¹Lës ws)P§z^¬t252]koÿÿÿï§£÷]»ÍÊS2•gsƙٞDkaœÔ9�Ç#˜Â"%F âƒDL*£¢ (B" ‡XÂŽAìb¼>ÿÿÿÿÿ±…åþY//ÿÿÿüæ©J$î”Y?RºÑôVT}ÞŠrQKjßZmu}vÿÿÿþ«ëzttz%¦TS•1ä#ÌÆ½�j=‘Òª”ªQ!0c ÓH,¢å £ÄÄÊ,¡Ñw‡È 8ç1Ðå†0¸ÐÛ ÃjÐöÿûbÀ¶€A ­ÑÙÈ"ô•¸}s—ÿþ¿ÿÿÄ@÷:XÈ®M*¨Cc¹§r”ü­#çDQz­ªý§µ)ÿÿÿÿýþ–ÑNbç›-LQl„0׳ )�Ük ;˜Â,5ܣŃ‹;"Š 8ЦA¨$ÁÑqÆ�\M…EAB@Áç( *ÿÿÿþ��ÿ-ã4Ñ—pþRÿÿÿ³¢îVlìU·K&öu+<Ï™‡tLììv3¡ŠÔ³I{×ÿÿÿÿúûû•YÑ ¥*«“êçªîR†Ð<Ž=ÇÔLU…aÅqáL (sˆ”ñ¨§D4P€È�‚Ä !˜€8ÿÿÿÿÿû`À·€’A „­ÁñÈ"´•¸ÿìŒ w"šçÏ’–«ÿÿþMÿÇýwóó¯÷Üu]fFÌÕH÷SR‰õô±×K¯×ÿÿÿÿÿÿÿÿÿÏw§qóßLò°»O¥O3r²1GÔ­mÍ»±å;=šSÊ8y£2lÏ#•0ÑÄÃHˆpò �¢¥�% « €ÿÿÿÿÿ²ŸÏ_åËzÿÿÿþþŠŒ÷Z2>ô±• ŒÌ]ªC\�È„VGGuyÕ(Êr¢J´ÿÿÿÿû[BUÝŸaj«ö£[‹Õ™HŠèãLRˆ˜«yŒ‡œ¬C%Üq]Qbì->A!Y�â†`£1\Xâ@`Ò y?ÿû`À·6A „­ÁâÈ"ô¡¸—#ÿÿÿÿÊ­ä&ʪË�ÕèêÊ}V¤1Ö³Fnn¹:û[¯ÿÿÿëmjÌës¡ÒÕF!ŠbŠê®Æ)˜†‹‚*‘LŒcˆ°�j¡¬*‰¢ï0p¥>$av!œXè4DHÁÁ5‡ÅĨU(p@1@ÿÿÿþ­ƒüŒÿ¥ÔËïëÿÿÿ7êˆìµR!Ÿ#£µŠè¨~ܦf5æfb1ÞŽÝS"ÛÿÿÿþßèÍiš£P®vJÖ®d1qèq”2ÚÈ0:Å+‘Tƒ6aÂbEl?2‡DD…‡‡\M"B £¢† ”Ácˆ4\6à ÿû`Àµ€.A „­ÁçÈ"´•¸´ý¹~öÿÿÿþT«Û"£—ÜÇž—ÑsÙÑhê®DÎmYd½îdSnÛÿÿÿÿéí¾­:ª3š§š•c%®5HQU<§!ÅEHcDH@8â(‡E`=‡(¹Ã§qR¸²:$&<(j¹‹ÆŠ¸  ˆhˆØ6­ƒóæ¿ÿÿÿÿ#í%)sMªØí1ærÚì·IUkwG‘rîGtTe÷Ñ—ÿÿÿÿÞÕêÛ++Jζ%ƱÞÈÄÌ<‹;‘XÇ8qˆ‚:‹ Aa6qe- @ÊAA¦`‘Dˆa"ÄÆĘ„@ð™”:?ÿÿÿÿý$ÿû`À·€A „­ÁïÈ"´•¸/þN_¬™ôëÿÿä ÷Gõ>¾J¥Ó:²�—G4¸±Q(„tC\î{+©•®gOÿÿÿÿ쮕½Ôˆ³!O<®ë!¨Žd,ŠæR1>‚%f0°¬@ê>qâ¡ô (¨˜åœ4ÖQ!0ø€ºX‚eQC€ÿÿÿÿÿÒäþgì?ÿÿÿÿÿ-‘œ¦ŽI"*ÌD£™•̧Y§In–jH~­’Vkg»T®Š¬‹ÿÿÿÿ•úÑÌŽäRËÕ®¬–K¦í[ÝF"Ψpá®ås ƒ”<îƒáC‡A r$ò 0ˆ×R‹ŽÌWˆ€ÿÿÿÿÛÿÿûbÀµ^A ­ÁéÇâô•¸½ÿÿß›ÿÿü¿->ùŞó/ß&@ºÒzšºË)¢Ô-^Ÿð¼Ž½Ïmûÿÿÿÿÿÿÿÿå‘ßæe ·îV›E‚˜6��Þõ$4C¹»¼­dPÀŽŠ$B¬ŽAÅ£E "£,†8SW©9 € €`5‘çÿËækúëÿÿòÿZšçTC£ú^5Ýõ‘œ¨bT©‘Üz-®–™=¤½ŸÿÿÿýiCž”èËB)©au”‚o,ÑÈ8‡c‡ ""@”AÐD¥*<:*‡ °x:@ùDEEH8:.Œ…Ї†ÿÿÿÿ¶ü¿ùëïÿÿÿÿ©ÿÿ–ŽÍ­îGH¢’°»NÞ±™ÄW%²zÕóØøDo“eÞÿÿÿÿÿÿÿþ_ü?)¹leyX†¿ç)ΜzR̈Ÿ"]Ë•L´'dxÈÐtS 3j±Û é àÿÿÿÿÿÀ~˜dsÿû`À½€>A … ÂH"´•¸æ½ ÿ#ÿÿÿ˲µÐÕc0‰&V‰ZâBÅrÌdpëFEyFˆm ¥*³¬Î¾ë×ÿÿÿÿÿ¿¿mYÊŠVÊÆ}LêÆ+>j=‚¨,å-*UcÅB²=� QSÎPèÑÎ"ÊY˜H  ÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿ¯ÿý~Æ(`JEª*!ÙÙÊbª”Vs ` �#³±Š©ÿ³”ÁB(ÿû`À³€ n? „mÁÑF¢ô•¹ÿûbÀ»€&@ÞMÀ[Àÿû`Àÿ€ÞÀbeetbox-beets-00724b7/test/rsrc/partial.flac0000664000175000017500000005260215253035401020273 0ustar pieterpieterfLaC"÷ Ä@ð¬D!îÄvoWeƒ×l°÷�� reference libFLAC 1.2.1 20070917 TITLE=partial TRACKNUMBER=2ARTIST=the artist DISCNUMBER=4ALBUM=the albumDISC=4 COMPILATION=0 �gÿøÉ•@µÇ!Ì¡'†hPæhRs%… $¡aäÌ̔Ô9C9)™<¡C™”ÌÌÓ%8Y”Ÿ)…% aœ(r’‡49CL9C%RY’Ì<ž… dÓ ”)™™œÎd¦M 礧2…&yùgÐÉågÊaá94�% L³9œ(Xp¤¤¡ÃB…3™e% B‡ ˜D™¡= ¡@³ ) !ý Ì’˜s(NN’…2P¤¡åe&faʤÐå3$C'3™ g$³ 3”%8RS%™"Bœ,’” IC„By— °ˆaNˆ”„Lä‘ ”Ê”¡”’yC“2i…9ÿÿ¤¡a))™B‡ f,0©@¦„¡IÉþ†Re ¡(XS� …†Ng:OCž†s¡C™C<3Ì4ÉL(hÌ9å”)“"))(Rp¦Jg3™™˜S39òÊ�I’‡?)“)9C3'(e äžPÊI,)(S L”)'&p¦r†œ¡Ìáae ”2P)2�HD%B†”†Je2yB„ˆP‘‡‡(~y@¤¡4)“L<™2“¦K(y(”2“‡3ýPç)3™™”)<ÊaC˜R�¡g)“)3æS0¥ 䟔ÉÒ2d@°å$晡C…†s,Î�C“™ XzBœ)™’�a@Ò�¦�ÌÊÊI伡I’‡%0æRe'ÊPÉB’PÌÃI”'&RP”2yNe2 ‘ 9ILÂ$2™)"% L¡Iš”þXRe&P¦pˆ(L¤þ†r…Pæ…$ò–,2’Pˆ”2’g JÉ43š¡CL)™Ìó”3' Ðå$C„ÉMRS%330%3 p¡I”2“†�IBr’�aÿùL’™2“ 3”É)'œ¡Ì§= ’˜x|)C9'èe$Δ dæsÒ$"I…9ô” 0§2̦g4) )(J¦g p¦fs)†œ¤¡…™¤ˆLÌ“ÂPçÐ)’„@ÐäBr� D…„¡á¡’�¤¤ô<'BP,(g(aaNÌŸ)ÊC930¤“ÃÌÌÌ)(RrPå0¦L¤ô9C””9œ¡Â!™HD fJ ç ÉB r“L‘$èg= 4Í ”9ÿ<¡É™™Ê<Ì™L%”’JL9ü¤ó9™C™L硜¡IB!(D9™ä§ L¤ÒS%2RRPСáI…†i4ÌÌÊ” fr’r„§9HD93ç@Í Ê3ÐÎPÌÉ™™™ÌÌÌ‘r™% 8d¡ÏBPÉÊLó9)C9”3’S32†JdˆL¡Ê¤¤¡Lá¡Ì")Ì,™Iè””90áÉL¦O”(g e&Rt3” D99I¡IL4)(y‡(g?@§ L™I”Ÿ)œ)Î�IB’‡))(r†PáC””9Ë sL2’O)%(O<æJJJJùÌÌ,™I$C!L9B„ʦMçB…‡(e$”¡2Â…8y”“çåŸÿ‘L¤™™%0ç”)'�IáNL)3å I™’r‡™ �œÊ)“L””ádÌ”š9�'IL”””9II)3?ýœ(g…2R†fLÿô2“!(D ™C32Jaœ™L,ÊJ˜rfH„ȇ“<)™…&hfPáC…8r!9ÊJrPˆJ”Éèffd¡Iå9¡B�§ÐfxÿøÉ’@µÇh!)œ“4)2™™œ¡I™™Âœœ¡ÌæfH�¡™L3”3ŸC”ÌÊå&s9Cœ¡IB“ÊÊàS‡2D2RRP¤Êý ðÊL¤Òz:†e Ì™çÿ¡Â$Í B…�Ð"LÄ2S„I„Iœå&|ÊLå&P¡Ìœç(fdša¦M™ÊL¤Ê”(JLÌ)(S'2PÓ g!d–JfP¦ffLå$§ fL¤ÏBP¤¤¦fK3Ì¡BP¦aIÌ”)2†hg4(hD L¡œô' S% r\3„@°Ïå&PäÊ"žILå p§8D9™ÊLÊœÎffaIB’…% NPžaL”)(y(S“)0²aIÂ’…' J ™ò…&P9@ær„§ fL¦¦M… LáÈ�N(RfP¤Ï(RP¤ÿ‘& Έd"rfs9B“™“òœô(Jr™(P� Ì” J¡œ D”)™”(s'3œˆ¤§‡3ЙL)3ÌʘYœÎPæRe2JJ’På æ™4Ô)8P¤ÎfJåž’™""ÎS’’�IIB˜p§33%8\9žff4e$ÊIC„I?(RaLÃɦÉÌÌ¡IžS…9È“4Ì)Éš Nr!(RyB’xJDPÊ99”9ùe‡=0ÊLå…%™3™ÌÊ™¡œ¡Â!(S&RæaJIáœ(S'0§' 3ÉL”)̧ dó‘ žPæg0‰2PÐÊL°³B�¡’PÉ”šg>i'Bee I…8RP¤È�Nd‘ œáNLæIL(Rg æS% ”�ˆ&JLˆIC¡BPˆJhPäÌÊB”“œ¤ÏŸÐå%%% ¤ÊJaÊB„ó–r$™He$ÉB!†™?"Éʘ~s”3™LçÐ))ú(I¡ Rg(g0‰3Í’ž†s¡È�BÌ4“œáœü¦ffL¤œ¡ÉLšOIô9CÃ2|ˆ%PÎ ”Ã)%2PˆJ ”(p¡C9333š…0ÎhsC� œå Ê,ü.)=!å ¦NRg” &rPÎIfg0Ó'aš…“3æRfe B!3™)˜Pá@²J8PÉ |ôÃ(PáN†PÎJB…&PáÎae%32’~dBag2’|¦s@‰0ù™’˜S33' ” ”&D'0²M ”(P§9Cœˆ¡Ìç3œ)")’!2!ÉÐ(RPô9èd¡Â!†g(Re'ü¦JB!HS)“)’�L”)8XDe0ó ™”)2“þS'”Ÿ)2“”ÉùB“2“úfs9™C93% ™ÉÐÂÃ)2†rP¡L”?)2… æ'ÊL¡Ìå'¡ÊsÊdò˜s†JIL”Ì)™2!†“3) RLò�aILšaIɲR‡&sœæH… LÌÌ”ÉLÌÌ¡œÌÐ)(D39%'¤"‘ œŸ”2S%% 礡I”ÉL”3’™™?(S0РRgŸ”Ì”2P¡)ü¡É”„@Œ€D…„ÊM0”Ã33&“¤¡Ê™'ÊJ”™ç)™’†Éœ(2e„Ê¡ÏÊNP¤Ê)’g%„ÊJœ¡2!“™’†�IÉÈ„ÊY&’t&S$³,¤é†…'% IC% ¦™”8“ÿøÉœ@ÿÿµÆP!9BR‡™“ÎPðå”$ò…'3% ”šdˆp§&†NfaI”ÃÌág2’eB„¡’†O”)™ÌСÊ”¡œ"9’…&i)Ï"(fg?C'ÌÌ™9œü°ˆ@¤ÌÌ¡œ™C8D2p¡Îfs9œÏ$Iœ°ù”…2†s rP<“9))"˜xL¤Ì¡Ì.I¡�‰˜RR†r„ô œôÌÊ’” JH|¤ùgÓ0¤¦e áLÊI4Ÿ”Îç–ÉL,"8r™)’™œ)3I¥ ¦Â!™…“3„@°å$ÊL"ÉB’ŸB„ÒI¡BR‡�‰™“Bae2S’…2O …(M ”š™aNfe…% r“)%$¦)(ú¤)(d”™ó"y2†…'¡’†L¡“˜\žRe'”(p¡fS „¡¤ÌèfP)™(hd¤äC‡¡ÊfRdBe ”ÉòÂ’‡)4(g0ˆd§)<Â!„I<3’…&yB“œÐ¤Ê“ÉèfPç%2R�ÌòÊáBÉ™”ŸÐÂÃý&…&t�0òtÉNL¡Ì¦r‡˜RS aä:Ï¡’… Ìœ3C9C9$C…3$C”„ˆ™Ìó dÍ'L<”)2™œå$¦IB�æfrD)ffg% !JCL9”3% LÄP¦NM0òP¡IœÉfL¡Ìç9C™™C9œÉÃäÌÌ”ÌÌ”) "™™’”š™¦˜g(sò’P¤,Ê™43ŸC'™Îg3™I”™L„LŸ)™:ž, ™I¥œ3C')’s$@¤¡I)(S%2XD$Cœ"B”9œ¡œœÏ9C 9ž~Y¡C˜S… Ð3�§$¹œ)“™™œÎPÎgå2J“)(r„¡C“2e%œ2™†…%™")œ¡ÌÌÉB’g fg2’rS2�áaœårD)3‘„B„ˆPÊ™C”„Cœ2““4ÉLÌÌæyÊÉOÐááC38R†rd¡’…'8D9ÌæS!°"dèr’…&2e%PÊB‡“™2 P¤ÂžS…9ÊNPСə)˜Rf’…&Rr!C”(Rri…2s2RP¡ÌÓRtšaä¡I(p RfP"9Ì‘ ”)(RO% 2D9™ÌÌÌÌ¡L™@ç)œË3”3“™á,(hRC (žJP”¡=ÉäÓ åS3œå æe2hPç (d¡’“"�r!3ÎRg(L¤ô̦B”“ÿ)(ICý’’‡…&|¡C“™ÊÂä/”™C“(s …|ÐÉü°¤äB| (Iò…&r†�)™9™™)?”ÌÎ}“‡3”<<’…!BÉ”3Ây™”9”ÎdI'”™d¡¤¥ Ê9BrPˆ„BO’ F,ý ”ÃÌ9’Ê“2rS3%%%% IB�¥�fP,:R†B%…�JI”3%‡3(g0³3™")’™:JfP"\¡IŸ2’fs9™‡(̙ʔ"IæD) ™>P¤(RrR�¥!BÂ’…$”(JPç¡IBÌÌÌ)9™™™™)(r“Òçô'ü¦aðô%Ô̔32P)3ÏŸ(y…2p¡Ãœ)I<9”9™™™)™Âœ(S3™™™)’˜S&D&D3„I”Ÿ)9I”ÈD˜ÄÇÿøÉ‰@µÆè!339œÊað§ dóÎfaÊ!�s LÐÉB‡ N“L<”)8g?Ò…ÎP¦L¦JP”¡4(JBa&P¦Lä@Í °¦fM çÿ¡Í L¤¡”38Pæ…&RS‡˜g=De É”„I”3…0¦NJJHD)9‡’Y@¤¡™å2P¡áäœÿ)(L¤”“å9ÒzM0å Ì,Ϥ(X&xD™”4 J)9’™’„@ááe'I”” JÉå2|¤¡(p¦NP¤Â!Â’’…P¤ÊM Jfd¤äC'30§!a”Ù”8D8D)(Dœ¡)™†R NÏ)>èr„¡’�L™@ÎL¡Éæs0¦aIB‡“ˆL¤¡™™‡’áB˜hD $ð¡I”Ïœ¡™)™’ P¤ÂŸË 9ÎRg33338S3'333$C'%'IÒP¤ðä@òdC338D4(Y3”% “2D(JJBP²…&fffp³ p¦e J“2Pä@å%(OPÌÌ“ÉJ™)’™Ê̤”™IÊd‘…3 fg3™ÌÊ¡œÌÉL””ÉLɦ“å2t °”ÈDÉ32S&’†„C™ò™9L(D% ™I9„C%'(rPÎe&S'¡BR�ˆs:œ)’Xe&r’e!¦JaL™IL–g9C„C'2S dä¦yùL<…2hfp‰3IÒt(d¥ èÉÌ”'C &RM% s)2™(”<¡Î¤Ÿ 4ÉLÌ¡š<ÉÐÊLˆL¤¤¦g dÊ™“IB“†p¦N‡"8e Ì™B‡3ÿèp‰(æJB�‰“™™’!Â!Iœ¡ÌùLÌå!9ærS%2S9’’†xs¤ô32|¦NPæRz9Êdé;&ɦ¤¡LÌÏ’’�ÌÊdèr†fL¤ÊfS3™ùNÌÌÌÌç¡ÎD’RhP”ò™:Ô93™Â™9™ÊNS$ГBe$¡H_üó9CÌæ’…&)“òœé(Re0§$ D”)ÌÊÉ”332S<ò…d¡É™4ŸèäŸ)“þ’…&RzJ¡C… ‘R…PÌÉ”™Ê(SPˆÉI„”))˜RP¤¥ ä”ÉLæRIILÂ…!O¡= ý&”'˜S$òS”™Ê™(S0¤Â‡ (s,¡Ê2fr’†fs¡Iš™Â!Îd¦M0òP¡ÌФ"!JIpÊNfs<¡aš,"Ê¡“æRe‡(Nd¦fJd§ 3™C%% B‡ =%RP¦g„¡äÌÉ”‘ æOš?ô(JÄ@°ÊM0ËHD  R š™ÏI‘ Ð)HR’˜Rf“C„I…)$¡ÏI¡N¤™I”” Na¡4(9B�ˆž¡43™žyC@¤Í äˆd§Ð¡Ìÿ)“ y'3”(s39™…2s L¡”™IB…!BÎYô2r‡3”3“3%9Ÿ””2zÎ�I’�ˆd¦ˆgÿB’S!IùL9œÌÊ̤”,>�`A“)%8r!)ô2„Ê|ùBÀˆrdˆd¥$å B– J™’™™æyÊ y‡(dÐÉBLæK32P¤ç)”%�èf‡)’™))(RLçÐÉBe&†y™œÌ˜e&)2’’†‡))(sÒzaòî’ÿøÉŽ@ÿÿµÆÈ!å” 0¥ B’�IBÊÐ" XAP¡2˜y…™L””33 Re BœÉL)’”)8PáLÌÌÎdˆað§2P¡’”% Có”3™Îd¤¤¡Í'I¤–P<ÃB†…32‡(PÎå&S3<9 0ærS%0¡IB™…… Ÿ”Ì” NdÐ)�ˆd"LΔ)3Cœ¤ f†r„¡IIBÉœáá‘ 43…2JL¦OC”š2S”ÌÊdæfg8Y’!™…2Pˆg„ÐÉB“‡‡%gþ~ÿ”ÈDÌ)Ì"pÞ Y…È\’Ê… Ð)(“ÃÉ40Јp¤¡IBœ…™™Ã”2�džáe ù¡&„…�òi(Rp¤¡aNH†fNaæg”9…(pˆ…™Ìæyù¡BxPæg2…!9Ìó$C%(‘’‡&p¡I™Êœ4¡”ÉÉ32P°ˆJs3%2i…2hs>RPÏ0¤ÊJžg(y2Â!<ôš2†p¥$B‡2fJfP¤ÌÌ”,)"&fsCB“Ì‘0øP²N„¡Iša)†Re3ÿ¡…˜Sž… Ðô”šd¡Ê’‡˜y(RIr8S39ÎRr…�ä̇É&PÉáË JfPç†�áLš¤"ÃB’œÏ™”&D˜D8e&’†…% H�)I”Ìæ‡ p¦g ‡PæfPÉÔ9IL”ÉIB“)’…&zB„¦OÍ!))(Y2„È„Êfr‡(L‰2’’ Rg ¤È„ó2“’M ”<�2P¡Ì–P,2‡ fPÎsÐÎPÎe™JË…8RP¡Ì¤ˆP§(faÌ,™C˜S… 3™™(s)…(JfRfK0§„„³%)‡Â™2†s<¡ÉÌæJ9”ÌÉL“†pˆR¤ü¦N‡"(r‡‡)˜Y0ˆdÒIfrS3<å&y™…&S32†g�NICŸÈ�¡BPÊaòg2†rPÏP)’”<”)”™LÜÍ…&fPç rap’Èr‡)(hP”å2PÉåLÌÌ"L‘ @‚œ¦L¤Ë J™(™(g&e ˜s%% ÊaðÍ ÏC”ž‡(S33'% J,8RP))ž†sB�f¦ÊL°¦OžP¤”)39CC”„B“9C„C™LžS8P‰ ç(g&PæRJa̤Í™”“™˜S2P°¤³330ˆdæO…8hR9C)&p°") PÎÌÎRe3�2S2“"…&g 3Êp§'(g0ˆLÊ… C$¡C…9C”2Pç)9œÌÌÌÌÊÊaÏ)™ÊHPáNdI„IC)2’’!ÉB’g�LÉœ3’œôÂ’…3' (J3CB‡&ffe$ðÊB……”<3… È�)èdˆ%% ”$ˆdˆR) d¦H�HYœÊaÎP¦aC33…8P°Ë f!Jdˆœ“Ã9ùC8D9ÎdˆL"d”Τ",,"ÎP¤ D™�IC’!BSœ¤¡=™“% ”ÌÎr“œ¤"Lç3ÌüÐÉCš™C””ÌÌÌÌÂÂ’!(S…9™Ìå ”’�IžP¤¥ ðΤ%0”) RSúÐááC”2“(S$¡H|3IB™’™"Í æD’|¤že'ý0øhD!0‰ s™™)(Re39”ÃL§�aBÂÊ’�á¡NÌÌæp¤ÊN™6‡CÿøÉ‡@µÆØ! (e&J2„"d¤¤¡L)�Ð,Ê)�ˆXRR~RNdˆNaÏþ‡9Éœ¤že$¡IÌ”) 2RD JæRO3” dÌè™Cœ²‡™)“IÐÉóç”) PÌÎL¤’˜Rs 0³ JI„C%9O&™)48YCÉB‡'’„HP²fH‡9Ió PÒO@³4(rO”œ¤Â&O P“LùI”(RPô&˜0¦g$¥J…)%2hd Rd¡I”$¤’!2 s‡˜y‡˜xffN†J†hNRP4åŸÓ…933&˜Re!äËɤô9C”9é†hd¡…’~S'9C8D%8DÙ32RRD NL¡”™¦J B$)ÊaN‡4ÉrD) ÉB†… Jœ(s4ÉfáNs̳)HP¡CB‡(sB‡'(På d§(Sd”áfP¤)HS3%3%%P¦frJd¤¡IB’…“9C)3ÿI)BJd¥0¥ ”Ìå ÌùLžPæÉÌÌÊaNLÉþ…&S39""ÎffPùB™™2 s4'BJaIš"(dÒzJœ”¤(fPæP°¡aB“=” ̡̜Ê% NRO2‡Â™™?@§ 9”9é(PСI”<šd¦r…“)(RS3”)3”32rS&’™,ÉCIÓ ¤™Ê¡I”æy”™IÿùC™œå¦K‡ÉIL”ÌÎPСä,¤ y™:)“)˜S&e$ùȆJ|¡aÿúaL“2z8s)&PáÌ¡œ)™’!’™)™™Be'"I432� FáL™Iç"Ì¡œ¡Êd§ $ˆR"LŸ)…ÈS3%™”8\¡IL¦™)…% 8Y(pˆRNIL%RbÏœÎd°¡¡ÿ”” Nd¡C“8e2P�!BÉœ)9CÉù)<2ÎS'ô(g&sÒtš¡áœèRp§'ÊÌç(ry…’S3Ÿ?(Y3”ÉJ“˜y’!žC% ‡<¦f™Ïþ’†„Bg%2Y’™†…%39’!“™)(dùLÌŸ”ÌÎPæ‡4)0ˆp Y� áB!3'3œá¤þ�N™™˜S<� ”ÉК¡äÐå%2„æJfp§ fd¦J@°¡NtÌÊL¤”ÈD™Â™œü¤Ì””)(S“(pˆsú¡”%3"òs(d¡LÉðÒ„ÐÉL”ÌÂ!HSÿþY”ÌÉBP,™ÏÐÍ0°ˆÉB™@³'33 dÈ�Êd¥!BÂ’!(D%&IˆdÊd§0°¡ÊJf™¡ÏB|ˆL¡3%… °¤Ë%9ÎR ÊÌ)™žS'Êp¥$çü¦fLˆLÐ,(pˆrfO 3œ¤Êa̤”É(Rs)8S“9†… OCž“"a”…48S2J"™4Ìå')“”2s3ÌÌ8S” (ÊfffLÊI”˜D8s%&…&S$Bd@¤¡IL”É)(S9š¥$å&RLÎPÎd‰0²ff|Êa™œ"™3(™Éé4<„He˜S2e%2S&’… LΓ¤¡LÂÂ……39IBP, s'ò™%!æa¡’�aLÌÂÂ!ÉÌ””Ìχ fg p¡IÌ)Éže&R~hD(L¡œ))“LÌ,Â!¡šy2k»ÿøÉ€@ÿþµÆh aœœÌÉB�¡HP¡Ê¡™™œôž…9IÏ æg332R†re ”¡É"Hy™ÊOèg?¡œò“(PÐ"LÎfaL™L2Àˆh&rÂ’„ÿþe!¤-”'"9L”ÃÌÌ)‡3¡™Â’„ÊfO”“ÉNäùó9œ§)™™…8S3%2tÃ)“Ì生)‡˜e&39C3%É9”3’Y‡)(hRP¦NaB�¡I(s)œ¡C”(|4ÉI¡)ÿèaf} 礗'IICšaò†hg™ð³3P”(y9™”’…&J˜Y„L2“9fSfe ”(J™ÏIèdèN†r™œ”ÉIB!'%™2†P¡ÉÂ…$¦M’�áBPçL”Ê…0¤¡O'BP"B„C% )�‰2…P¡¡C”�0"J”3ŸB‡3C9”¡<¡Cœ(y™Ê9<šaÏùæs3(g2‡9)Ü)™œé= @¤æe$æD2P¦IC˜hD% JJ2“ ™™(P”"% ”’™)™™Â!™™(RO&’… dòg9C% N9'Ês‘&i’™)’™)(XS0°¡L”"̦Oÿþ†eaL’‡%&He$¦ffJ%&r“ç(s9CÌÎPÎS$@ˆJ,’˜PàA B™’†Oʦdä@¤¡B“"BœÊL*"B™„C<…(S!|¤ÿèPÎLÌ¡œ”2S)“úç)ÔÂy„BP „¡B“ÉL‘„ˆPòS™™"3¡HPСäåš¡�‚™áLžI2„¡aI@°ô2’„Bg ÌÌ(Ráae á™HYBS0Ò„)“IC@) dô™fR�Ì”2R†fdð²�ä’!„²hP²äÌÎe2†Jr“Ê™)% B dáfe%™ÃЙI„C…(sÊœ"œ’äˆP”Â…‡3”9™œ”)2™)™’!Â$"&LÉùL“”’P)(PæffJf¤(D†R¤ž<ÃB†˜y…s„šd³8R„Ê“B‡2…�¨‘Ì”¤žP¤ÊO9À°¡Î†sC”„C… Ê44,,"2“¡I˜„ÊJfså3 J2S39ÂÉ”9œÎg(Rs”,Ï(rs„C’^SŸ”̡ aN!@°ç(O…)33™”8Pð� ç)0¤ä¡I”<”Ìßèr’’…&hRrS&†fg(hr„¡™C)�³$C2“ ̦”&†xe!Ì)’œ"LÿȆJPÎC”””(s4ž’‡"ˆa¦JfM0”2P)Â�IO”ÃOC”)9…3$¤™“32S&!“œ„I„C38Y”"(r’…“9ÎdˆL¤é‡’™"ÊC:B‡&dœÉá<“Ñ…”2PÉC'Ê™1 ”ÌÌ)(Rs332S’!“ÃÌ)2……8S%3(s?)™Í Na¤é4(ry)’Ì<ÉLÎsœ,™™™…&Ðæ…&S0¤¡CI…“9™Â“˜y(RR�ˆX B!(D%(r�Ê% L¡)Î&%Ì“ä‰À‰(R|¤¡0‰2e!Ð"BœÌÌÌšN†só8P§ p°ˆJH„¡aNÉ”æPáœÎPó'þ†p¦OÊJ(PáB“,Îe$üüå$¡IžP¡I…3™”8D32rS$C0êàÿøÉ­@µÆà!™”’S NaLÉ”””2P¤ú愞ffJffR¡“™)’” °“C9¦M% L¤¡Êô8D4(y:”3˜D9)(… dä¡IÌ”ç,"†PÃáèffd”™ÌæÌ̤Â!Â!ÉB“?¡œÊL¤œ¤(D�¤òyI@¤"%2ä,¡Ïò“4r††S <§2”‡C9IB˜s>‡‡&PÍIÓ �L™ÌÌÉC@ˆJaN¡œ<¦OÊI"%†NJJfd¦aœÊdô J„I2„Ð)ÙÌÌÌÌ¡IÌŸ?”Ì"ÉB„ÎI RPÐÏ 2D2S$C%2D&D'2†rs9…9?”ÌŸ)…8PÌÉžg9þ‡(frP‰ áLÌšL‚H�¥&S2„¡”(i’™œÊ™C™å L̤’&INJRBÊáÏC”)2“ÐÌ¡ÉBR�²’…'0§ s“?þe$.Oò™:%<°¤¡= ó@¡"gÊdùNt8D‡¤)Ê8r’�¥%% Ì)œ(S&SR B$2!“™”9‡3LÎd¦B$ÂÊfp¡¡B™)œ¡¡9“9žP§ 38P,¡LÌœÃL”ÌÎPæg(s™ÌÿÐÉC9B…% Jaʇ †™†RIL)“™…8S…3’DÉò™3”% JJáB$2„óúJfp§&r‡% B”’˜S‡å9Ó%$@ЈJPÎ L”šLˆp¡ÊJ™C2e39IB™)™’™4ÃÉLÊÊ2f} ”3(s4ž“èd¡’„ÊO)™™œý æ… �ˆO0òNg”)0ˆP”Ï„Lœ™™™™˜P¤Ï!32Ri(Rs% !Iœ3ž„ÐÉC””)2†Ra&RRD 2S'C 3B’‡"¡9@ˆs(p‚!N¤¡L„@°§”ɔÙ̡œœ¦g†rN�Iå0Í …'(På ó”%™")™œå&s„@°¤þ†Re&…!C”�$ˆd¡Êœ)™™œ¦eæH’aá‘&s™”9ùLœË æffJp¡I™¡œ‘ žP²e2S9@²…33�2På ¡BD9L))’™‡“B‡3B“):)<§†rs"„B™É)“B‡2˜S…9™™)˜RgC”)“œ"(D%&PåÌ™gÒP¤šœ"…&†J(p¤¡2$…Ã90¦(S I¦f!JND H�CœÊaædÐÉC”)“)=0¦Iæe$󔜈J”3(p RgúJÎaL™IBÂ…’R†fJœ)&dÊ9’‡3œ¡ær‡(g Ê™“L<”ÌÉL”‘ ”„BP‰'>�IB‡’|¡¤¡aÿС–IÊS!L�‘„ˆD2R†p¦aI”ÃɦI<”,(sȆJ}’…†Y2’JP2D)2™4)(S' ¡œ=Ì"Í3™Ì‘“™Â D…„Ê“"(d¡œé‡ÉФ2Â…&e Iá9(p‰ “„C˜Y@²e9Iˆdä¦J”3Ÿ9I@#0ÿ‘LÌÌÌÌœ¤ô 3èg(Rf“"aäæs”™C”P,94�fNRP)3(O3ÊÊÊ”2R†JaäÒ„¥% Òzd¦På™ÉL–fs9)™™BdBNz"= ¡Â!'(Pžt(XpˆJ@‚¿ÿøÉ ª@µÆ� g™Âœ(Y%„BP‰% LÊ“(r’…2J™””9C”9Ièg(RP¤áI@³?ä@æNg)'œ)’hd¤þ†g�M!) RPˆ¤äBe'L‘É4𙡙@¤¡Bz¡L9šaLœÌ¡’‡†…2†pé%33„BP°¡I™B’”)™4ž“¦¡C™¤¡aO9C… Nd§™™™”<>dæffJ‡ô3’™™ä¡LÉNaЙ9††M!šäHICɦH†Jd¦fg$B“:ò™“æRg)2“9By)CÉ)’YРD™™IÓ†x !NC…$C9œÏ= IèJ%(r‡(e&P¦Ng9I”ÉÎs–9™œ¡C3d¡Ìú2’…%’…… dæ™IIINáfK33339B’‡2XrÂ…2rd@¡¡Ã””ÉL”š4(S2s s3339’!œÏ(Re ”9ILÌÌ)3ü§:9� =ÉÊœŸ>e$ó)3”œ²„¡C38P°§å8XD $ÊNPС̤¡C9ž… É”Ÿò™?СÌú"s&På ÎáNÉ”) ’t3…”8D2R�fS%32D2S9Ê™I)’„ÊB!C)3’Pæe$¡IOB„æL¦r’!ÉC“9™˜y4Îg30¦L¤¡Î˜y… ”)œÎg3) hÌ4ÃÌ”"C"I”“)&g3”)(RP9™Îá¦H�Ìô3Ô42PœÊaÊ&JIÊœ,"ÌáC…C–çùʆ’fJÊaIœ¤ÊdŸ2’�IÉý ffa†LæH†p‡<ÊI"9B™œ"„Be å IB’…$C'(d¥B!·(sB‡“"(Pæò“9Ìó™ÌÎPæPäÎffM0òS$B“ÏIé= ™C’‡3”’„@å 8yIš33&@Éažç)3”™B“%2t3”9ò˜e%! D9Êg‡' J32†Jd¦Jpˆs')'BdC'2e&$Î)’™˜D8YùÊIò™I<”Ì”ÈD˜S2”ÂY„BP¡äô…9,"…2e ¦¡BS…%3(JfdˆP”"(g&†L¦Id¡f'B�ú%?èfP”“2†…g(g&d¤¡ÊÉäÙ…9œ¤ô dÌÊI¡†” RaCœ§=30ˆd¡LÂÂ’“L>JR¡áÊåB”�³3”)œÂ$Â!œ(fRe339…2e$@¤¤ÂÂ…'% J™¡™Â!HR‡:aNe Lü¡I…3 ¡š” :4 P™@æS8SœˆPæpòP¤ÊJœÉI2RP¤æfxÐЧ'(PÍ ó”8D’†�aI8P¤ÊJÿB~faÍ !BS”Ìå% ')ÀŒ’YÊp¡¦S0¤Ì¤Êfe áùLÎhS9™”&D…)…!Jdÿ)’‡‡@³))“L)ÉLÎt(rfJ%œÌΡ’…%% L¤¡I”ÉÉáNPáær“”9™˜RaáC9”Ì� áI”)†Xf“‘ œ¦fsÿÐòPˆ)¡Cœ(J|ù”8RD%(y<¦dç30ÒP²adšaL%Ã<ŸC'å%Â…†C%))™)"™ÎPæK˜D˜YC˜D8P§B@­ýÿøy CÔ@µÇ(©i*”´¥¥-*ZUd«(´¥-IKDÊJYeDÂÒÊRË*YJ”¨µ¢©KQT¢ÒÉ•)ZXš,µ%,©(¹)QjJZ”©IjRL¨šRÒªT²¥)K(­%rWJV*X©bÊ‹R–T¢ä¢å)R‹JVT¬´¥©J–RÒKQj‹R•µ*KRZÉU%©-EI‹E­*¬©U’T¤˜š-,©Jª\²Ub¥‹KJZ-eKZJÔ––¤©¤‰ªER‹‹I”–´L´ZÊR¥©–Tµ,–RRÔ’Ò•-*²Ò–•YJ‰”¥%“%JK%T©eIeJR¥%–”\´²©,´²Ô¥%©.-,¸²Ô•”´«J\YZ¤ÑeJª¬¥JªURÕ*,¤²•,´¨µ%I2’Ô¥)--IjR’Ô–YQKR#)-U•*©2•Ee¤Ée¥+RZ¨µIJ¢eJK*Y*²ÒU%eJªªª¬¨š,–+,©)J‹TZ¥)e%”¬¨šYRËRT¤´«,¬µ*&I‰”¨¥ÉZ¢eeKRU*É+)JZJ¢Ê–TªÑk*R´²µ)R¢å*ZX¨šQ5"êT²Ê”¤ÉdÑKJYQ4¥R©eJT²¤¥¥-RZÒU(¸­JRL¤©EKK*’­,©ieRZ’Ô¥)R•-%R•*Yqbhµ”´•IZ’Õ)R¥–”¥©)2’–)&II’ɢʕ&QYKR”©U•,¥J«)j*Yh²¥V•¨µ%IeDÊRR¥JªUTµ)QiUJ¬’Ô”¥¤“IjJL¤µ¥¥¥•+)Q2”¨˜ª¢É•Y*¥e)iEÉe¢©JR¥)J‰•**R–’ªUU–\¤©eIJQieÊRÒR”¢Ô\YrTL©JRÔT¥”¨˜´²²Ò¥(™(µ\Z”¥KR©+K-%K%”–”™iIeIIeJÊ¢•)j•V¢–”µJ-J²U”©UK.)T²¥UU”–T\²´µEÄÅ¥R•,ªJÒ¬¥J´«J´¬´±kE,¥%-)UK-*IU)U*LZYUKJ”©R•JT¥)&J–*TT«QK)--QrÊ–R’–R¥,¸¥ÉU,©JZJ©eÅ‹R¤\¢âbÑ2¢eE©E¥*²’Ê•ZYRÒ¬¥”¬«,²T”¥)R‹’Z”R¨¥RZZZ”©e))UeK*Š.J-JK&’”¥¬Z¢¥¥*T\L©KR‹”Z¢eEe%KJ––-QKIU+KTªË*RËK,©JZ’Z’«)*T¥JZKRVJLZQ4YyU¥VYIjRÑe©)j,´¥JR–’–”\”¥)IjKR”¥*R¥)JR”¤µ(µEdÉdÉT¢Õ%ZJ¢–’¥–”µ%©--Dµ%©e*Qr•”¬¥K)JŠ–”¥”––\&T’«*-IR”¥JU*Yh¥¨€q¦beetbox-beets-00724b7/test/rsrc/pure.wma0000664000175000017500000005620015253035401017467 0ustar pieterpieter0&²uŽfϦ٪bÎlB¡Ü«ŒG©ÏŽäÀ SehÄQ€>ÕÞ±��ÐtÐÊ› € € ôµ¿_.©ÏŽãÀ SebÒÓ«º©ÏŽæÀ Se4êËøÅ¯[wH„gªŒDúLÊ”#D˜”ÑI¡ANEpT3&²uŽfϦ٪bÎljthe titlethe artistthe comments@¤ÐÒãÒ—ð É^¨P‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104$WM/BeatsPerMinute6‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8ahe labelDESCRIPTIONthe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eTotalTracks3WM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8athe commentsDISCTOTAL5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a5COMPILATION1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8a1(MUSICBRAINZ_TRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aTRACKIDJ8b882575-08a5-4452-a7a7-cbb8a1531f9eWM/Genrethe genre(WM/EncodingSettingsLavf54.29.104‘Ü··©ÏŽæÀ Ser@žiøM[Ϩý€_\D+PÍÿ�aÏ‹²ª´â aD¬€>ç çç@Rц1У¤ ÉHödARц1У¤ ÉHöWindows Media Audio V8aWindows Media Audio V8a6&²uŽfϦ٪bÎl2K‚ ]“‹„ç ç“ÿ@ ÓÃÏ6Ó‚}mà ;€¦Jà$´æ“$�Ü$›ì ?'qU1Ù1%¦4©€` -I$ÀIP�c Ô I¨�R„UI10U5R’I‰¸IjR` Ù$Ę@«JTBTÓI¥1,E4” ¦”�Ò’ÒÒ€I:¢„bf¥1&C›°` �³QR@H@1Všˆ`šˆ †€H “:ÓP@¨þ¥�KÌI^o'�»@*@˜7C²@ •ÂL À$¨Ä %©--¦ši!T€H””¿HEPùj�H@&B4ŠJJÁóä"„0Ò•…ý Sƶ°|µALU2”’k?ßí/¨/ß¿¥,B(âýqôŠ1BÒÐ~¶¶š-ÜKlø¿!+t„H¢�„„å8� H¨‰¡h-Ûߥ)B Ûô-P_”PVéCäQný"—év0{eýIBÒÒ�ª¸�V‚i~·ÆüPè6òµA \@ÑÅA KT¿ÚÛëpã¥k‰¿, ñøRѤ ­¿vÙFPµB(âó^®oã§�Íù»yZÀUÁ”P„ã(À\KYFP…»}¿÷o¤ÓM–Ê?_¥ Rýmøâ·> ·× p?,£ŠÝúð´à*à}Æý–­ËKx)~üþ°óyKïÒoéãýÒ±~ìù¼§(ðƒïΚÆó\yïû§ó¬sXß•?´­-ÿµ´[–¨}BÞSJÒ8øÇ‰9ïùå>Á·÷úýqº_ͧ‹õE¾±øÿ'~ú—è·ÑÄ·ÙH¢š_%úiÝM.Ê]ŸÙK°´V²ž+sô~_§`;t㎟ߛü°c[ŸOšã[t-·A¥ ·?ü¿|T>¡ûúBÒÓêr•¥¡”­ñññ-¿ý¦ÞýÙ·[–Çý>ót~¿'A·Ð„%lÓE(?º0çÔñ­ºi )·Ûé¥òßîÞ·C÷ÉnÀ@­å4qºR#)O½k(ZvÏ¿:< ¿ÊhÀT"±Ÿ-­­y¼¥6úr‘Å@[Á*�XÈù­~뫈3Xöü§=ÿtþ¸¿\n�ÇÇ‚WÜi⦊Æ=©(Y�XùºÇ[[¨Œÿ)ýùº?+{ !öt½/¿Khó\võ³ÇO„Q•+yÊ-�ÀU�‚[ucåYò[Ð0òøqà?5€ÿtà”¥Ä\úÀN‚‡Á§`0þ¸2š2•¥†{Qàx6š>ÀT—ô%ù¤º[þðü_y»{ˆ7öáæí�·ñe)Ê_y â × ºØì¦šàâºÆ|NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç§ ç–ÿ@ˆð%,V,XU2¼�ƒ¢ d†´µ°DôZb`°D€« ’ZÒÄ’XªpÍR/¸I… &`c †²X¬ÀH1…$Œ)1´ÌJI,¡•2"MK¢ ˜A2¢B`’*!&©JADÕ€ë$Ši�–„¤‰ E&®‘(hØ+D¤„¥!¤Á$ˆ‰``:–h&FÄ꤈¸l¶¶ ¬Üô�F”a؈…E„–¹‚Cv[0¤á@™�˜˜00Š&¬“‡)EdìEB��MCQ 3P ¾4R EB( ±JKô¿BPPB0è@„„[‘M/Å¥‰ Û¨J€°¤¬Rü¡`ËTþêOT©QcM¼�°–¿-ZZ¥hÒý nÊ-ôñ:\kaúüÖÓùSÇÅæŸ~¿×OóÔ~Íp; yHZÊ ÿÌ¡q!ÒÆ¸8风ßùÓG®/É ¥¯Én‡ïÿkHóHÀ_µ¼ýõpºZ…§ÂÝ”ºSÄŸÏóãüߥm÷xÂiÊ_;t8ˆµn®§òO8‹êÆ}”ñ~¸Ðit²ÞSŸ¿[¬`ÿ`ª¸pD†¸„såBÞP_× P”Ö=Ž·BÕc'(ã�Õcy®'ÕÁ€ÿoè¡ÿp›cóåÁ^vkL£þ_“÷KWQÆ·‚WØ ­ÛŸ×ÁV}F §=ð_×ÞSBÕ4¾ð‚,¥(À~oóÁ*ÓúǬlù-ÜvǾq�NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“¹Œ„çÕ ç–ÿ@“¹Æ_­mšVÿ b†­°&6¢ H7#@&RI($L™&ú»’@(Ó£" h&gQ‡0c "`éì “†2QyJB%,Dš€&`–ŠÈ¦S„ 2Ì@0’i jH”Ã*J ƒ˜1 (‚i¤”  $¢©Ê ÂJa0BJI%�¥­$X €H–„ëD§ � X©³B «-#@Á!¨JoV ]G@Ðc¼«-TËNÉéªÁ³ ±¥†®˜ªI1Q‘¹BJ…� LÁ’…€À$˜„îši¦¥@“JÄ- .ËôŠQB@~„HDBÕ%4ST�(@JIJØ¡…¥�¡òX¿DS+eóä!/È~•ºBÊ”#ö´r¦„QNâ}Jj—ÁÛ¿·­ÛŸÒ‡Ï‘@vxŠ-£ö4>~mÅÛ-SÄùm%J-ëU_qþü)4&»)ZVô‡n´·H~·ùŽ?ÒVŠÚ?'ã(O©@}ú®È»gÏÒx�·ùÛ­ô¬V�húâ yíúâÍþ5¿É¡a€é·þNÚœ!mú+ŸÝ(óKÏ’HÊCëzVÈB?YHâCÿ4û�ôûЏO›¥mb�Ë•½Òïíß´Ž5¤¾OéÄ>SùÛÿ*P¶ÏÉõª°Ï|€©ókvî%¾/αè¡8Í­Sû§\täKùþ‹¥óÝëq|·B7K­WOçÅÄy¾#û}ùùº_£=Ê“üåÿ›Z¥o(·Óo¬zœCœ÷·þøøÖ¸ü#žÿ¾$ÛÖ–ðéóúÓOšÊy¼rŠÆ[Êx‡šûÊi·×QÇû§Í[¸ÿ!ûü¿^t¶{~ø––‡šÏl‚Kupeµù­QNP·ù¦ªÞ%ù¢ŸÎ¸ ¥€NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç ç–ÿ@üð-TÀ×ß½Gé=õ¶4C $š DΠ&I�:MOü`áÄ´€6 ‚FÈuaÌTAc áA@a@-2E@i0–,P I$¤ÔÀh“:I‰-/�B(, áá´¤¥cRL Љ(H©JMDÉi@š‚ÑIQ¬6  Š†KL’™‰‚PL„ÂJRH4Ë@YP 5€" $†ÀÄ iJH`$°fb`liÌC`)Û¼Àç¿�޶ënæ6€¬Ë ¤†5@Lµ hÃÉ$‚€Ä¦�Š¥`+:H„¬QE dÁŠQA¦…€E-|ù4ýúh B‡ô‹ú(BA@Ú){¡kÍW 8–ò‹cÜCeµ¿ÝEx o)Á1”»/¸«õ€©tÿŸ%câG€€¸¿óvÿ5æ¿o©KêÇ(Ê^NNNNNNNNNNNNNNNNNNNNNNNNNNNNç2 ç–ÿ@b—•aEDØ%�­iBLA2d 5Ôf¬vî‰ �”Õ Kd™ @ :„€&*’’!¤!bÔ"f@‘.%©¢¬‰¨�ÀZ JR a,’CP†! %3U RDI%×Q‚˜ªÂ$HA@“0™(XVPÁ 0�¦¬¦¬,Œ"€*‚°‰@0RK¨вІÔL†„TH‰U% ± (؈ ‚þLŠ¢ÃUkI ͬnTƒbe‚.ÔÈÂT�s!¦éDư€ ¶Z 1`‚ � Ja$¬°Ù k%Ôœ±~ý™5|¤¥m4;jΗéM)$iH ”>R"¢Â“Y ÒE @[¦€Ä)( %ý55–ÖÊ2ƒJ¨·Qý 4!(?·Ð‡ô¦ÞÑ&*>âvÜkOŸ,)BR’µBi ¡i`·JRùú©OÞèEDÒ(ðŠ?K||PýúpñXüD`>'ùN}oãý?Oäè+T-¤Ÿ ·&Þûˆe?¼¢ßúã‡ÅG¸ñRø¾â§óþ OpøUSoÊ-õ(+\h}O〟¿¬rrŽ7AFP¶ÿ">„e]¾[âü‘á,¦�É¥inœ§)â¤V7[Ÿ~¸éE[ø©âGQo|C¥ø�’VÇ¿a÷Q€¿iGëöâÿä]>U¾%·ëeoÀ@Të…o)[[|íèýå'Â%·>óVÇþÎ _`’¸JÛþ+{ˆ®ÁÏtñþíÔ„‹š@óx6’ÿòZ·¥mOïÍ­%kÂ.ŸŸà‘k‰ñZJ|׿+�öSoý­¾£÷æœDqö·æò‹c­Ç÷”å ßy²·ûÊ2šàÛæ©®ÿ’£Â+Vúàʸֲ•ºàÇú[/¿YO|šióTÑOèÓ”S””ñÕ„ç·éin•¿ÊÝ”qÛ‡ínÝáÒr�ùƒûÊi¡6ô�×ê±ß‡mlv{qññå/ß[ió\kYBÖù?4å±ÒµÄùiÿäùBp°IÇù?~µžÈÏn5 œ¥6êÆÊºü펥öQ€©/øŸÛèÀ^iÛÏê‡ùRZ`%ªÆÏ|‚[u¿‹=�|#žß»~Rÿ>J©ý[ò‡ø”-q×óUŒµoÏ5”¦ÝžÎ—·`•–Ê+œš”[–­Ïß¾¬u§mæÿ�ÜNŸ¨®ÚÕÄ;çáÓð}‚QoüÍ»ÍNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“s‹„ ç� ç–ÿ@Äò²AP{õ¶ƒges@� ²ZÕ5¶ÁÉJ ÆØÄ‚Æ„È'´„•Ÿ H5 �„&*N¿ä‚‚’¤T`b J †BRM ’„ÀD/HIª*%t. ˜"ЏA2iT"DH ª™€„’‘†[Q%• Hª-ˆRL€ @hD ¦pB6@À"óe KPI º,DÍB`D@… =ÞÜÛŒA˜UÕdʆb eÄ@D²HiÒBI’�)nä,$JD¡¦—ÉX€ @BL³�4‡È%“)&’”�KúJ%lÓÆH¥ô¡!mÙ‰vÜa4ÑI/‘ ûðø¥n¡¢ªVЊÁ}ÇHCõ¥´-¡ú8Ÿ…¤P‡Í¥õ’ú‚’·Æ„ÐŒŒQEÉK°?°ù ·Ük°úˆ ñ:´-­§�)X>Z[âÊKyO…­QÇKûzÛçÀR•¥�äµEÐ8Ÿ?h·ø“úÊ2—éâA·¾+t¸‚ÊVŸþOÿTÖ„mߢž;z×îØãXÕŠRþ¸E->E»¼±—Ïé·ˆ·¾·›}»ó£ÂÿB„PÿÍ;~%¿7\=¸©£ø_í÷íkò[›ësဩ #=©ÊÚÞ¬ÏÂûu4¾·e."Pr…»}4­­3Ùýpå’›wâ/ÿ+{ünýq-ç½)•¯Øü¿\|x%ü–Ö¼Óçå/«ƒ�;—ÇÍþÖ‹¥�µ”e9C§Þ­?°µnóuÔ۰?´~¸ëLå/¸œC`.7Ï�ýkôégÔWÞ{~­ùGäšáÀb±øÝ/\JÌí½ýpþíÔ­ñV˜[EOËÍ×Mpe6ï[ŸæŸçÉnʳÝk=ò•ªRâ"?_·ø ÍÇ{->tûñe`/7û¬{pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ç¾ ç•ÿ@˜O3  -ð9²ÄÉ×Xá«£Z�¶A�¡’Ö)ƒ:�Õ’T««À%A€�$ªd„!±LA’‰ŠÌD IJÐaIJÀ¤™lˆ¥)% BHLÕ ¢Q%0&ª%0‘I šHX¬RŠQ‡ I4¢RDÐCe IiŠP³‘&Š„S5�$„�˜–š‚²ŠP”‚* e! A;©Ù”š�‡DTMPIh"PfÓ2 ‘†XVy“¶@ �Íæ$À‘`4s�0W–X[$á†HbgD“ƒ½$UlÀ„*$€‰«R’¶DBQBhA4”?&Œ© „¦¬a¿/�šQAD´¤”š"„¡û°þ„-x\‚R*Ð샳IXR툤RA|š_ r‡Ä q¡jßJGJh‡Ô¿¦Š©(·daGHÈâmÄÕBBÕ/¤¬ƒ¶âM¹øZ}VÜ·ÅBhâÍ~IZ)§(ã¢ßM ¡òM [®Ï�­¾ ®Aºÿ’Ý8ö(Z£Š—Ä[ÿTëNƒ€“ûý¿óX Ýnü£óº?/ݹPiM?´Ð) vå®*ë¸B/ݽóühX§õG愾 Iü‚h·×Ïwþz/7ÅûðºÇ ­Û¿vàŸÉ÷…q[ß[ë‚ÞùÀÿ7ù„q¾(â£öù´Œü[¸ð ¿ 0Th·~GÍ%ÿZÊ-þi¬ù&‡ÿ§Þl>[Àoÿ<ý87¿ËÍ¢—öêV¼×€€Ø?ýøGõù"œZeÒø$¥ý¹ý¸Ö7íõpq>q ”g±ã·`•?¬öýWç”çÊú¸2—ÿ´Ð³8·€³Û=ßà7õ�o·ÓÅÅ€­èEcù¬§ò®æ±£�ͺ}¸ðqú ¶ü…¸ ¶êÇÃæŸV™q Xßž® ÷ZÀh‘'äø¸‰ƒjÚÅþ 2•¤á NNNNNNNNNNN çì ç–ÿ@õõ1à E.üÆÍÐwa(,± ­ÇB utL(fcDÁ`�. �‚%�ÉÚI¨€�-”¡ H$�„H’ØI’S&$…RàI,™)¦ZR¬6¢ÄŠ`BÔ”„‚)Am)HF¨(�C&˜MH u�(”ÌÊ�T$‚tH )A((Q5S'üÉ�†ÂAQ¥I”3q†`$QD a·S57$À³-Ð%¦ØÜFØ,ŽË&o­2¼hÌho`…„2I4Èa«’ÈI¥ a楇ŠS‘蔬IªìÕJj!4ˆŠ · $-¥ôBÚ Õ Jj¿ã(ŽFO•ŠPŠV…/¸‹çÉ·„„P_Ë'È¡ij‡îÇþ.$:)âG[H(Z·-:RÔÓÇBÁõ½l[ÐùnßA§ŠÝJÒx–ê%(+@|ÿ)+’]šhZKì%/¸¿e?ºZ vÿÈPµnãÊV+šÂÜé|¥—õŒh§ñ…º€[¸èX i¥õ‘-U¤~­þ$ñ~T¿~µû¯Õc?Ài¥öS”PþßCáNâýù¼2Ÿà­;`>ý¾ð‡R-Î"Û©tsïÐù&ܶÿ)Z[3”¿ÀX%ýq­å/©Mü£öÓùO„Vè9E4å/ßù¤g·›®ùRšá«ùÒÿ(¬l÷|°[.‚•·ÙFUÒùŠ)ÒÈÏj_×êÜ·ÇûÀhðµ«vPµæßWQùºío�ýuÃáX õ»ŒÓ‘.P¶éd~·-׸ù¯6•«vPét~uŽâ'è[“ÅÅù-¥múp.—KìöOêßM¼xA÷ì')E6òâ/š)Ê?#nãvË_«r?\N–}€­Ëx*Ê?UÂø× Ýpº^±Ý-H}XÞn´ÇæéI”çÉžç(¢„eÃæŸþ`NNNNNNNNNNNNNNNNNNNNNN çç–ÿ@ç%ø,H¿A~”’Åð!½�f%°Ö�Åíz ÀXd€ �ˆ$¸uÕ€PÈ- ’P ’� ™©1 ’J ¡!5!µ %‰L€I Œ3 ªDCú¥¨–ja†“¢ª‚œ$˜ `©…T’$–¤„ ´ ™0 ‰ˆ ‡Y(L ™aP2Á-;*j@ É–U2PvÖT@ˆØ€€È&bÉhh €I �Ø´Á*†ZÀº[- �²¡Ä•6I6��É]XD‚Š‚£¬ò�’YC¤¬…� S PxŠPP MRH¦TÚˆ•¤ˆ ¡hJĤPì¾ ¡l-?B—ô»)ÂÙ„�I¦Š�ÿoË ËúM (¡&š2…¤>-%+eb”ñ?ã§Šßú¢“JÃ(ÅÇ/ß­/Ú]—Ë|r)¡ FRý%`éz™Yž4')¢š-ç�"Šx¿Iâ¡úÇÅnÀAñZZAl>}C÷èn[ý-£ô‚´°?§á÷Rùÿ.7õ_å?’+Íe  ¿Ê8‚ßhóU�Äø>ÇGì>À_—ê±–gV’·GçûÀT£`'ß–SO·þÏðSæ²…¼öý?ýe9A£ò|!Çæê­äIn¬d»wëC‰§ôýòÞPµ@JŸåÿn!Ý,µ”-¾ãüÖg_ñÒ_  ”[Ñ\cÍq`*-öà2Šm�ÁR8ðKæ�š[ãüÿ'ùí€ßÖ3ˆ©óO¨~´|"·ù­Q”q¬g_~O‘àT¤V6 (BÞ{ y·?¦ØàJŒ¤[ÿ+{¥�_Ïß-V7êÜœ¥6ÿËŸ¡Æÿ>Jk�+Oÿ/ÎÝÄýó¥¼ÀÝÅ€Ý/ù× ½ilà,Æé~,øF‹xüë(§)§�)A£´þ––¼Ýce.—ZÁ"NNNNNNNNNNNNNNNNNNNNNNNNN‚ ]“-‹„ çIç–ÿ@˜_×I°Æ44¢{ˆ`ÙRAL—TĨ�É€RÆK@*L)H-`‚ Lfgb*T 1 DÄ)0™„IEC%0"0¶üeé@v%þv+"”�TÀ$Œ9J*T‰dDÌJBh%aˆuÉ5)(5!"ê l"©’Pƒ„[´ ¡%ÖM!¤Í I(©8A•Ih5jBN�  ™è‰Ñ æ[T4oa€ïLl�ÑÀ“ÛNκ0fÁ‰$�3¶‰)‘TÅ‚H¨v4B*0�DJ)(Ja"­C@�˜(`)!4‚iJA|²‡ôÃó oÀ‚Š˜tÔ,_ÑJè¡I|„RâùÛSCäÒ�A)|ù)¢”ºRíÿB_ÒJ·n[¥in(¥n—Öþ:V“”>|ú©6íSúL­»)EDÓù V–ø�±ð»z4?|µGå”Ón«s÷Ï©[GJ€RƒÇæÿ€þ±‘NR] _ªÆ·~ø€âJßêŽ4­>|‹u (·­#)¬oÍ÷çEo–ðV¶2Š*üÕ4º ý:RÐRø$~ŸÛ’þ¸ÿ^k‹‰÷q;ZvüKKOÿT¾[¡.�à|h·~Ñ~‰âqö„QX߯ßçn£¸‚âýþU�”q­,¿Í¡múÞSNSùQ”W (Ê?*Ç¡o=ߺ2Ÿ`‘nßNZã[Ïgë\HJßš}”V2ж_-Ûß­­"� ¢´Å¾›v �–¿+rÕÿF±íÃ=ò•§Þmý!5Àò‡ùC±ƒm¹Ä:?o¸“Ç€²—ôþNƒ‚JÇýþßÍÄU¯Í––ÿèüÂ×…-à;cÂÆ)â§õ�Gï)·Û³ÚªÛúmÁ4x +vúÓ—çæÿ.*”¾?¿åV=EJà|û‹ŽØïÉbšàý~¨ãt°NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçwç•ÿ@5øYà J•þ{l¯¿¢Í*ƒ'þX¾ 4ݵ2ˆ€ ƒ¦I €Öl�(‚ˆØCœ8 A’tMY$Rœ3(IK“N’ɨÂA: ƒ,LLAiÔ(&BAÃ2€Ð0PU( “LÕaI@$B+2„’š€ª %™(š*U$Å&I5R€�DЍ%Òì‘%!¨B�‰‚P!'¥R„Š£Ä % 8S!AAAfXPµF†F�PÒ"Û:Ëš¤9Ê�¡—¶&H*–b ¨iB@HBH ÂH@4”¬àUv@j0@@ %‰h„PýúI¥òÚ(¥Ø«I¤…´Š$Ë÷áÓDЍGªÝ?[&•¾7d»4%nÞŠ*Ò”¢� Ïí`…‹þ*_¤Ð¶8Òýihq­¡inÝú lZ¥ÿð´­->©ÅEº¢(é㦈HJxÖèâ[åªSJñ$£ˆú„q->·ÓOï÷o}æŸäKK÷ÿ™E/ŠÒmëOÿ>4SMøéJ×ìeHN¥ú]ÝF –Š?5µ«sëz_Ñoói âBº c­›}pùºP�Óñú¥Ð+Íe#)üŸŒ¢Ü´¶ü¾þ:ý McÛÖÐûŠ”[ÿiFRµGïõXùíOäŸ7žé Æ—áÿš[ã ãZBmâÝû·»o5žä?ñ'õùþo¿OòŠp?•6ñlzkR‘æÏ們Y[Â\DüËêà¬t&±Ÿñeå¿Ë¾ûÍçµ.–AÊk÷›t³ü"þÞÿôx°é÷›ýù¼÷/‘Åùà.?×å€ÿ\IÊ-î—[¢Üÿ�àðŽPúšÆ}Io>L¦ƒžô×Êû®H×ÉÁ/šÀUÃ\5�ù`<£xBŒ”~ÿvÇ‚éoÎÝ€­Ø%t¹ÀN!ÿ_µ¯ËÂÎ{eíÇZak=‹ìHNç¦ç–ÿ@bð#ÕØòsg¡uÍ"HÚ›]²ËÃ&;b&#`�™�¦‰,n€h$Õ«±I"%2C̘ Âpà5;� ¤™I&jÁhh@I-5¥0¥ „HJ" ©‡EM”ÊHÈKeÕ)(4Õ‰TH"”dVDˆK ¤B@NA¦fU€�d¤‚RN’dP–¥«B`È„¤ÄˆI %’Ì&\’K"Ú°7 T¨lžî…XK™¸HøcR%Q¡…›É1 !&bZLƒ@YÀ¤“2ÒHJ*! ™šP±Á¤¤¢“ XÒPL>J""¡ „�±4ÐE¤Rš( „>4Õ4¦‚�ùlñÐ’°©Ä”Rú i Kô? ‘ BÓõº2˜KñRšh[âÐJVç(¾¸Ÿ~ÎPP„~Ëêˆ}o¥ÙâD”¿(£ŠÜìRšÎx�±|ì%Ðic\ XŠGR·FD¥ð[êÇvÔÛËô[ÊRì-ñþ’þßBQGíij_~O�…º)Ïk}?°ù9M5QÇo¡Ø~‡é¬z´¶´ýñÅGä< mÏзÅot¤óÑñQáúMâv¼(Ûßþ¿IZZHÊ0(}‚»~®Ñ æ©Ê,Xëv÷ëyJGéiþ�•ª?<hÊ_å6ì÷âãÀyFãü’kƒk~$;/¸°çù`ÙúÏ{w¹Û~UŽÿõ\[\Ö5¹þ -ô,Ê Â| _—Ζý-§(Zü–�ÿŽÝ‘- ¸Ÿ~b¯?;u¸øEóðú‹aÂÒÖS€¿KKK3–÷HÚ;}pøCò[¢±¸ß罺ܵ斖ø°·>£òýà4>¬t?Æ¿*x°KûOïõ”:~ÏwÞoµÂ·ƒe¥¥«çKþÏ…­ø+_ÀãZ®ÈNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNçÔç–ÿ@ïð*|¨ßW¯!¢e‚Bª( �+ÚlIƒ¶D5"ÎÀ2AVT˜ÑH10dACDÁKpŠhê[$NÑ Ú€I*ÔBI"Ä ¥¨‚F©ª  DÌ  [ (¡a ¡PH/é‚$È2PA�‰I(A‚@! „§¬[Q`L‚° @¨·PDU �ÁI Ñ”…I $A2CZLÈ2‘ I€2bR©Z4n¾Îúu†††BªÙ`›•l)"[«£¸Â@’&!bL8`¥¦PH1NØR”Ø:ŠKö @¥ Th%úLÕE, JP]‡eZ|è¡­¾vô"�àq>?› TZãvôš8¨4~°î‡ô Š/ÖŸ¢ŸÛ·|“\/ÊÚÛê Ó÷ëX*(JÚ”ñ!úKo�‰ BÝÆíé4¥úÕ?¥¸À\Aò\?¯È Ò”[‘A·Ûß­åOR+… T¡â§÷”бý~T[¿_§ütùºEGô­Bmÿ¤¾}n·~x �[|ž$V5ºŠ–¼#ÅžÏݶ -Ö÷ÖêQ\ À´·æ­éZZ¢ßKþ5¿ÊßnÊ¿'ÕŽì­e)[üÐþŸÕ¹ØoŠÝGæ|ÞPµ\Û¨Ê?дýnÝžéýqдµùà”Qá×¼>üòšàÀ^j�Ï"9jÜúž:áÊ~–“”ù£žØ ?—åùå6ÿÚÝ¿­$'ôŠÇ·­[¿h¥k=ÿ4W„<Óˆ«T£Ž‡ï³äâ[¢Ÿ×ë=ë¸Uݹõ¿ÍÖ1ý8‡Áµ$Zq _¾® zاͭҊkÞýÐV’ýn±«„Q”yº_× ÏpûÍþ°Là'Òú…¿~te/ÝŠàÁ¶¸2€NNNNNNNNNNNNNNN‚ ]“ç‹„çç–ÿ@tÇ€€ +WÕ7÷ Žø;!¥„@è˜$I¬Ó*ÆÎÚ–€Â�„bálˆ.dD”P"ˆKa$Š¡!¤È0Xˆ„È�€X„� I" RQ)&DÓ J ‚V “`RÑÂ(EIL��ÒVx1TÔAL A& €°BeˆØÙbDP³„¬@T¤¦$ÀÙd´B!"¢V0:5Du¸"J$CH’@f¡�›$LôÖImELG`ã™,h,fö¼I!®»€„f‚„j2‚� B Ã’�P@ªtŒ*•Z)4&Zù&¬P�V)JjP‡ácBÚ’ ”>&‡È ¢ªÔ—d-¡ù¤Ð•ŠêŠ)ã~VñÛÓÆ¥ùã¥ð BP?r‡ô5JØã~„SQlˆ|�•µªVðTÿ#;4-”¨@ '‹ŒCê´¥õ!ÛÒù&šhã„~T}~ÓoÁRÆš8Ò‹zݸ¦€_,S”[Ÿ~Ö²š8¸íÖ쥨£Í¿K÷öÿÍÐ(·à'ïÿ+æëò)óO©Zt·›4­%#öù AÐVoy¥¤þgŽßXÉâ6즜ö§"T5ùù´qÛðKJ­?·‡ß¿Ì¿[üÂ+�$£~k_�)ýqe ¢Ørú‹tà/Û¥Åð¹oo‹õ¿ÏòtýnÁXÕÞþh×p>ótþht»ü£œ^n¢0šB+¸�?øFœ¡(¥òßš¥.–�áà8¸xèMc­y·ÉOš@NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNç1ç–ÿ@ð*ÿ—ÚÞÅѳò.ÔcÕ� Ãgm ʳ53($”²2A!²0Á«!—6–ȆÀEI  Ë SwT$,D¤T€KÔŠ¤0 ¶€)‚”¡´@!² hM@‰¨Ó„ Âp’u Š’ "“%5@�HHË‚BP†msI€Ù )HAЈÃu²RÂ@:%�AJ˜p H%¦"MÚd¶a¬ÙDÉ`$À�¹a[¡F64\á­¹�cPeI$’Ð�ˆ-iI „¥(¨„:BA€±BBP/Â#dЄÒþh ÑCåˆJh¥»*,@|ˆ—A)ãM)BÔ"”ºM.ÉYë\KA# ñ4%ÙÊúV�CO…—ÆÞ•ˆ[E+ð( [–ß"ÞµE¹Ðq[Ðû(¤Û²”ºš xÜ•¤Ð_Úi}ûZÏ|?ñ%«zÚ?hM¯Ý N–~ýiõcÛÊÞ{RýjÝùû¦š“n®?ñ?5Œ+±�mØ cæé·-¿À®$Ò¿t`‘ù.�HZÊV¨ý¾ý-!."e%kB ïË�/òŸÕ£Â+nƒ‚JÇâ¨)}nªú˜·qñ‡ët% £�ò„‚;n7ÔåÉ Æ•«pM å°(C°ì¡4�&…º <`R·\CJméK· Ò‡ø+·%ù·?|¶EKv “ÅÅRßù�ìŸÕ OÊÙ@Ê)"šr…¯7Jh|µM¾„۸lj¸ãñ-P•¥¥´¾·å!ý!h`*àý¤ŠršàGî…¾%®1úÊ2‘û|—ÞjŒƒh}oZ⦗Ͽvëy}æ�x°꜠g·P•µ‡¿òóYFXþIYœG€€xÒ¶¶·G÷ÙM¿�ÿä ?iÊ0æK§þ$[©q”¦‡k�úM±Ã�/ø¨·à>5™Ûr-ÕŽ�ßä‹zݾ‡ôñ—åm (ÀX6 Ö7cà0þØ÷Ëo–©ó_¯Î—Kñ­¿Ê2œ¢ß€�,·‚ZõÆŠà·çµ([F{-ƒì¥Ø­1E¿=¸‹ˆ¸$tµ»ùòmôÿ>é{zE9­ŸÓÿ­çºÛ¥’þ¸ršátÿ\"Üxß¾üÝ,@â}lu¾Ý”qþéFQ‚L§šá[ZHNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN‚]‚ /‚ç¼ç–ÿ@ ®q~&<ñròX$é|N¶t 2æîò³²Y ÁÂ- ºfC«¶ˆIE@A &L$�"©  &`j”Š‚ªJ ()J&¤CHJ*˜�%W 2P’d B¬Ua P(!%"ªID%!ÔA0SQ2LH!-~Ij¤ƒDT‚$ƒ0t€€Â „à±*‚�,H�ÐÁ!Öš¡°Êº©-“ÈÙBvƒ2u²DÁ ­ªÐÐ –ÁÖ¤‰�jf*F¾ êR€ ™|ÊJHK* š„$Ê[Q(X„€™Z(€)% 4Š©AL Òü‘8TÓV~•‰¡@I \O€)…·š•M)JSJh¥|I¡l%ÿ²�K÷Å)ÓÇE%nÍ©%õ%&ß–)+UiK²’x’±·ÓKÿÚßõ®4¦ÞOé+o�„­H¥+gˆññCïÒü¿Ó”¥öSÄ´ý4ÓÆE4AZKôå?—Qo·%+iâ6ôÛÖÔ·å$ÒCÿ7€íëa>mk�òã[¤ÅÇú¦Šxß`.?Úk…m+x (}”->Êù­þ_¡ú|�‘*×¾œV=+’Þ¼è/²•¥¯Ù¥_¿Ï‰ÐV²•ºá[·'tÑ”?·à<§ÍþN–t¶Qù[üÕ¸¾ý!jP)G›@æíÜ·ÖúÆÊ|_’Û¥ÿ_µªhŽ*¿·e¼ß6ãæ–ü#ÇÆþÞ—ÜyM;86-SùþKtSCô¡ú_ÛŸ8†Á-›¥“oæ­Î”µÀü¦¸?Võ¾>3Oç€�›ýºYOº—Ô¿|’Œ«Š_¬kƒùçüž r„xAv_·H¤-,iª  R…¡ —Á/ÍeO¡úÀ¦š ô…ªiKòM4Û�(ª´ÑA AâKñB-ï¥ñ|$#ö¶€V¨©üÊŠj?hãýÓJRVݲÑK²ì% k@P´¶û÷ò´ŠR—A+i·­ÑžÉ¥qŸÐÊ)ÀVü÷}…” å(~•·ô~c‹=íÈ¢œ‘Xè'ŠšÆýŠ_>¬jÓ+O°ñžé 8 Š�ÿ(§Íe/Êò” QCäÒµZf‡öûwÛî,û)}û£‹õúEõ¯5\4£ŠØî/ óyGçBOço·~Yïžÿ¯ÖÊ<ÞS”þ_“ˆ¼u�XöÿÕc'‰."šÆº0ÖÊKˆ¦¸-é/³ä§=¿YJ8‘Xÿª+†ßXÔ8†¢±ø’ùmÄ7NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNbeetbox-beets-00724b7/test/rsrc/oldape.ape0000664000175000017500000003320315253035401017737 0ustar pieterpieterMAC P4Ü3Ù0' 0éoÅ|ÍþqôèîˆD¬D¬P('¸è+6¹D€»…›gz¿ãÿnè±`Èé¯CÔC-]áXUÚ½ÛΈý–̹€ËRôa‹% –ýÒñ0ó©'lOéØ[&ï(ïïHõ)œ"i%6aMJO1FÅ@…D8Ùqlpù¤ŒE ]“¹$ê åýwëvy0äÏ\þv7®Œ±I˜®Æ ̇m7¥.uMÒÉè$Åý #­×x|‰SŸúgb;<·|:}|{H?k¬ò"ÁÓ{�äìæwß áÝéÝ¡"v˜útŽ`OM".ÿÄ+.Ë÷"q=f“; åF&8e*’<û´íH4ŠÈiçÞ-w»´7rý:¤Û˜œJ� \ó!¶Ü$W'8[4“ì«„ËAvìMXFÊUÄÍ�HU®qta!;{;ªë¹ ÊÁ­àG^ôad¶Gê™gŒ¾P¥­)«Œ·È úîØ™ÜzИšSŽøg_êˆQ¤Ü=ÏS ªù¶¸âèM¿‡næ”– ­u%ã÷ú¢ÓÁ8½ Ì úx«=j]m6“aú@�“I›L]ö~çên0.*§ãÏæcžânQjŠ0‚ôêí‰6j®ñ1ÚC%g§�4ß\-GhÙ3Ý•[èàH"’—ó@ù>¯3°+©ÙÎÿäÜG½ù§W3r˜ÚKn>œÒÚ+{ç²òô·Š¬´ &…ñ6u¿_zêmeS)K+2òkò± éØ8ôÝ‘c¼3L®ÝÚí�Žªv²WܸÚßèÑ‘�¶Yຓ@§1"kâr}õqIÆþu ¸ ¡©[#ØÈôð¦‘w“f•—C?s·”b Œ[XAÅÊ Ã=‰‹\ ú„yäü�vJe¹•ÙׂfÁ$0²¤y£ž}:ŽÎ Ø­ô[èr‰zØ>Q†Áx �„“(® ~ 9Å5QþK�¸ÓÓÈÓ&)±¶‘9jÜa¥«`¾ê‹A8¤Ì×– ”©¿ƒÕ"“à†;bR3¸ “D©�W væÇ)ãϳS›Î£Ž�ÚÊ̲A}ÏÐꂇTÖ‹¾DcXHwüWE>Èà‘'•:Ð�•ÈœÄqqoie4>#�÷ -&}ì#}F�í5pÅã�±ã³*"•(taà¡ÂàÅ“"Ñ)®BÜ -·,AEexj¥ŸòÚ†›ûu®R�H×n_¶n¶(ö¶Îâg'v9HÃ^%Ü!?¾"XÎ@µÛÚ6×›R÷…­‰¯ÌÎyÔÆá=ÀÏ‚ö¯–8/Ö3VõMæÂ»8¿±ÿu!ð™rP@ÄÔ¯ ›“øqSzá~åjwñ¤xTèv¨TÚ.'ÿî†>ÐäÒš?Î`XºùÊT÷:™—ýÌ Aã?”1²\@ðd±Fâ|ɶÆD½‹°6õ Xõœ“4„,ˆðÁMÝR¿#÷°Œ¥&ìeõ¾­E„›ŸväÊýS²š+vWÈãsJÿËžýxñ¢Ìœã{ö[·>¦pQ… tÿ³òŽ)®Ì ¤Ç`ãmnX±^xõÚ-Ç®“©=®æ�´|�t¢Àr…βþ‰¹!ɰvÈ ^T¿ ßN‘k1½9¥#œÞiÔ[@ÝöSÉ‘’è&ÀÏvš¶¦_Ö.¯oþUœ�æ÷ÙÕt÷xLÚ½êø‰H/ ‚Ïm…Òfè¿ÃÉ‹.y Æ8Ô÷KüQE¶p:•7'§Nn¾„ì 8lh˯îo=›}¯¾•9P}Ví{sÔèÿŽ�ïnsÀXiVÓ”íEI€íH=ÒƒõsºK—Î{ÍÁ»ØÒcyO€g›¡P˜û‘–õ‰¿ÉÅþµ\3yy8#;çtº2‡ÿê[mš ©í‡ÿ‰y0˜ÚäQv{DŸ×®ú3@ä ã­h½lXÂqKž!®!õÐÖ¹ú§çÚ‡ŸîÀø–�%5Pú]×|¹õ´††#i2‰öíÍý Eäùì›êLÿî­ 7X¥¢)E»[Ýá[Z$ѾƺÅ–½¿îKšW¤¥ÒÜíešY#ñÙ,‰í�Þ„ì.eÀÒ<Š[èÍ؆,�I#ŒôÒ·5´BÚ ¢6Ìå)¥ÙùMP™12]ž Bäã'‘i"’-,¹XQ3Á™€Ø_@øå©ÆY5ÎŒDd�m P Uëe*zï =ý…,òc‡-¿gCó½6a‘¢1ucô°,a$õÖ×zܤ æV‚òÀRå “”$}ôÇÅ~ï¸9EZç1°H.1.–j¸¢î¿Ÿ{—N]aL·.7 ¦¯€DQ‰l¨°Ùñ‘±89Ågg˜­vDm˜ê^żäžïðDUV‰.’‹ „OX“EV½ñúůſ>qáz¯™Q}(¯#¸MoNªþ‚,–-ç~bûc–97þƒÛ W_ýÚ 'sžNYO j]feÈu´Ê6ó݃3¬¥Nâ‘+1g¸`äjÄ;Vn6ý²pf_OBdkàžpìuÕqž\HM…k�ûÇbµY2}¶PÏe'¼ÒqCG¡[J�ì7‰P~Oëê ’k¬™‘Õ3“/—A ]%†°h@ ozWÇlýÒ0—u¹rî[ÿ˜KŸ}–ún²gþÌ@)E¢ …/ï׿•A ãì�š¦›ŸÝéFz ‹ìӓ͸B‰@[Ë %Û×á!Ê~nÂ8o¦®H#7±=ªðG Ÿö¿qÍÐóв`Kaÿ„íHÃPXÙóú{ Œ¯Þz“ð|\+Èç|+Nn{W´*ã›Òý2†usá1\$«J÷‰µ®E3Õÿ°Û (ÓÁò‰¥Ql µÓâû¦ˆ\õ€V 6°ì¶†RÐ-]ú–SÑM¬´«}.ÒZ+í)BÏw{”û]ò�×¼BôŽ £[Ú~š–’‹©–uÖêk‹§*ë[“Réù½¼ÈƒKñ^ÿWñ.ý�yx^èS¥`¹ÇXñ T�9 Á‰}­ ,f%cò¶z¤Cdð°‰/oûXfÍÁgî/òŽæÖLb ãz¹IÑ9z,çik߸m2ÃHßè:ÚÈ™U3±6ê›ÐÔVà-­!S)­Tµþòt —Ãߊq‚üãÎ4zM’î=03mcí(f4E×Ù9¨˜Ji�#çØ$Ö€²‡.¼¶½î—f¹OÛša—¿ÇFaöæoËFV¹68qc•ò:u[P¯_«eÒžfàëf›ÛÖ»�$;R¾íŸÄ=§Œ‘!M�Æ—íS±(ÙbéLI�çoWÙ>òŸ“î铳ÒÓ¶—S{Iî=C.…ŠÛÍ'ÃÎ?^“Hut†q§¹›Yn—¦´ˆ®1o2²�òz.½ :L�?ÑÁmt‘¦×x) Lìå\èíöó¬�©K•a¿´¬p\!)ó §÷¯P#û…?#™ðÆÎêX58æ»ù޵¸*l¦&#àp(müL‡3–B±AóéV$®ò÷\Ö^›G�4–Øï”y³Þ°"Q’©s¬¯aò—R%VªwPRõ±ûo�ÆuÒÍ‘?ºËèðÔø| ÑjÅÆ ˆßFZ© Uíçíw¦³ÊåÝLeòt—Þ¡£±ß\®]�nfÈ yø*e6úŒ.ü¦”P��èZ Öâ‚ º!ýi…ï«{ï¤Ý†S¶hÚëêØgeyäÎy&úñ —Ê6#ˆýF(;`;S÷íþX·à‡«¶~Nþ>^„Æjß½#䬭VÏ%Þ†„Ød8tLí¥ƒÚF:änœ_ îõÈxrr«åô± „àŽV¡ÿ—;œ!ÑÆüHÙ¥©½IÄA�º_\d™êÞYšštˆI˾§ãzÒ!¦%,¼"{–( –ƒÆiðÅůÓïI«»ö�e²¢mnøq¥ŒÉ…w³ËX!qõüm­~"œ.Ã5Ì08¡8’ëA&›k÷y»pÌÝg¸þä¡!O úÆ5Ò/#Fv²Ñ¾»AßaI$¶öùIM$éV]ÆŽÎtõº˜ ¹ˆ\€�^ö*­B§X/e�`{Æh ÎLóê¥5ÎV4híE@òEÁhŒ�2²H1C|ggÍʳÏß® :O­ —B¿ ¸9’Œ0²ïXwTl}Š$4¨é�]¸ô‘“l“ÎôFÝÞ¬½0ÆeSbŽ+¿’í‰<ÑL¸J‘õ^‹!h�òï¡SiûA �fa‚B$?é×ZAt¸# – =š ü¿ÎGú—çTûÔûõU¾‘‘+FèX §L7ÿ»-áãx»µ¿˜Nƒ`¯Á�„6$cöÓ ÁÂBÚõ:—þN’mkCØ=ŽãF/}8âÖã^ÚDðAs¹´®#x_™•C«KT]˜ÖƲÔ¾½møa×á}üo† Vú´âä‚€ +Z*³N÷·G�°.™ IÊ›êáS \†Ä?ΤRý}-Jzã¡ÖbÍ­wêµØµ„ �…È�™_’ä7¥Æó¥sRáÁÅtÍ­n—’ëT;×ñŒl CŽS÷Q’ë¥Õ>T¡ã‹#A陡¯:^¯hõQ”ŠåÚÆÐÌU fB\ÿœm˜\ÕMrYó^ù`—A‡ô–œEëQˆïZ‹’�ÿ̪™¾Ð8#”Ú:V:ÞgJo’C‚ß0~×}”ætž4$¥ºóÔò°Ái“@b8epÚµÁµíÆE+˜b÷y–ßb´è³ò„«.ÓÐî˜v0ù›™H9û('�%™ÎqÓÁ‰‡N«)†{œ‰b²§?›,-nþ x½k Î?UT…áʰ4vl”¥P{%ªÝ‹vÄuݦBnðC¿jI÷4CLJ§�ì³Xk?fC¯åjpõß¿h×q”«ì�50RHU*‡ÒØÌ-m‹:Á|ã5´;Q•›µß&¼ùì¶PérçÕnŽŒ�L‘Uçò×5ƒ÷©yéšI,OY¡*„áùŽ“)XLÐN5 8ð‡L¨Vá6«³W 9Q R#+ކ K¢ìýäXÜg.náá2Šá»í2KÒØ—ïTõÂÞËÇÝ„¥F0XC‡,S_ç-ÏÔ,ÞÇñäÄÜà–¸‚ ö3"¤m²wr•‰kBÇR‰žÎrêK¦Éå.yú°V:±Ü;â *� 0èk½—V¼!¾“ŽBçýê ÔŠ¬±ˆì¿´Šú祽ò´D…¶ïbhtÄ·+ǵ!dƯ¢t'UNa¤…‘øÃÈÆ³RV»3J†™¢ñqôòï(Öô�<xm%cw†8Òž gVlz/˜ZÀφ“é{ꇕõGï@îv�•“pذU×ML-wmÕ<õ[ü ‰ŽêiAå8\0"k87Êž??—…� Zî"¶B'ì�ry/ Œ¬G’ñ)Ê•Hœj¾d/¦EÞLÑÆÿ4×8éG©Vä^LÁÊr1ÿ›¤äP =£¿g�Œ˜(F݇VÅÙY´ü4Åd•SÐL×ZÄÈÿ@,Ú†qñ­Û÷sUwOéB©Ø�‹ðáiñŽ$B¿ü(Ü»/ÞœSÀÑùdñëŽ3{Y¨¸¶ÛAò¥ ÙS'¦êçX*=eB3;näŒ1 îr§ír™‚ÊGÛ¶šãÍ®TóÄÍ <¼Ìžá—‰šy³sWûCáÜ=ªÝÃIjÐyg!=°Š¤�m¯\2£ö}bD!bë¯}ÂWœš�¢åÐÓÝ=XØj´:×…*hýøA81 #$ÄcØWfš'çF]iJo·âY…ÿ�d çmdÃß B~!=9- •ÔµþÞ yMMfª¿l�p‹ÙÞuÁßá°æ•¹6¹•]«Ùøk²¨6´%{둞: µ·Å³ë₍ï�û`眺!T̺p=�ygxæ(q–˜®ÈZn¼@Š�E¾ûö½aœe¯c6ho†Uè�Å[óuø"Ðï¤}†aÌä�“ÐÉ>:óˆŽ)ß»^]Q¬˜#õy«‰Câ«9åÜÅÎÞÑÅ…ÿG¹DZjœ³í&⥎Aà=ä²½um©q>©jJF¨’!ÙÍÀZ »{Ê^Š©óf!— o:Kç\tÚJ8™X@ —úÎj Ü4«º;07:MóÑ!©çñ3Vï‚€dܱ MÝppËTýµ]÷?l��órˆÔÔV/b „Ö†68¨º.'“[±$ƒ<בiﮂ¶æŽˆ¿4 Í®§ðú€1Ü�ñ.†úôÂ~pç”d>?ØÕ¾æw‰8­±P¹Lçbð\8Q·Ì²mï�f\ ƒe+‰õ½Í® ù?Êìªd)dœ“ÉóŽ�¥µ„�…®W™®´ÑIr$YB8v�@Ø 06�Šf%¸.ý·�Ê+1_Ê£€Ìî^Ѥà <•ºîp[GépÏŒwÌ ‚ìÙ´EâÔq6ÛªƒñË´×›ý�_ƒ-/¼‰kç qNúãKŽñLDu÷ïá’ c_DM!ÌâçwsV·¨¹ -ðUÓ÷ãØŸA¯�Š´¼q®g@Ukwíìp~SE9½tݲduÍ�tÿ}*Á&ïYe�zÂîÛSÙñEóÝâ=|çÁ Ʀ ;ïÐ<_�oâLÜ�òÔ|’'Y÷ûÈá=‡2¶y¢nï²Ì}VœúRìtOæ¼ þ•A0gÎ:KÉ{‡ìµÂ]è­I‰}/àÀjóÒ�ah•_t ®I$5‘uÌ&.µÒq¤2ÍÎ^¿w…dMMOè1-)zàuñÃX<Û]ÖIâ ŽÈ" Ý,ˆ/g® €ã|õ¯˜>éŸu¦¶ËÀ9ÃVÿ�ûžÉÒ/ò5k€ì-!“[Äø&þñŒ FÖ Ö{ëñq±ØõwhŽ¥ æéyõ3²]—æäéˆÛÛP\5NDùìÙžožcAÈSéâVm>[þâ}kE:Ž"üºÍTÆ ?WŸ î'aï3QíjŠuØxgÇúnrj–èMQyµäçŸÏ�høV´W†–&ÞÿÛEÙ)ó–È«<ªýLÓmÿѵJEöíÄDâ|ødæCj¹žßA§+äˆ׉Ôwˆ,Ý rcÆýMÜ­«M“Ïפ�kFKg˜ÓÇ ü¡ÇZcxé ìÊ)lQYŽ*Ru¹tO’2¢¼^½òµW@ýäÞ‚½ƒÄÐ`þÜÂT�¯šÜ† fCpK:©Þl)Ü9Øc––Mž¸¦ß®&)n,•ì‹Nñ%ù»ß4�ç{Ä?3�Ð^@>èÈJ„.òE|ƒ 0¡×\�ì§=e÷7üØsÉZ$ 5Þ«w? \."<$Ó)´�ßpäRwèƒÌß6Î;nì\+@°ÃiÍõ”ë–Rxã7Öî.V€~傦Bmk4ñ@áé‚%?-f$1¿²ÍFbñçšã•²ßPïeCS r:ýJ(üqÀf‹µ9âç˜äˆ¶L iáØÕÁNS(†î)»%w–yûyðS(Ô$("­�¤-­£H2Á‹²f>šËÙVïà$xbƒ‹žsÆhÃ%uÎIíòm+'ðNÝç�d럈?¿põË—8}ÖÖÊàpÝb�è�î§‘™ßè¬�à̈ŠPÄ«¯(KL.Íg ¼kH¼a+Œxé‚3ü1˜›+éOéçÌ…ar±7& ëÁvõdVóùOÉËê6!ï3ÞB4ÿø,F|sÄ·¡ž¦ë¿õw@*B`Ð_]æq>ù/ �èÃñ�½ø�×Ô"êÎÇNiK&”…=.ÿh¾À-JÓìæÎ;RvÓõ¨„À;YD¯ŸðÂpâšôT>JmÑØ„§3a¿ÕS ¬J+`Õ=*ãŒ1o05ÖY¼ò1¨k¯2eîÉÒÚÃ:ÅŽò5IrÝ �å¬WÚ1Ë1(£ X=~É`ä5ø;B,ƒd—´5ŠB KZOù>üS.�TÝ Š é%*¸ŒźþíoOú4yJ˜Ô8"B‘¶`G YSôâ#Ÿ‰ U¨I• 1ú÷nùäîy)~Nj7��÷•ZÜg¹\|¢¢EÐ «ÿ«0‚ŽínSîÅ�À¼“UúP Rf=²ÎÒòUE¹!¿_’šïÛ?~ åŽ+æΰÔ[£!W;þ#�„µ‘ú%‚tqšeŠ*ÚÅö»˜ÊŽLð û‹òY9WTd Ê+¿vsÓ~Vò!@œº’š�Ý ;éWÉïl�ÑÚUéf€æ6€ÒG¾�´y ²ü–¥%rŽŠLb@çå-���,ßÚy Á¥Ý MxR ä¼�o^‹ÉüdçN¬Ÿôf¤ÏóÄåmà% Û1÷[òKÇ;‹.žúBºÅ,ý�¢á:þ£þ^§ÁÌ&µ> ê/!†3|Ö«SÞ—yTßF?øË0E22¢>¤jQu?ìžx€©’ûî~$[Ó«™8ô¯ù{Üw!?I‰’a ×)!ö@à°½È@¶ jTz\žù+þU¼•øÐêêÆüß¼–T½Œ‘£ºBŒ+.ú€Ý%Û'±Zú oMO™œ8b(ºÔßg.ÙØE·�ácGZÒËêŸB—æ¾Wx‚»5õÔ0¤'œç##9]!@&˜Ìó�Ý¢FýL†FŠÐ*ß•Âa¤6˜ï`­£ 1\j¶Œ©ûܦ#ÂôÊÁ«ÌÀ5~µZ œ¬;s–í¹ØŸ¯o9­5 :!Ï$½—¡`môŽJºÒ¨ÑC+œþH;q !LO‚ñ�ªá’b�5­O~ 6D„o§õÉòÑkCZå¹@ȶD›©t†xÅø Ûõ˜¿4‡ï¬Ž<œŒU§9ë—žægù²Ÿ•ë–zÛ"rU¯ BœŒ‡,¿|¼?;Éùñî¾²ñ0sê�@aŠ€Ë³�éYòó:‰’@5¦1ñq±0ÆYDãc:âPoBê.Õ­²WZ²ÍDL÷·ÞÜ ÅìZ­°ezž> \_¼7tm–îÓë9&¢DütÉð—Ü•hI >kæ…F€‡þÒLöÑqWPBX`á#¦´«ÚæAßùþƒ#ÎÓXn³$u1�Y ÀuÃ|þE)èx†H¿õ.®-¿\t¿<7¶dÆ®(ìTü¾%ž(Í‚%Çê–¨«¸™Ç¨-’7ï±=ªaß’Ö±ü@†?À‘ÈT¡}ý‰öó·p ÷§àp(¶�RW‚»\ŸT@² �ž½îâ²;)BhôR9ïþ÷ïß®�ã«´ßì?}_™‰l¿ &°Y–ˆèê½odŠ‘ô*ƒïðÊ¿d�D«´âí€�Ì ³ûª]›õëha >ôyTMp´2‹¸e q¬±�8/ߟjÈ ÚǫɿÀÏ k³ Y® ¾ m’èº].Ê}ûß`æ4Ê�1Sy˜;€à,ɯt r!Mƒõ1Á�:°/i)¸X£ŽŸçÌa‘Xö–ø 4ðˆRš(Œ”ŽÕÕxºäIfQ3så/ŒÀ†Ñöž5ÒÕÃ',ö÷,½Ç²ªu[rwÝþ ÖÏn i á‰Tç†Ó9�XÏs§³Šè \·Ø =ºœôî˜1 "¸coäÅ/ê¡ã……¶“ ƒéžk?'-ÍHWªk …ukÈ1 0f›-Ý�Д˜¬5²gñéãªøÖc˜» q�;ˆZÀî5\ÂÓY5*÷[àØx–Àñ¯ß R»Y b¢úÄ_(%�…×L™ëa h²§5(·yÓn>�‘›éDŠ-¤Á»ˆ/HòÒ{uäef�/TCIÇ·R+FlÁ±øÄ» ÷UãÚ8ïúfBûa¦Þ<š’9 ¡ŒUvnɆŒ`g K³1–ŠN�Dß·¬ ÇL§? :ÚYS3oÜ 2b~ôg ó(š/¨y'æ”´¸ç@I%�JšZÐö3 lülŠY±=± ^!ua¯¼eAöè(†Ÿ34þܵÿÏSºaþ^ÀrŠÑrmgG`+n]8Ôī¿‹ù¨ˆ_Ã`ñ øHpn]á¼.2Dìò{µ¨ðDáÁí¶|’�>– ÇÓö~­mW�ÌÚxI�#¯g—zžÈ;‡*Õ~¶ïÅ ¦ëÞzi�9§6@û<û²ÂÔÆºI&o /Þ…t¯Ô,ˆ=?«v•s»Ü¥ÒÎ @™R)e~3ÛÑë�ûcêhiI�—·Ë�¸¥9«¾9Ü|F{ÿC2V1��°÷ÞSYêôše�@µ 9_,˜ í ñ9%¶ó£ùÂúÃbŸ…#æ2ä`O\úÈf+e^ìϦ�ê«_~úÆaÕgÛÖ;¸i † ï‘:§3mmØÁÚþ„ Ÿ{w©!dP-ÆæSêg£0ºÂÁ[Ü{efOŠ ˆ–s@¶ôÏÑ_!”um²hñM}õ!�å‹ë+Ò&�‚6YH C‹DµÕ{_ÅÅЧ0T7m`)C/4 Õ/a‡ •uâ©}XÛãcF ‰›Çš“SéºÄGÔÀbý�zðó¹EísÚ‚X¥çs ÚÿÙ‘žÿ:°÷dþ%ÎN—fÉóá ôVÍó ç掶¤CXÏIýóê +{A:3�Î×\4ñ&0]-k•ÈM$8£Äúâþ…éã§�jë]at ¸ÿ±/æ‰h& Ì(ÞŒj MΜûÊ+˜«ó½ãϹ¡ÇÉ8,'ÂC²Y0‚ùnù­eCÄ«®"¡Å«B¨û1øêåŒù�N>R.pñ1ü§)L­©Ó…WRW‡ÛZû°Ålÿç„£ª–ÝŒµé¤ &Ì‘ÔÜ+UáÌ&Ú«u´ýÝÖ~XªÏ"cÁ"l@u¸Ñ0¾ùòÈý×Ó'Ø ‚S¢XŠÀãZ¨\%téÔrŠ‹n¤¥5Ìç*¨\QzáÆ=@%â|¿øÑû.TÂO"µØ¸dGúE"sXYà!¾äx�­}M§ÖÎAdL¹Öï�„\•«üóͽlö·¦²ñeQMY¼’ãÆÓÑêìÎâ�Ðò^§ŸºŠÚð­)è›òê)—*ñæö} q ç‡ 0‹ãe¨ÇpwvšÓ æ¥I¯¼ØW‡ô,2_FüZl�à:Ô%,,�Ü!º9¾…yÓ”)[�~CZD,ÚëM“ß|NÀù_¨ÃJ[‘1hëäÔn¥Å-ª^÷rsÌ«§ymLBÁ÷Py‡…ÿk#”ÑQ{óxÅôgü[ ØH¬­a¼ ù¯¤w¢wGÕŸù^;Œ<ó?ó¨<¡Ý!ÆbNmÖð<^Ë´™É ýPÖË�Ò6»y^‹ù¡Ð†¤¿•;Ñ„@Š¢¤vf+]û²2{æ¡ÜVFªÚó¨e¦&™k1ÕVîj6¼_£™f½×L2bJ¯SÌÙmý�«3QIÜ]¹»ÜÖæ_Ÿ£‡ð8øŸ§{sB8çœsÎ9çœsÎ9çœs‚Ð�UA6†q§ HŸ£�EˆiȤÝ£Ã$h r ©G££‘Rê ”TÆI)� 4d!„RH!…RH!…Rˆ!†bÈ)§œ‚ *©¤¢Š2Ê,³Ì2Ë,³Ì2ë°³Î:ì0ÄC ­´KMµÕXc­¹çœkÒZi­µÖJ)¥”RJ) Y€d�AF!…Rˆ!¦œrÊ)¨ BCV€<ÉsDGtDGtDGtDGtDÇsUõ}Sv…áteß×…ßYn]8–Ñu}a•máXeY9~áX–Ý÷•et]_XmÙVY†_ø�åö}ãxu]nÝç̺ï Çï¤ûÊÓÕmc™}ÝYf_wŽá:¿ð㩪¯›®+ §, ¿íëÆ³û¾²Œ®ëûª, ¿*Û±ë¾óü¾°,£ìúÂj˰ڶ1ܾn,¿pËkëÊ1ë¾Q¶u|_x Ãótu]yf]ÇöutãG8~Ê€€Ê@¡!+€8�$‰¢dY¢(Y–(Š¦èº¢hº®¤i¦©ižiZšgš¦iª²)š®,išiZžfšš§™¦hš®kš¦¬Š¦)˦jʲiš²ìº²m»®lÛ¢iʲiš²lš¦,»²«Û®ì꺤Y¦©yžijžgš¦jʲiš®«yžjzžhªž(ªªjªª­ªª,[žgššè©¦'Šªjª¦­šª*˦ªÚ²iª¶lªªm»ªìú²mëºiª²mª¦-›ªjÛ®ìê²,Ûº/išijžgššç™¦iš²lšª+[ž§šž(ªªæ‰¦jªª,›¦ªÊ–癪'Šªê‰žkšª*˦jÚªiš¶lªª-›¦*Ë®mû¾ëʲnªªl›ªjë¦jʲl˾ïʪ)˦ªÚ²iª²-Û²ï˲¬û¢iʲiª²mªª.˲m³lûºhš²mª¦-›ª*Û²-ûº,ÛºïÊ®o«ª¬ë²-ûºîú®pëº0¼²lûª¬úº+Ûºoë2Ûö}DÓ”eS5mÛTUYveÙöeÛö}Ñ4m[UU[6MÕ¶eYö}Y¶ma4MÙ6UUÖMÕ´mY–ma¶eáveÙ·e[öuוu_×}ã×eÝæº²í˲­ûª«ú¶îûÂpë®ð p0¡ ²ˆŒaŒ1�RÎ9¡QÊ9ç dÎA!•Ì9!”’9¡””2ç ”’R¡””Z !””Rk8Ø )±8@¡!+€TƒãX–癢jÚ²cIž'Šª©ª¶íH–牢iªªm[ž'Ц©ª®ëëšç‰¢iªªëêºhš¦©ª®ëºº.š¢©ªªëº²®›¦ªª®+»²ì릪ªªëÊ®,ûªº®+˲më°ª®ëʲlÛ¶oܺ®ë¾ïû‘­ëº.üÂ1 Gà @6¬ŽpR4XhÈJ €0!ƒB!„�RJ!¥”0à`B(4dE'C)¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RH)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ©¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)•RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”R �Šp�z0¡ ²HŒQJ)Æœƒ1æcÐI()bÌ9Æ”’Rå„Ri-·Ê9!¤ÔRm™sRZ‹1æ3礤[Í9‡RR‹±æškVk®5çZZ«5לs͹´k®9לsË1לsÎ9çsÎ9çœsÎà48€ذ:ÂIÑX`¡!+€T¥sÎ9èRŒ9ç„"…sÎ9!TŒ9çtB¨sÌ9!„�9ç„B!s:è „B„B¡”ÎA!„J(!„B!„:!„B!„B!„RJ!„B ¡”P`�@€ «#œ�²€– R΄AŽA� AÊQ3 BL9Ñ™bNj3S�9�tjAÙ^2 € À (øBˆ1AˆÌ …U°À  æÀD„D�˜ H»¸€.\ÐÅ]BB‚X@ 88á†'Þð„œ STê àà ""š«°¸ÀÈÐØàèðø8>€ˆˆæ*,.02468:<€€€@€€OggS@–þ–ç=ý‚å'02310276;:?CCBl…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹¬Ø%ô B8FkF#ëœzÊýýžåJI`Ÿ76BU5À: š†îK.Þ[/IÀ´˜˜€Ž€ ~ÊýýžåJ¼çÛJÙ@!TÕ€ €z wPˆ{@Û‚š_,ß5ðè@ 4>ªýÿüå žík¥°@!TUè40ÑMtô™àÉÆ+ÚÙÁ…WÇуàÐ>ªýÿüšäâvy¨…PU¡ô…|G×�OӱЂ††�ÊpBÀ&€>ªýÿüšäîô4ª…PU'Ð@$¸O}�Ç%åMÒ;†:€ žä>ªýÿüšäÒ´ð&”ªÊ* @t𨴯ùçaï¥)t (4 ƒ˜šýÿOre1éM0BU 1>ÞY(¥ÚsYÀ&-RJgè¡ÕMkòØÀ‚VšýÿOr¥2ØåIØUUÅ@EO5š‚nE~IôÆÓ´JÊqØ)d¢U)°$ @šýÿOr¥28åMèªÊj ÌY�¬"æeç…d×Ôdþ‘òcw¢ ±“¦‘€d :šýÿOr¥`°Û›¸TU:Ì]¹¤¿\Ïô³\ÏÒ{QFH4¬T05Þyýök”‹2¸ÛÛXaE…P + &EÒæ^ ô#©”¶&Ú!ir}Ï””Ωaku¨“)lY �‚&˜ HÞyýök”‹2˜íMP*jT¦Þ1{Ã�1^_Y•¢~vçt×ZŸ}¹.ó­¡£ª9“5\1á)èàÁ_#ÞyýÿþåR Ny“B1ê,˜r(¶Øò³4ptmp sR›¦£L/g9‚èÞ?®Í0—M)°”,ZýÎu¹ƒ‘Þ8 4´X‰ h©u À÷ßÒ‹ö~>S£Èü†ý$=cr¦Èß7²ü¼öŽ¥ÏÃŒóù0ƒÊ«®b¥*¯ß·þQ�ÿŠá¨Y4®#öO¤Å± Š«=¡ P{údX]ÎÔýÎ59 £¼ „f)6ðÖ”³A`fœ“€½^�Ä!ƒ<©¬˜i0/d¥·?/Ôh³=é«m¤ò¶Þ­™ž��wÛÕZ:Ý–ÿ‰�^®¦×Ö‘&uVwû’CÅ_Åjð-˜mŒýÎu9 %½ Ð"++IÀ@âÊAGÕ�rý5]óo”X€¯/sãÎ�\ú çHÇ‘ÙqoÅóÈÐ3ú.+¼ð¬qÖ\E�¬SF’¿1R-à"ç ÜI¦ÏlÂjÂɘÌìæˆýÎwÙ4-= Ĥ¼ÌdÀ¢ÐIà,1æ8‘qü]âj­_è÷⥧Թéô''ïsçõu|‰ìwûæ¹ÅÇë�³Îå‹�/ó¡<:�0ÑÛå$¡Í½'—3Œˆí®�ý ýÎu9q­< B¡¡ËÂÉg�Pà€~57kg§P¿d´]�ÙÛü¹œÎo¿’_Ú¹Js)êã5÷Òä¤Åp–ô•õÚc\^;Ç¥QåtFôbˆ[D®áì §­“ýÎ5¹ƒVÞh’ʦ¡°@vv¿´ÄN˜¾d ¦²²Ki*¯u67[˜`&· 'nV‡§¯‹“ËÈcºt“Ÿq’C>-VþFŸÄ¼VÙ ]êïtGNÊy49ªéaœÙMãýÎ5¹ƒä�¡Xd‰‘\%`8�'\àÁÁû5ô�7‰M?/'x‘,ׯ×}Y¿Ž½nmcfFU)¸¸ð“‡0ÙëÞ¾ÕÑøÚ��·•êP[©+T²ûë¼ý2š\ÍüÓSœ ÂG.W¹èX©;·åUFÀhkôo†FØ/÷àÂu cÊ:ýÎ7Ùƒ–Þ8€˜š• ›0Ød7•\´×vÎ}ií½E«MÝ M3‹Š"äðºÏ~µ½b³¶#Ah©'òR‚ÑÖ&y,]~�MG“-9¶#8…þùäë¼�#s/yýÎ7Ù8ƒQ¾1ˆ•Ö%ˆ8€iup;š¤_I5…ÀÖÿ?»ØÄ&òÒµädu¡n±{½ï…é!‰Ÿ»:•¬Ï…úzÅU.25žBÉ–+Êèq0ïîQ®*/CUë&^ܱé-ýÎ59q#} „&å68ZÀ€ôлt3ü´WÜ™ohm™äP»-¨Y?Ç{ž°êŽLXø8&MöØ f%ªO©›÷NÉ”‰Íͯ®b¢ì½›ìÎÈPw¡ëWI;–ýÎwÙ(ƒ–ž„*hRdÁPL�Kºá?7œ�I—»B��Á¦Ñ|_O&±arúäºvQà$¹k×°d­Áå²l­Lc/["°R#lcú,èVÀÝ�Š…«äàHïbz¬Û{8˜TýÎ7Ù8ƒQÞ1ˆÉJQ3=HÐi—� ‚©æÊì•ä¸óM6¿ÝRmöµ|fê «ö’ôÑZ*Ìü(NbÎÑÙ&ç²ýÎu¹ƒ–ž@-jIÁ…&&èh‹o\ˆœ‰[¢ÆüJx2ÝÏÚ ^Cí7^:«YGcF¦òO}žÝºž‡ƒž�™‰°±<É~¾¬2Pâü"SÔÞ‰íõªÀö™!Gæ&ÛóS’‰�ÎI…¨ýÎu¹8ƒQÞ(BÌR¬H¦Ð‡YB,ƒ’²-oÅx3CT§XÈèòßÑ| éÈÓùÆûѳ^^ª„^‰)5=‚%G½pïb€{fy](€>(Ö÷:;ubjÙ:kGG:OggSD¬þ–ç=‡¿²¬‹‹‹‹‹‹ýÎ59 %½ ‚”. :>�þè]µ¤?÷TãÌxL€çsÔ˜žM›PÏXšÁ„—+q!^#§ÃaâèÑ|S«ã.�„™ãµ•«Q®%(Îsnå¶©lõ]”N-{~ýÎwÙ8ƒ™ž0B“b…qÄñ–X9vñ)l}¬Å¼�b‘Id=!û…t,W¢7Åæÿ9±¸õñ­Ûÿâ® Rñˆçƒfƒ©ÄÀoé<ïËÓ—·§¾UÚe±”׫üpõ0Úé[(wÉÎ"…ýÎu¹8ƒ–Þ„2h–¢"hrðÈ)=|éP›Û"ýr:Iò"q�ö°Ì˜è¹¨š¯à޾Rß"à€"«•uÞ½‰ þ¹Ú‡¿š.øAsñ©Ïˆnµïn7…£'òèeŽ~ ýÎu¹ƒÞ0B Í c@2 °8èä>h»ï_6ƒzyu—YÆü|$Ô•»¹Žëö¬ÊÀÅ…÷ñSìÙ n'E²0!¸¶²ö>~v3üayè™zŸ›9óMÔk ¦1×5„éW7ñ#ÞežÈiýÎwÙ8ƒ‘ž1h–bÞFh‚¦zmœòp4<¯å²é*é´ ´ÚäœÉ"N¨„ªñ|oâSðjl’ÌôøœxŽMqIß–Š'S´Î—WøKw®²:&U0TÌn;�‘bbž ÆPÈeýί² 8P‹<Üà0P8�Ó¹­j xz}]�Übeetbox-beets-00724b7/test/rsrc/spotify/0000775000175000017500000000000015253035401017500 5ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/spotify/track_request.json0000664000175000017500000001004715253035401023251 0ustar pieterpieter{ "tracks":{ "href":"https://api.spotify.com/v1/search?query=Happy+album%3ADespicable+Me+2+artist%3APharrell+Williams&offset=0&limit=20&type=track", "items":[ { "album":{ "album_type":"compilation", "available_markets":[ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], "external_urls":{ "spotify":"https://open.spotify.com/album/5l3zEmMrOhOzG8d8s83GOL" }, "href":"https://api.spotify.com/v1/albums/5l3zEmMrOhOzG8d8s83GOL", "id":"5l3zEmMrOhOzG8d8s83GOL", "images":[ { "height":640, "width":640, "url":"https://i.scdn.co/image/cb7905340c132365bbaee3f17498f062858382e8" }, { "height":300, "width":300, "url":"https://i.scdn.co/image/af369120f0b20099d6784ab31c88256113f10ffb" }, { "height":64, "width":64, "url":"https://i.scdn.co/image/9dad385ddf2e7db0bef20cec1fcbdb08689d9ae8" } ], "name":"Despicable Me 2 (Original Motion Picture Soundtrack)", "type":"album", "uri":"spotify:album:5l3zEmMrOhOzG8d8s83GOL" }, "artists":[ { "external_urls":{ "spotify":"https://open.spotify.com/artist/2RdwBSPQiwcmiDo9kixcl8" }, "href":"https://api.spotify.com/v1/artists/2RdwBSPQiwcmiDo9kixcl8", "id":"2RdwBSPQiwcmiDo9kixcl8", "name":"Pharrell Williams", "type":"artist", "uri":"spotify:artist:2RdwBSPQiwcmiDo9kixcl8" } ], "available_markets":[ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], "disc_number":1, "duration_ms":233305, "explicit":false, "external_ids":{ "isrc":"USQ4E1300686" }, "external_urls":{ "spotify":"https://open.spotify.com/track/6NPVjNh8Jhru9xOmyQigds" }, "href":"https://api.spotify.com/v1/tracks/6NPVjNh8Jhru9xOmyQigds", "id":"6NPVjNh8Jhru9xOmyQigds", "name":"Happy", "popularity":89, "preview_url":"https://p.scdn.co/mp3-preview/6b00000be293e6b25f61c33e206a0c522b5cbc87", "track_number":4, "type":"track", "uri":"spotify:track:6NPVjNh8Jhru9xOmyQigds" } ], "limit":20, "next":null, "offset":0, "previous":null, "total":1 } } beetbox-beets-00724b7/test/rsrc/spotify/multiartist_album.json0000664000175000017500000001353215253035401024140 0ustar pieterpieter{ "album_type": "single", "total_tracks": 1, "available_markets": [ "AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "PR", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK" ], "external_urls": { "spotify": "https://open.spotify.com/album/0yhKyyjyKXWUieJ4w1IAEa" }, "href": "https://api.spotify.com/v1/albums/0yhKyyjyKXWUieJ4w1IAEa", "id": "0yhKyyjyKXWUieJ4w1IAEa", "images": [ { "url": "https://i.scdn.co/image/ab67616d0000b2739a26f5e04909c87cead97c77", "height": 640, "width": 640 }, { "url": "https://i.scdn.co/image/ab67616d00001e029a26f5e04909c87cead97c77", "height": 300, "width": 300 }, { "url": "https://i.scdn.co/image/ab67616d000048519a26f5e04909c87cead97c77", "height": 64, "width": 64 } ], "name": "Akiba Night", "release_date": "2017-12-22", "release_date_precision": "day", "type": "album", "uri": "spotify:album:0yhKyyjyKXWUieJ4w1IAEa", "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/6m8MRXIVKb6wQaPlBIDMr1" }, "href": "https://api.spotify.com/v1/artists/6m8MRXIVKb6wQaPlBIDMr1", "id": "6m8MRXIVKb6wQaPlBIDMr1", "name": "Project Skylate", "type": "artist", "uri": "spotify:artist:6m8MRXIVKb6wQaPlBIDMr1" }, { "external_urls": { "spotify": "https://open.spotify.com/artist/4kkAIoQmNT5xEoNH5BuQLe" }, "href": "https://api.spotify.com/v1/artists/4kkAIoQmNT5xEoNH5BuQLe", "id": "4kkAIoQmNT5xEoNH5BuQLe", "name": "Sugar Shrill", "type": "artist", "uri": "spotify:artist:4kkAIoQmNT5xEoNH5BuQLe" } ], "tracks": { "href": "https://api.spotify.com/v1/albums/0yhKyyjyKXWUieJ4w1IAEa/tracks?offset=0&limit=50", "limit": 50, "next": null, "offset": 0, "previous": null, "total": 1, "items": [ { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/6m8MRXIVKb6wQaPlBIDMr1" }, "href": "https://api.spotify.com/v1/artists/6m8MRXIVKb6wQaPlBIDMr1", "id": "12345", "name": "Foo", "type": "artist", "uri": "spotify:artist:6m8MRXIVKb6wQaPlBIDMr1" }, { "external_urls": { "spotify": "https://open.spotify.com/artist/4kkAIoQmNT5xEoNH5BuQLe" }, "href": "https://api.spotify.com/v1/artists/4kkAIoQmNT5xEoNH5BuQLe", "id": "67890", "name": "Bar", "type": "artist", "uri": "spotify:artist:4kkAIoQmNT5xEoNH5BuQLe" } ], "available_markets": [ "AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "PR", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK" ], "disc_number": 1, "duration_ms": 225268, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/6sjZfVJworBX6TqyjkxIJ1" }, "href": "https://api.spotify.com/v1/tracks/6sjZfVJworBX6TqyjkxIJ1", "id": "6sjZfVJworBX6TqyjkxIJ1", "name": "Akiba Nights", "preview_url": "https://p.scdn.co/mp3-preview/a1c6c0c71f42caff0b19d988849602fefbf7754a?cid=4e414367a1d14c75a5c5129a627fcab8", "track_number": 1, "type": "track", "uri": "spotify:track:6sjZfVJworBX6TqyjkxIJ1", "is_local": false } ] }, "copyrights": [ { "text": "2017 Sugar Shrill", "type": "C" }, { "text": "2017 Project Skylate", "type": "P" } ], "external_ids": { "upc": "5057728789361" }, "genres": [], "label": "Project Skylate", "popularity": 21 } beetbox-beets-00724b7/test/rsrc/spotify/japanese_track_request.json0000664000175000017500000000777015253035401025130 0ustar pieterpieter{ "tracks":{ "href":"https://api.spotify.com/v1/search?query=Happy+album%3ADespicable+Me+2+artist%3APharrell+Williams&offset=0&limit=20&type=track", "items":[ { "album":{ "album_type":"compilation", "available_markets":[ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], "external_urls":{ "spotify":"https://open.spotify.com/album/5l3zEmMrOhOzG8d8s83GOL" }, "href":"https://api.spotify.com/v1/albums/5l3zEmMrOhOzG8d8s83GOL", "id":"5l3zEmMrOhOzG8d8s83GOL", "images":[ { "height":640, "width":640, "url":"https://i.scdn.co/image/cb7905340c132365bbaee3f17498f062858382e8" }, { "height":300, "width":300, "url":"https://i.scdn.co/image/af369120f0b20099d6784ab31c88256113f10ffb" }, { "height":64, "width":64, "url":"https://i.scdn.co/image/9dad385ddf2e7db0bef20cec1fcbdb08689d9ae8" } ], "name":"盗作", "type":"album", "uri":"spotify:album:5l3zEmMrOhOzG8d8s83GOL" }, "artists":[ { "external_urls":{ "spotify":"https://open.spotify.com/artist/2RdwBSPQiwcmiDo9kixcl8" }, "href":"https://api.spotify.com/v1/artists/2RdwBSPQiwcmiDo9kixcl8", "id":"2RdwBSPQiwcmiDo9kixcl8", "name":"ヨルシカ", "type":"artist", "uri":"spotify:artist:2RdwBSPQiwcmiDo9kixcl8" } ], "available_markets":[ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], "disc_number":1, "duration_ms":233305, "explicit":false, "external_ids":{ "isrc":"USQ4E1300686" }, "external_urls":{ "spotify":"https://open.spotify.com/track/6NPVjNh8Jhru9xOmyQigds" }, "href":"https://api.spotify.com/v1/tracks/6NPVjNh8Jhru9xOmyQigds", "id":"6NPVjNh8Jhru9xOmyQigds", "name":"æ€�想犯", "popularity":89, "preview_url":"https://p.scdn.co/mp3-preview/6b00000be293e6b25f61c33e206a0c522b5cbc87", "track_number":4, "type":"track", "uri":"spotify:track:6NPVjNh8Jhru9xOmyQigds" } ], "limit":20, "next":null, "offset":0, "previous":null, "total":1 } } beetbox-beets-00724b7/test/rsrc/spotify/album_info.json0000664000175000017500000006510615253035401022516 0ustar pieterpieter{ "album_type": "compilation", "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of" }, "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of", "id": "0LyfQWJT6nXafLPZqxe9Of", "name": "Various Artists", "type": "artist", "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of" } ], "available_markets": [], "copyrights": [ { "text": "2013 Back Lot Music", "type": "C" }, { "text": "2013 Back Lot Music", "type": "P" } ], "external_ids": { "upc": "857970002363" }, "external_urls": { "spotify": "https://open.spotify.com/album/5l3zEmMrOhOzG8d8s83GOL" }, "genres": [], "href": "https://api.spotify.com/v1/albums/5l3zEmMrOhOzG8d8s83GOL", "id": "5l3zEmMrOhOzG8d8s83GOL", "images": [ { "height": 640, "url": "https://i.scdn.co/image/ab67616d0000b27399140a62d43aec760f6172a2", "width": 640 }, { "height": 300, "url": "https://i.scdn.co/image/ab67616d00001e0299140a62d43aec760f6172a2", "width": 300 }, { "height": 64, "url": "https://i.scdn.co/image/ab67616d0000485199140a62d43aec760f6172a2", "width": 64 } ], "label": "Back Lot Music", "name": "Despicable Me 2 (Original Motion Picture Soundtrack)", "popularity": 0, "release_date": "2013-06-18", "release_date_precision": "day", "total_tracks": 24, "tracks": { "href": "https://api.spotify.com/v1/albums/5l3zEmMrOhOzG8d8s83GOL/tracks?offset=0&limit=50", "items": [ { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/5nLYd9ST4Cnwy6NHaCxbj8" }, "href": "https://api.spotify.com/v1/artists/5nLYd9ST4Cnwy6NHaCxbj8", "id": "5nLYd9ST4Cnwy6NHaCxbj8", "name": "CeeLo Green", "type": "artist", "uri": "spotify:artist:5nLYd9ST4Cnwy6NHaCxbj8" } ], "available_markets": [], "disc_number": 1, "duration_ms": 221805, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/3EiEbQAR44icEkz3rsMI0N" }, "href": "https://api.spotify.com/v1/tracks/3EiEbQAR44icEkz3rsMI0N", "id": "3EiEbQAR44icEkz3rsMI0N", "is_local": false, "name": "Scream", "preview_url": null, "track_number": 1, "type": "track", "uri": "spotify:track:3EiEbQAR44icEkz3rsMI0N" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/3NVrWkcHOtmPbMSvgHmijZ" }, "href": "https://api.spotify.com/v1/artists/3NVrWkcHOtmPbMSvgHmijZ", "id": "3NVrWkcHOtmPbMSvgHmijZ", "name": "The Minions", "type": "artist", "uri": "spotify:artist:3NVrWkcHOtmPbMSvgHmijZ" } ], "available_markets": [], "disc_number": 1, "duration_ms": 39065, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/1G4Z91vvEGTYd2ZgOD0MuN" }, "href": "https://api.spotify.com/v1/tracks/1G4Z91vvEGTYd2ZgOD0MuN", "id": "1G4Z91vvEGTYd2ZgOD0MuN", "is_local": false, "name": "Another Irish Drinking Song", "preview_url": null, "track_number": 2, "type": "track", "uri": "spotify:track:1G4Z91vvEGTYd2ZgOD0MuN" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RdwBSPQiwcmiDo9kixcl8" }, "href": "https://api.spotify.com/v1/artists/2RdwBSPQiwcmiDo9kixcl8", "id": "2RdwBSPQiwcmiDo9kixcl8", "name": "Pharrell Williams", "type": "artist", "uri": "spotify:artist:2RdwBSPQiwcmiDo9kixcl8" } ], "available_markets": [], "disc_number": 1, "duration_ms": 176078, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/7DKqhn3Aa0NT9N9GAcagda" }, "href": "https://api.spotify.com/v1/tracks/7DKqhn3Aa0NT9N9GAcagda", "id": "7DKqhn3Aa0NT9N9GAcagda", "is_local": false, "name": "Just a Cloud Away", "preview_url": null, "track_number": 3, "type": "track", "uri": "spotify:track:7DKqhn3Aa0NT9N9GAcagda" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RdwBSPQiwcmiDo9kixcl8" }, "href": "https://api.spotify.com/v1/artists/2RdwBSPQiwcmiDo9kixcl8", "id": "2RdwBSPQiwcmiDo9kixcl8", "name": "Pharrell Williams", "type": "artist", "uri": "spotify:artist:2RdwBSPQiwcmiDo9kixcl8" } ], "available_markets": [], "disc_number": 1, "duration_ms": 233305, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/6NPVjNh8Jhru9xOmyQigds" }, "href": "https://api.spotify.com/v1/tracks/6NPVjNh8Jhru9xOmyQigds", "id": "6NPVjNh8Jhru9xOmyQigds", "is_local": false, "name": "Happy", "preview_url": null, "track_number": 4, "type": "track", "uri": "spotify:track:6NPVjNh8Jhru9xOmyQigds" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/3NVrWkcHOtmPbMSvgHmijZ" }, "href": "https://api.spotify.com/v1/artists/3NVrWkcHOtmPbMSvgHmijZ", "id": "3NVrWkcHOtmPbMSvgHmijZ", "name": "The Minions", "type": "artist", "uri": "spotify:artist:3NVrWkcHOtmPbMSvgHmijZ" } ], "available_markets": [], "disc_number": 1, "duration_ms": 98211, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/5HSqCeDCn2EEGR5ORwaHA0" }, "href": "https://api.spotify.com/v1/tracks/5HSqCeDCn2EEGR5ORwaHA0", "id": "5HSqCeDCn2EEGR5ORwaHA0", "is_local": false, "name": "I Swear", "preview_url": null, "track_number": 5, "type": "track", "uri": "spotify:track:5HSqCeDCn2EEGR5ORwaHA0" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/3NVrWkcHOtmPbMSvgHmijZ" }, "href": "https://api.spotify.com/v1/artists/3NVrWkcHOtmPbMSvgHmijZ", "id": "3NVrWkcHOtmPbMSvgHmijZ", "name": "The Minions", "type": "artist", "uri": "spotify:artist:3NVrWkcHOtmPbMSvgHmijZ" } ], "available_markets": [], "disc_number": 1, "duration_ms": 175291, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/2Ls4QknWvBoGSeAlNKw0Xj" }, "href": "https://api.spotify.com/v1/tracks/2Ls4QknWvBoGSeAlNKw0Xj", "id": "2Ls4QknWvBoGSeAlNKw0Xj", "is_local": false, "name": "Y.M.C.A.", "preview_url": null, "track_number": 6, "type": "track", "uri": "spotify:track:2Ls4QknWvBoGSeAlNKw0Xj" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RdwBSPQiwcmiDo9kixcl8" }, "href": "https://api.spotify.com/v1/artists/2RdwBSPQiwcmiDo9kixcl8", "id": "2RdwBSPQiwcmiDo9kixcl8", "name": "Pharrell Williams", "type": "artist", "uri": "spotify:artist:2RdwBSPQiwcmiDo9kixcl8" } ], "available_markets": [], "disc_number": 1, "duration_ms": 206105, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/1XkUmKLbm1tzVtrkdj2Ou8" }, "href": "https://api.spotify.com/v1/tracks/1XkUmKLbm1tzVtrkdj2Ou8", "id": "1XkUmKLbm1tzVtrkdj2Ou8", "is_local": false, "name": "Fun, Fun, Fun", "preview_url": null, "track_number": 7, "type": "track", "uri": "spotify:track:1XkUmKLbm1tzVtrkdj2Ou8" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RdwBSPQiwcmiDo9kixcl8" }, "href": "https://api.spotify.com/v1/artists/2RdwBSPQiwcmiDo9kixcl8", "id": "2RdwBSPQiwcmiDo9kixcl8", "name": "Pharrell Williams", "type": "artist", "uri": "spotify:artist:2RdwBSPQiwcmiDo9kixcl8" } ], "available_markets": [], "disc_number": 1, "duration_ms": 254705, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/42lHGtAZd6xVLC789afLWt" }, "href": "https://api.spotify.com/v1/tracks/42lHGtAZd6xVLC789afLWt", "id": "42lHGtAZd6xVLC789afLWt", "is_local": false, "name": "Despicable Me", "preview_url": null, "track_number": 8, "type": "track", "uri": "spotify:track:42lHGtAZd6xVLC789afLWt" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 126825, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/7uAC260NViRKyYW4st4vri" }, "href": "https://api.spotify.com/v1/tracks/7uAC260NViRKyYW4st4vri", "id": "7uAC260NViRKyYW4st4vri", "is_local": false, "name": "PX-41 Labs", "preview_url": null, "track_number": 9, "type": "track", "uri": "spotify:track:7uAC260NViRKyYW4st4vri" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 87118, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/6YLmc6yT7OGiNwbShHuEN2" }, "href": "https://api.spotify.com/v1/tracks/6YLmc6yT7OGiNwbShHuEN2", "id": "6YLmc6yT7OGiNwbShHuEN2", "is_local": false, "name": "The Fairy Party", "preview_url": null, "track_number": 10, "type": "track", "uri": "spotify:track:6YLmc6yT7OGiNwbShHuEN2" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 339478, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/5lwsXhSXKFoxoGOFLZdQX6" }, "href": "https://api.spotify.com/v1/tracks/5lwsXhSXKFoxoGOFLZdQX6", "id": "5lwsXhSXKFoxoGOFLZdQX6", "is_local": false, "name": "Lucy And The AVL", "preview_url": null, "track_number": 11, "type": "track", "uri": "spotify:track:5lwsXhSXKFoxoGOFLZdQX6" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 87478, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/2FlWtPuBMGo0a0X7LGETyk" }, "href": "https://api.spotify.com/v1/tracks/2FlWtPuBMGo0a0X7LGETyk", "id": "2FlWtPuBMGo0a0X7LGETyk", "is_local": false, "name": "Goodbye Nefario", "preview_url": null, "track_number": 12, "type": "track", "uri": "spotify:track:2FlWtPuBMGo0a0X7LGETyk" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 86998, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/3YnhGNADeUaoBTjB1uGUjh" }, "href": "https://api.spotify.com/v1/tracks/3YnhGNADeUaoBTjB1uGUjh", "id": "3YnhGNADeUaoBTjB1uGUjh", "is_local": false, "name": "Time for Bed", "preview_url": null, "track_number": 13, "type": "track", "uri": "spotify:track:3YnhGNADeUaoBTjB1uGUjh" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 180265, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/6npUKThV4XI20VLW5ryr5O" }, "href": "https://api.spotify.com/v1/tracks/6npUKThV4XI20VLW5ryr5O", "id": "6npUKThV4XI20VLW5ryr5O", "is_local": false, "name": "Break-In", "preview_url": null, "track_number": 14, "type": "track", "uri": "spotify:track:6npUKThV4XI20VLW5ryr5O" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 95011, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/1qyFlqVfbgyiM7tQ2Jy9vC" }, "href": "https://api.spotify.com/v1/tracks/1qyFlqVfbgyiM7tQ2Jy9vC", "id": "1qyFlqVfbgyiM7tQ2Jy9vC", "is_local": false, "name": "Stalking Floyd Eaglesan", "preview_url": null, "track_number": 15, "type": "track", "uri": "spotify:track:1qyFlqVfbgyiM7tQ2Jy9vC" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 189771, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/4DRQctGiqjJkbFa7iTK4pb" }, "href": "https://api.spotify.com/v1/tracks/4DRQctGiqjJkbFa7iTK4pb", "id": "4DRQctGiqjJkbFa7iTK4pb", "is_local": false, "name": "Moving to Australia", "preview_url": null, "track_number": 16, "type": "track", "uri": "spotify:track:4DRQctGiqjJkbFa7iTK4pb" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 85878, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/1TSjM9GY2oN6RO6aYGN25n" }, "href": "https://api.spotify.com/v1/tracks/1TSjM9GY2oN6RO6aYGN25n", "id": "1TSjM9GY2oN6RO6aYGN25n", "is_local": false, "name": "Going to Save the World", "preview_url": null, "track_number": 17, "type": "track", "uri": "spotify:track:1TSjM9GY2oN6RO6aYGN25n" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 87158, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/3AEMuoglM1myQ8ouIyh8LG" }, "href": "https://api.spotify.com/v1/tracks/3AEMuoglM1myQ8ouIyh8LG", "id": "3AEMuoglM1myQ8ouIyh8LG", "is_local": false, "name": "El Macho", "preview_url": null, "track_number": 18, "type": "track", "uri": "spotify:track:3AEMuoglM1myQ8ouIyh8LG" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 47438, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/2d7fEVYdZnjlya3MPEma21" }, "href": "https://api.spotify.com/v1/tracks/2d7fEVYdZnjlya3MPEma21", "id": "2d7fEVYdZnjlya3MPEma21", "is_local": false, "name": "Jillian", "preview_url": null, "track_number": 19, "type": "track", "uri": "spotify:track:2d7fEVYdZnjlya3MPEma21" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 89398, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/7h8WnOo4Fh6NvfTUnR7nOa" }, "href": "https://api.spotify.com/v1/tracks/7h8WnOo4Fh6NvfTUnR7nOa", "id": "7h8WnOo4Fh6NvfTUnR7nOa", "is_local": false, "name": "Take Her Home", "preview_url": null, "track_number": 20, "type": "track", "uri": "spotify:track:7h8WnOo4Fh6NvfTUnR7nOa" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 212691, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/25A9ZlegjJ0z2fI1PgTqy2" }, "href": "https://api.spotify.com/v1/tracks/25A9ZlegjJ0z2fI1PgTqy2", "id": "25A9ZlegjJ0z2fI1PgTqy2", "is_local": false, "name": "El Macho's Lair", "preview_url": null, "track_number": 21, "type": "track", "uri": "spotify:track:25A9ZlegjJ0z2fI1PgTqy2" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 117745, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/48GwOCuPhWKDktq3efmfRg" }, "href": "https://api.spotify.com/v1/tracks/48GwOCuPhWKDktq3efmfRg", "id": "48GwOCuPhWKDktq3efmfRg", "is_local": false, "name": "Home Invasion", "preview_url": null, "track_number": 22, "type": "track", "uri": "spotify:track:48GwOCuPhWKDktq3efmfRg" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RaHCHhZWBXn460JpMaicz" }, "href": "https://api.spotify.com/v1/artists/2RaHCHhZWBXn460JpMaicz", "id": "2RaHCHhZWBXn460JpMaicz", "name": "Heitor Pereira", "type": "artist", "uri": "spotify:artist:2RaHCHhZWBXn460JpMaicz" } ], "available_markets": [], "disc_number": 1, "duration_ms": 443251, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/6dZkl2egcKVm8rO9W7pPWa" }, "href": "https://api.spotify.com/v1/tracks/6dZkl2egcKVm8rO9W7pPWa", "id": "6dZkl2egcKVm8rO9W7pPWa", "is_local": false, "name": "The Big Battle", "preview_url": null, "track_number": 23, "type": "track", "uri": "spotify:track:6dZkl2egcKVm8rO9W7pPWa" }, { "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/3NVrWkcHOtmPbMSvgHmijZ" }, "href": "https://api.spotify.com/v1/artists/3NVrWkcHOtmPbMSvgHmijZ", "id": "3NVrWkcHOtmPbMSvgHmijZ", "name": "The Minions", "type": "artist", "uri": "spotify:artist:3NVrWkcHOtmPbMSvgHmijZ" } ], "available_markets": [], "disc_number": 1, "duration_ms": 13886, "explicit": false, "external_urls": { "spotify": "https://open.spotify.com/track/2L0OyiAepqAbKvUZfWovOJ" }, "href": "https://api.spotify.com/v1/tracks/2L0OyiAepqAbKvUZfWovOJ", "id": "2L0OyiAepqAbKvUZfWovOJ", "is_local": false, "name": "Ba Do Bleep", "preview_url": null, "track_number": 24, "type": "track", "uri": "spotify:track:2L0OyiAepqAbKvUZfWovOJ" } ], "limit": 50, "next": null, "offset": 0, "previous": null, "total": 24 }, "type": "album", "uri": "spotify:album:5l3zEmMrOhOzG8d8s83GOL" }beetbox-beets-00724b7/test/rsrc/spotify/track_info.json0000664000175000017500000000454215253035401022517 0ustar pieterpieter{ "album": { "album_type": "compilation", "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of" }, "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of", "id": "0LyfQWJT6nXafLPZqxe9Of", "name": "Various Artists", "type": "artist", "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of" } ], "available_markets": [], "external_urls": { "spotify": "https://open.spotify.com/album/5l3zEmMrOhOzG8d8s83GOL" }, "href": "https://api.spotify.com/v1/albums/5l3zEmMrOhOzG8d8s83GOL", "id": "5l3zEmMrOhOzG8d8s83GOL", "images": [ { "height": 640, "url": "https://i.scdn.co/image/ab67616d0000b27399140a62d43aec760f6172a2", "width": 640 }, { "height": 300, "url": "https://i.scdn.co/image/ab67616d00001e0299140a62d43aec760f6172a2", "width": 300 }, { "height": 64, "url": "https://i.scdn.co/image/ab67616d0000485199140a62d43aec760f6172a2", "width": 64 } ], "name": "Despicable Me 2 (Original Motion Picture Soundtrack)", "release_date": "2013-06-18", "release_date_precision": "day", "total_tracks": 24, "type": "album", "uri": "spotify:album:5l3zEmMrOhOzG8d8s83GOL" }, "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/2RdwBSPQiwcmiDo9kixcl8" }, "href": "https://api.spotify.com/v1/artists/2RdwBSPQiwcmiDo9kixcl8", "id": "2RdwBSPQiwcmiDo9kixcl8", "name": "Pharrell Williams", "type": "artist", "uri": "spotify:artist:2RdwBSPQiwcmiDo9kixcl8" } ], "available_markets": [], "disc_number": 1, "duration_ms": 233305, "explicit": false, "external_ids": { "isrc": "USQ4E1300686" }, "external_urls": { "spotify": "https://open.spotify.com/track/6NPVjNh8Jhru9xOmyQigds" }, "href": "https://api.spotify.com/v1/tracks/6NPVjNh8Jhru9xOmyQigds", "id": "6NPVjNh8Jhru9xOmyQigds", "is_local": false, "name": "Happy", "popularity": 1, "preview_url": null, "track_number": 4, "type": "track", "uri": "spotify:track:6NPVjNh8Jhru9xOmyQigds" }beetbox-beets-00724b7/test/rsrc/spotify/multiartist_track.json0000664000175000017500000001235515253035401024146 0ustar pieterpieter{ "album": { "album_type": "single", "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/6m8MRXIVKb6wQaPlBIDMr1" }, "href": "https://api.spotify.com/v1/artists/6m8MRXIVKb6wQaPlBIDMr1", "id": "6m8MRXIVKb6wQaPlBIDMr1", "name": "Project Skylate", "type": "artist", "uri": "spotify:artist:6m8MRXIVKb6wQaPlBIDMr1" }, { "external_urls": { "spotify": "https://open.spotify.com/artist/4kkAIoQmNT5xEoNH5BuQLe" }, "href": "https://api.spotify.com/v1/artists/4kkAIoQmNT5xEoNH5BuQLe", "id": "4kkAIoQmNT5xEoNH5BuQLe", "name": "Sugar Shrill", "type": "artist", "uri": "spotify:artist:4kkAIoQmNT5xEoNH5BuQLe" } ], "available_markets": [ "AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "PR", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK" ], "external_urls": { "spotify": "https://open.spotify.com/album/0yhKyyjyKXWUieJ4w1IAEa" }, "href": "https://api.spotify.com/v1/albums/0yhKyyjyKXWUieJ4w1IAEa", "id": "0yhKyyjyKXWUieJ4w1IAEa", "images": [ { "url": "https://i.scdn.co/image/ab67616d0000b2739a26f5e04909c87cead97c77", "width": 640, "height": 640 }, { "url": "https://i.scdn.co/image/ab67616d00001e029a26f5e04909c87cead97c77", "width": 300, "height": 300 }, { "url": "https://i.scdn.co/image/ab67616d000048519a26f5e04909c87cead97c77", "width": 64, "height": 64 } ], "name": "Akiba Night", "release_date": "2017-12-22", "release_date_precision": "day", "total_tracks": 1, "type": "album", "uri": "spotify:album:0yhKyyjyKXWUieJ4w1IAEa" }, "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/6m8MRXIVKb6wQaPlBIDMr1" }, "href": "https://api.spotify.com/v1/artists/6m8MRXIVKb6wQaPlBIDMr1", "id": "12345", "name": "Foo", "type": "artist", "uri": "spotify:artist:6m8MRXIVKb6wQaPlBIDMr1" }, { "external_urls": { "spotify": "https://open.spotify.com/artist/4kkAIoQmNT5xEoNH5BuQLe" }, "href": "https://api.spotify.com/v1/artists/4kkAIoQmNT5xEoNH5BuQLe", "id": "67890", "name": "Bar", "type": "artist", "uri": "spotify:artist:4kkAIoQmNT5xEoNH5BuQLe" } ], "available_markets": [ "AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "PR", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK" ], "disc_number": 1, "duration_ms": 225268, "explicit": false, "external_ids": { "isrc": "GB-SMU-45-66095" }, "external_urls": { "spotify": "https://open.spotify.com/track/6sjZfVJworBX6TqyjkxIJ1" }, "href": "https://api.spotify.com/v1/tracks/6sjZfVJworBX6TqyjkxIJ1", "id": "6sjZfVJworBX6TqyjkxIJ1", "is_local": false, "name": "Akiba Nights", "popularity": 29, "preview_url": "https://p.scdn.co/mp3-preview/a1c6c0c71f42caff0b19d988849602fefbf7754a?cid=4e414367a1d14c75a5c5129a627fcab8", "track_number": 1, "type": "track", "uri": "spotify:track:6sjZfVJworBX6TqyjkxIJ1" } beetbox-beets-00724b7/test/rsrc/spotify/missing_request.json0000664000175000017500000000045015253035401023613 0ustar pieterpieter{ "tracks" : { "href" : "https://api.spotify.com/v1/search?query=duifhjslkef+album%3Alkajsdflakjsd+artist%3A&offset=0&limit=20&type=track", "items" : [ ], "limit" : 20, "next" : null, "offset" : 0, "previous" : null, "total" : 0 } }beetbox-beets-00724b7/test/rsrc/full.dsf0000664000175000017500000033762615253035401017464 0ustar pieterpieterDSD –¿\¹fmt 4"V€Üdata ¹ID3 0TIT2fullTPE1 the artistTRCK2/3TALB the albumTPOS4/5TDRC2001TCON the genreTBPM6TCMP1TPUB the labelTCOMthe composerTIT1the groupingUSLTengthe lyricsCOMMengthe commentsTXXX;MusicBrainz Album Id9e873859-8aa4-4790-b985-5a953e8ef628UFID;http://musicbrainz.org8b882575-08a5-4452-a7a7-cbb8a1531f9eTXXX<MusicBrainz Artist Id7cf0ea9d-86b9-4dad-ba9e-2355a64899eaTXXXCMusicBrainz Release Track Idc29f3a57-b439-46fd-a2e2-93776b1371e0beetbox-beets-00724b7/test/rsrc/empty.m4a0000664000175000017500000001334615253035401017553 0ustar pieterpieter ftypM4A M4A mp42isom ŠmoovlmvhdÄLé_ÄLï¬D¸@�trak\tkhdÄLé_ÄLï¸@mdia mdhdÄLé_ÄLï¬D¸UÄ"hdlrsounÓminfsmhd$dinfdref url —stblgstsdWmp4a¬D3esds€€€"€€€@xú€€€€€€stts.(stscÌstsz.22""'-+1/+&0''&%)(-,*).)(*%)-4&6.*,$,3/'& stcoÆé •udta �meta"hdlrmdirappl°ilst Wfreefree(mdatЃì\«11;Ä<Àøƒ¤4„ `I�fàe—^àï�P0#Ü·›�Áb˜Ä»VOØÙ(*¾J€q8òƒ„q©-@>Ťè[-3þ!‹rtg¼¼(ι¶q]b¥¸úƒÄPEÙ€€ ª°DãÙ‘>JUl3ËA$Ö)i)ƒÀúƒÄA#�€+:3ï`Xa¶™˜ÉùQ;«À±˜ˆèàöƒ¢" „Î Ž× óf{q wZ“Ä 3z¿f#)NÙq'øƒ¢" „kËr½ÙÖ£ g�§ý'”ê )y*¦˜Úö»,°Îµx¡úƒ¢" „r †BXVFìì7nhϦNž|z%ôe0Ue®«Œ œöƒ‚B„_`9åo¢ðJ­Dz0¯)òøáÛ1F8‘ú·åÉ>7t·#‹Uàøƒ¤4#ŒXÛõÞ™¾áàÒ`¸Ž‚Þ×xT†aGˆ~fäHv<ý¶ÁÀúƒÄ`? &ˆ×63Дl:äGàë’ 莵š„ÇÓëåN‚àúƒ¢R#Aש9Ï<³ÔiÇ%Öøê¦—µŠÍÎê®yfžÎôƒ‚T„ `®!�I}uhnV$?‹+ä¡(Z«„Á�¡Üta¥Vi±+±l‰8úƒÄ3#P�0¼ñ•T`’3¹èžÓ#?}¥ÕõÚ»ìÔ‹€úƒ¤Q#Hl`µˆÁ½¥ËK§)Q)E‚ñõ>O²Âô¯SÔ¦úƒÆ"#P ÛdpËŸ¿Û2é­~sÛÈÓï�'Pîì=Í&ü!úƒÄPG<Ž0NÝÍ�Eø™_ƒõ'1…:õ˜‹å\øƒ¢ ˆ,l ƒq¼Ôº<�¬>èðÍ&ïÞ¦J3}•]dQ€€8úƒ¢`F  8I+–¶:aá–;0¥Ç>m>;ßM¾íÛ�Ÿ× ¥/gøƒ¤p>€ÞbSci›”¤L z:~H�5ƒM3©'°A+è&„f ‡Ö(pöƒ‚0!dÀ¢’¯:%¢C°9B³î+]þ3Z†¹ècJr†Â¶�öƒ¤`E€�a,]µ)\BiwÈ,yç@úD¸ù�ü'ħ¥¨Üøƒ¢ ˆÐÀ€0qóà=bžmBÅAwùH°×! šDSª� 8öƒ‚5 !`Â4†§å^ñíª^:$9µÏ…gs`M%…ÊZZtª^U£Y(o€úƒ¢"ˆ¤09œ’#NÑ·#̬zÚW›;t A-1dyß”3¤^ àúƒ¢" "ìFâwì¼ú„,µ¸rŠþ¬js%”ŸÒísÙfžep=¼øƒ¤`G €@ÀãÒ5?à¼`•Ø�ÉÍM²ÈöÆýYB^×;C€øƒ¢`BÈ ÆãiRø—‡iéŽ6ˆ0 9ü¾åÓvë…(ÜÿÿGYJ´…=˜¢oçlÇWøƒ¤3 BÐ3ÜQhLÖÆ$/ê‡b<÷~³µ8ëûÛΚS�­n*jõXeÅ×7’#àôƒ‚"(„@Ø Ad¨*Â`óÙ'ሬÁ®co·>Vûça &µ% øƒ¤`F‚ ¢±äßxã}¸<ëÊüfP[2ÚqXä.Š'Iµpúƒ¢" „¤*ÓØšÖ'êŠÇÉR™z[oÝÓ¬ía‚„¾”XÇS2p'ÀøƒÆ2! éZðÞx²µ¾ùìú$©¿Vn´%j(óVÀöƒ¤`F‚�€öŽ�F†@›c}}ðCÂ2>Û<ÆçO5£!¹QÞ/grD�ðúƒ¤aBàô‡2‰´S(^®Z�dð{¦P�¤Ÿ~‰ÙÛ˜¦‘6 Sºœöƒ¢ „,`¼-1wNÞAÀÍ”XPKh¡wKÛ#0R¬Y±X�-Àøƒ¢`E� "ÅImq¤>w¢È1s5{!ÁXº[¯/æÛ?ÓG�¥xøƒ¢2"%€Xä  aÔž®ŽæÏû©ÆÏç¿÷º�r¯˜LaÀƒì\ªRi"?pƒì\¬ „ô@À\beetbox-beets-00724b7/test/rsrc/image.flac0000664000175000017500000005260215253035401017721 0ustar pieterpieterfLaC"÷ Ä@ð¬D!îÄvoWeƒ×l°÷�Ï image/png album cover›‰PNG  IHDR6ˆIÖ pHYs  šœtIMEÞ  J™tEXtCommentCreated with GIMPW�IDAT×cüÿÿ?‚9Ñ…'IEND®B`‚¨ image/jpeg the artisttÿØÿàJFIFHHÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÄ ÿĵ}!1AQa"q2�‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2�B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?’€?ÿÙ�ÃÿøÉ•@µÇ!Ì¡'†hPæhRs%… $¡aäÌ̔Ô9C9)™<¡C™”ÌÌÓ%8Y”Ÿ)…% aœ(r’‡49CL9C%RY’Ì<ž… dÓ ”)™™œÎd¦M 礧2…&yùgÐÉågÊaá94�% L³9œ(Xp¤¤¡ÃB…3™e% B‡ ˜D™¡= ¡@³ ) !ý Ì’˜s(NN’…2P¤¡åe&faʤÐå3$C'3™ g$³ 3”%8RS%™"Bœ,’” IC„By— °ˆaNˆ”„Lä‘ ”Ê”¡”’yC“2i…9ÿÿ¤¡a))™B‡ f,0©@¦„¡IÉþ†Re ¡(XS� …†Ng:OCž†s¡C™C<3Ì4ÉL(hÌ9å”)“"))(Rp¦Jg3™™˜S39òÊ�I’‡?)“)9C3'(e äžPÊI,)(S L”)'&p¦r†œ¡Ìáae ”2P)2�HD%B†”†Je2yB„ˆP‘‡‡(~y@¤¡4)“L<™2“¦K(y(”2“‡3ýPç)3™™”)<ÊaC˜R�¡g)“)3æS0¥ 䟔ÉÒ2d@°å$晡C…†s,Î�C“™ XzBœ)™’�a@Ò�¦�ÌÊÊI伡I’‡%0æRe'ÊPÉB’PÌÃI”'&RP”2yNe2 ‘ 9ILÂ$2™)"% L¡Iš”þXRe&P¦pˆ(L¤þ†r…Pæ…$ò–,2’Pˆ”2’g JÉ43š¡CL)™Ìó”3' Ðå$C„ÉMRS%330%3 p¡I”2“†�IBr’�aÿùL’™2“ 3”É)'œ¡Ì§= ’˜x|)C9'èe$Δ dæsÒ$"I…9ô” 0§2̦g4) )(J¦g p¦fs)†œ¤¡…™¤ˆLÌ“ÂPçÐ)’„@ÐäBr� D…„¡á¡’�¤¤ô<'BP,(g(aaNÌŸ)ÊC930¤“ÃÌÌÌ)(RrPå0¦L¤ô9C””9œ¡Â!™HD fJ ç ÉB r“L‘$èg= 4Í ”9ÿ<¡É™™Ê<Ì™L%”’JL9ü¤ó9™C™L硜¡IB!(D9™ä§ L¤ÒS%2RRPСáI…†i4ÌÌÊ” fr’r„§9HD93ç@Í Ê3ÐÎPÌÉ™™™ÌÌÌ‘r™% 8d¡ÏBPÉÊLó9)C9”3’S32†JdˆL¡Ê¤¤¡Lá¡Ì")Ì,™Iè””90áÉL¦O”(g e&Rt3” D99I¡IL4)(y‡(g?@§ L™I”Ÿ)œ)Î�IB’‡))(r†PáC””9Ë sL2’O)%(O<æJJJJùÌÌ,™I$C!L9B„ʦMçB…‡(e$”¡2Â…8y”“çåŸÿ‘L¤™™%0ç”)'�IáNL)3å I™’r‡™ �œÊ)“L””ádÌ”š9�'IL”””9II)3?ýœ(g…2R†fLÿô2“!(D ™C32Jaœ™L,ÊJ˜rfH„ȇ“<)™…&hfPáC…8r!9ÊJrPˆJ”Éèffd¡Iå9¡B�§ÐfxÿøÉ’@µÇh!)œ“4)2™™œ¡I™™Âœœ¡ÌæfH�¡™L3”3ŸC”ÌÊå&s9Cœ¡IB“ÊÊàS‡2D2RRP¤Êý ðÊL¤Òz:†e Ì™çÿ¡Â$Í B…�Ð"LÄ2S„I„Iœå&|ÊLå&P¡Ìœç(fdša¦M™ÊL¤Ê”(JLÌ)(S'2PÓ g!d–JfP¦ffLå$§ fL¤ÏBP¤¤¦fK3Ì¡BP¦aIÌ”)2†hg4(hD L¡œô' S% r\3„@°Ïå&PäÊ"žILå p§8D9™ÊLÊœÎffaIB’…% NPžaL”)(y(S“)0²aIÂ’…' J ™ò…&P9@ær„§ fL¦¦M… LáÈ�N(RfP¤Ï(RP¤ÿ‘& Έd"rfs9B“™“òœô(Jr™(P� Ì” J¡œ D”)™”(s'3œˆ¤§‡3ЙL)3ÌʘYœÎPæRe2JJ’På æ™4Ô)8P¤ÎfJåž’™""ÎS’’�IIB˜p§33%8\9žff4e$ÊIC„I?(RaLÃɦÉÌÌ¡IžS…9È“4Ì)Éš Nr!(RyB’xJDPÊ99”9ùe‡=0ÊLå…%™3™ÌÊ™¡œ¡Â!(S&RæaJIáœ(S'0§' 3ÉL”)̧ dó‘ žPæg0‰2PÐÊL°³B�¡’PÉ”šg>i'Bee I…8RP¤È�Nd‘ œáNLæIL(Rg æS% ”�ˆ&JLˆIC¡BPˆJhPäÌÊB”“œ¤ÏŸÐå%%% ¤ÊJaÊB„ó–r$™He$ÉB!†™?"Éʘ~s”3™LçÐ))ú(I¡ Rg(g0‰3Í’ž†s¡È�BÌ4“œáœü¦ffL¤œ¡ÉLšOIô9CÃ2|ˆ%PÎ ”Ã)%2PˆJ ”(p¡C9333š…0ÎhsC� œå Ê,ü.)=!å ¦NRg” &rPÎIfg0Ó'aš…“3æRfe B!3™)˜Pá@²J8PÉ |ôÃ(PáN†PÎJB…&PáÎae%32’~dBag2’|¦s@‰0ù™’˜S33' ” ”&D'0²M ”(P§9Cœˆ¡Ìç3œ)")’!2!ÉÐ(RPô9èd¡Â!†g(Re'ü¦JB!HS)“)’�L”)8XDe0ó ™”)2“þS'”Ÿ)2“”ÉùB“2“úfs9™C93% ™ÉÐÂÃ)2†rP¡L”?)2… æ'ÊL¡Ìå'¡ÊsÊdò˜s†JIL”Ì)™2!†“3) RLò�aILšaIɲR‡&sœæH… LÌÌ”ÉLÌÌ¡œÌÐ)(D39%'¤"‘ œŸ”2S%% 礡I”ÉL”3’™™?(S0РRgŸ”Ì”2P¡)ü¡É”„@Œ€D…„ÊM0”Ã33&“¤¡Ê™'ÊJ”™ç)™’†Éœ(2e„Ê¡ÏÊNP¤Ê)’g%„ÊJœ¡2!“™’†�IÉÈ„ÊY&’t&S$³,¤é†…'% IC% ¦™”8“ÿøÉœ@ÿÿµÆP!9BR‡™“ÎPðå”$ò…'3% ”šdˆp§&†NfaI”ÃÌág2’eB„¡’†O”)™ÌСÊ”¡œ"9’…&i)Ï"(fg?C'ÌÌ™9œü°ˆ@¤ÌÌ¡œ™C8D2p¡Îfs9œÏ$Iœ°ù”…2†s rP<“9))"˜xL¤Ì¡Ì.I¡�‰˜RR†r„ô œôÌÊ’” JH|¤ùgÓ0¤¦e áLÊI4Ÿ”Îç–ÉL,"8r™)’™œ)3I¥ ¦Â!™…“3„@°å$ÊL"ÉB’ŸB„ÒI¡BR‡�‰™“Bae2S’…2O …(M ”š™aNfe…% r“)%$¦)(ú¤)(d”™ó"y2†…'¡’†L¡“˜\žRe'”(p¡fS „¡¤ÌèfP)™(hd¤äC‡¡ÊfRdBe ”ÉòÂ’‡)4(g0ˆd§)<Â!„I<3’…&yB“œÐ¤Ê“ÉèfPç%2R�ÌòÊáBÉ™”ŸÐÂÃý&…&t�0òtÉNL¡Ì¦r‡˜RS aä:Ï¡’… Ìœ3C9C9$C…3$C”„ˆ™Ìó dÍ'L<”)2™œå$¦IB�æfrD)ffg% !JCL9”3% LÄP¦NM0òP¡IœÉfL¡Ìç9C™™C9œÉÃäÌÌ”ÌÌ”) "™™’”š™¦˜g(sò’P¤,Ê™43ŸC'™Îg3™I”™L„LŸ)™:ž, ™I¥œ3C')’s$@¤¡I)(S%2XD$Cœ"B”9œ¡œœÏ9C 9ž~Y¡C˜S… Ð3�§$¹œ)“™™œÎPÎgå2J“)(r„¡C“2e%œ2™†…%™")œ¡ÌÌÉB’g fg2’rS2�áaœårD)3‘„B„ˆPÊ™C”„Cœ2““4ÉLÌÌæyÊÉOÐááC38R†rd¡’…'8D9ÌæS!°"dèr’…&2e%PÊB‡“™2 P¤ÂžS…9ÊNPСə)˜Rf’…&Rr!C”(Rri…2s2RP¡ÌÓRtšaä¡I(p RfP"9Ì‘ ”)(RO% 2D9™ÌÌÌÌ¡L™@ç)œË3”3“™á,(hRC (žJP”¡=ÉäÓ åS3œå æe2hPç (d¡’“"�r!3ÎRg(L¤ô̦B”“ÿ)(ICý’’‡…&|¡C“™ÊÂä/”™C“(s …|ÐÉü°¤äB| (Iò…&r†�)™9™™)?”ÌÎ}“‡3”<<’…!BÉ”3Ây™”9”ÎdI'”™d¡¤¥ Ê9BrPˆ„BO’ F,ý ”ÃÌ9’Ê“2rS3%%%% IB�¥�fP,:R†B%…�JI”3%‡3(g0³3™")’™:JfP"\¡IŸ2’fs9™‡(̙ʔ"IæD) ™>P¤(RrR�¥!BÂ’…$”(JPç¡IBÌÌÌ)9™™™™)(r“Òçô'ü¦aðô%Ô̔32P)3ÏŸ(y…2p¡Ãœ)I<9”9™™™)™Âœ(S3™™™)’˜S&D&D3„I”Ÿ)9I”ÈD˜ÄÇÿøÉ‰@µÆè!339œÊað§ dóÎfaÊ!�s LÐÉB‡ N“L<”)8g?Ò…ÎP¦L¦JP”¡4(JBa&P¦Lä@Í °¦fM çÿ¡Í L¤¡”38Pæ…&RS‡˜g=De É”„I”3…0¦NJJHD)9‡’Y@¤¡™å2P¡áäœÿ)(L¤”“å9ÒzM0å Ì,Ϥ(X&xD™”4 J)9’™’„@ááe'I”” JÉå2|¤¡(p¦NP¤Â!Â’’…P¤ÊM Jfd¤äC'30§!a”Ù”8D8D)(Dœ¡)™†R NÏ)>èr„¡’�L™@ÎL¡Éæs0¦aIB‡“ˆL¤¡™™‡’áB˜hD $ð¡I”Ïœ¡™)™’ P¤ÂŸË 9ÎRg33338S3'333$C'%'IÒP¤ðä@òdC338D4(Y3”% “2D(JJBP²…&fffp³ p¦e J“2Pä@å%(OPÌÌ“ÉJ™)’™Ê̤”™IÊd‘…3 fg3™ÌÊ¡œÌÉL””ÉLɦ“å2t °”ÈDÉ32S&’†„C™ò™9L(D% ™I9„C%'(rPÎe&S'¡BR�ˆs:œ)’Xe&r’e!¦JaL™IL–g9C„C'2S dä¦yùL<…2hfp‰3IÒt(d¥ èÉÌ”'C &RM% s)2™(”<¡Î¤Ÿ 4ÉLÌ¡š<ÉÐÊLˆL¤¤¦g dÊ™“IB“†p¦N‡"8e Ì™B‡3ÿèp‰(æJB�‰“™™’!Â!Iœ¡ÌùLÌå!9ærS%2S9’’†xs¤ô32|¦NPæRz9Êdé;&ɦ¤¡LÌÏ’’�ÌÊdèr†fL¤ÊfS3™ùNÌÌÌÌç¡ÎD’RhP”ò™:Ô93™Â™9™ÊNS$ГBe$¡H_üó9CÌæ’…&)“òœé(Re0§$ D”)ÌÊÉ”332S<ò…d¡É™4ŸèäŸ)“þ’…&RzJ¡C… ‘R…PÌÉ”™Ê(SPˆÉI„”))˜RP¤¥ ä”ÉLæRIILÂ…!O¡= ý&”'˜S$òS”™Ê™(S0¤Â‡ (s,¡Ê2fr’†fs¡Iš™Â!Îd¦M0òP¡ÌФ"!JIpÊNfs<¡aš,"Ê¡“æRe‡(Nd¦fJd§ 3™C%% B‡ =%RP¦g„¡äÌÉ”‘ æOš?ô(JÄ@°ÊM0ËHD  R š™ÏI‘ Ð)HR’˜Rf“C„I…)$¡ÏI¡N¤™I”” Na¡4(9B�ˆž¡43™žyC@¤Í äˆd§Ð¡Ìÿ)“ y'3”(s39™…2s L¡”™IB…!BÎYô2r‡3”3“3%9Ÿ””2zÎ�I’�ˆd¦ˆgÿB’S!IùL9œÌÊ̤”,>�`A“)%8r!)ô2„Ê|ùBÀˆrdˆd¥$å B– J™’™™æyÊ y‡(dÐÉBLæK32P¤ç)”%�èf‡)’™))(RLçÐÉBe&†y™œÌ˜e&)2’’†‡))(sÒzaòî’ÿøÉŽ@ÿÿµÆÈ!å” 0¥ B’�IBÊÐ" XAP¡2˜y…™L””33 Re BœÉL)’”)8PáLÌÌÎdˆað§2P¡’”% Có”3™Îd¤¤¡Í'I¤–P<ÃB†…32‡(PÎå&S3<9 0ærS%0¡IB™…… Ÿ”Ì” NdÐ)�ˆd"LΔ)3Cœ¤ f†r„¡IIBÉœáá‘ 43…2JL¦OC”š2S”ÌÊdæfg8Y’!™…2Pˆg„ÐÉB“‡‡%gþ~ÿ”ÈDÌ)Ì"pÞ Y…È\’Ê… Ð)(“ÃÉ40Јp¤¡IBœ…™™Ã”2�džáe ù¡&„…�òi(Rp¤¡aNH†fNaæg”9…(pˆ…™Ìæyù¡BxPæg2…!9Ìó$C%(‘’‡&p¡I™Êœ4¡”ÉÉ32P°ˆJs3%2i…2hs>RPÏ0¤ÊJžg(y2Â!<ôš2†p¥$B‡2fJfP¤ÌÌ”,)"&fsCB“Ì‘0øP²N„¡Iša)†Re3ÿ¡…˜Sž… Ðô”šd¡Ê’‡˜y(RIr8S39ÎRr…�ä̇É&PÉáË JfPç†�áLš¤"ÃB’œÏ™”&D˜D8e&’†…% H�)I”Ìæ‡ p¦g ‡PæfPÉÔ9IL”ÉIB“)’…&zB„¦OÍ!))(Y2„È„Êfr‡(L‰2’’ Rg ¤È„ó2“’M ”<�2P¡Ì–P,2‡ fPÎsÐÎPÎe™JË…8RP¡Ì¤ˆP§(faÌ,™C˜S… 3™™(s)…(JfRfK0§„„³%)‡Â™2†s<¡ÉÌæJ9”ÌÉL“†pˆR¤ü¦N‡"(r‡‡)˜Y0ˆdÒIfrS3<å&y™…&S32†g�NICŸÈ�¡BPÊaòg2†rPÏP)’”<”)”™LÜÍ…&fPç rap’Èr‡)(hP”å2PÉåLÌÌ"L‘ @‚œ¦L¤Ë J™(™(g&e ˜s%% ÊaðÍ ÏC”ž‡(S33'% J,8RP))ž†sB�f¦ÊL°¦OžP¤”)39CC”„B“9C„C™LžS8P‰ ç(g&PæRJa̤Í™”“™˜S2P°¤³330ˆdæO…8hR9C)&p°") PÎÌÎRe3�2S2“"…&g 3Êp§'(g0ˆLÊ… C$¡C…9C”2Pç)9œÌÌÌÌÊÊaÏ)™ÊHPáNdI„IC)2’’!ÉB’g�LÉœ3’œôÂ’…3' (J3CB‡&ffe$ðÊB……”<3… È�)èdˆ%% ”$ˆdˆR) d¦H�HYœÊaÎP¦aC33…8P°Ë f!Jdˆœ“Ã9ùC8D9ÎdˆL"d”Τ",,"ÎP¤ D™�IC’!BSœ¤¡=™“% ”ÌÎr“œ¤"Lç3ÌüÐÉCš™C””ÌÌÌÌÂÂ’!(S…9™Ìå ”’�IžP¤¥ ðΤ%0”) RSúÐááC”2“(S$¡H|3IB™’™"Í æD’|¤že'ý0øhD!0‰ s™™)(Re39”ÃL§�aBÂÊ’�á¡NÌÌæp¤ÊN™6‡CÿøÉ‡@µÆØ! (e&J2„"d¤¤¡L)�Ð,Ê)�ˆXRR~RNdˆNaÏþ‡9Éœ¤že$¡IÌ”) 2RD JæRO3” dÌè™Cœ²‡™)“IÐÉóç”) PÌÎL¤’˜Rs 0³ JI„C%9O&™)48YCÉB‡'’„HP²fH‡9Ió PÒO@³4(rO”œ¤Â&O P“LùI”(RPô&˜0¦g$¥J…)%2hd Rd¡I”$¤’!2 s‡˜y‡˜xffN†J†hNRP4åŸÓ…933&˜Re!äËɤô9C”9é†hd¡…’~S'9C8D%8DÙ32RRD NL¡”™¦J B$)ÊaN‡4ÉrD) ÉB†… Jœ(s4ÉfáNs̳)HP¡CB‡(sB‡'(På d§(Sd”áfP¤)HS3%3%%P¦frJd¤¡IB’…“9C)3ÿI)BJd¥0¥ ”Ìå ÌùLžPæÉÌÌÊaNLÉþ…&S39""ÎffPùB™™2 s4'BJaIš"(dÒzJœ”¤(fPæP°¡aB“=” ̡̜Ê% NRO2‡Â™™?@§ 9”9é(PСI”<šd¦r…“)(RS3”)3”32rS&’™,ÉCIÓ ¤™Ê¡I”æy”™IÿùC™œå¦K‡ÉIL”ÌÎPСä,¤ y™:)“)˜S&e$ùȆJ|¡aÿúaL“2z8s)&PáÌ¡œ)™’!’™)™™Be'"I432� FáL™Iç"Ì¡œ¡Êd§ $ˆR"LŸ)…ÈS3%™”8\¡IL¦™)…% 8Y(pˆRNIL%RbÏœÎd°¡¡ÿ”” Nd¡C“8e2P�!BÉœ)9CÉù)<2ÎS'ô(g&sÒtš¡áœèRp§'ÊÌç(ry…’S3Ÿ?(Y3”ÉJ“˜y’!žC% ‡<¦f™Ïþ’†„Bg%2Y’™†…%39’!“™)(dùLÌŸ”ÌÎPæ‡4)0ˆp Y� áB!3'3œá¤þ�N™™˜S<� ”ÉК¡äÐå%2„æJfp§ fd¦J@°¡NtÌÊL¤”ÈD™Â™œü¤Ì””)(S“(pˆsú¡”%3"òs(d¡LÉðÒ„ÐÉL”ÌÂ!HSÿþY”ÌÉBP,™ÏÐÍ0°ˆÉB™@³'33 dÈ�Êd¥!BÂ’!(D%&IˆdÊd§0°¡ÊJf™¡ÏB|ˆL¡3%… °¤Ë%9ÎR ÊÌ)™žS'Êp¥$çü¦fLˆLÐ,(pˆrfO 3œ¤Êa̤”É(Rs)8S“9†… OCž“"a”…48S2J"™4Ìå')“”2s3ÌÌ8S” (ÊfffLÊI”˜D8s%&…&S$Bd@¤¡IL”É)(S9š¥$å&RLÎPÎd‰0²ff|Êa™œ"™3(™Éé4<„He˜S2e%2S&’… LΓ¤¡LÂÂ……39IBP, s'ò™%!æa¡’�aLÌÂÂ!ÉÌ””Ìχ fg p¡IÌ)Éže&R~hD(L¡œ))“LÌ,Â!¡šy2k»ÿøÉ€@ÿþµÆh aœœÌÉB�¡HP¡Ê¡™™œôž…9IÏ æg332R†re ”¡É"Hy™ÊOèg?¡œò“(PÐ"LÎfaL™L2Àˆh&rÂ’„ÿþe!¤-”'"9L”ÃÌÌ)‡3¡™Â’„ÊfO”“ÉNäùó9œ§)™™…8S3%2tÃ)“Ì生)‡˜e&39C3%É9”3’Y‡)(hRP¦NaB�¡I(s)œ¡C”(|4ÉI¡)ÿèaf} 礗'IICšaò†hg™ð³3P”(y9™”’…&J˜Y„L2“9fSfe ”(J™ÏIèdèN†r™œ”ÉIB!'%™2†P¡ÉÂ…$¦M’�áBPçL”Ê…0¤¡O'BP"B„C% )�‰2…P¡¡C”�0"J”3ŸB‡3C9”¡<¡Cœ(y™Ê9<šaÏùæs3(g2‡9)Ü)™œé= @¤æe$æD2P¦IC˜hD% JJ2“ ™™(P”"% ”’™)™™Â!™™(RO&’… dòg9C% N9'Ês‘&i’™)’™)(XS0°¡L”"̦Oÿþ†eaL’‡%&He$¦ffJ%&r“ç(s9CÌÎPÎS$@ˆJ,’˜PàA B™’†Oʦdä@¤¡B“"BœÊL*"B™„C<…(S!|¤ÿèPÎLÌ¡œ”2S)“úç)ÔÂy„BP „¡B“ÉL‘„ˆPòS™™"3¡HPСäåš¡�‚™áLžI2„¡aI@°ô2’„Bg ÌÌ(Ráae á™HYBS0Ò„)“IC@) dô™fR�Ì”2R†fdð²�ä’!„²hP²äÌÎe2†Jr“Ê™)% B dáfe%™ÃЙI„C…(sÊœ"œ’äˆP”Â…‡3”9™œ”)2™)™’!Â$"&LÉùL“”’P)(PæffJf¤(D†R¤ž<ÃB†˜y…s„šd³8R„Ê“B‡2…�¨‘Ì”¤žP¤ÊO9À°¡Î†sC”„C… Ê44,,"2“¡I˜„ÊJfså3 J2S39ÂÉ”9œÎg(Rs”,Ï(rs„C’^SŸ”̡ aN!@°ç(O…)33™”8Pð� ç)0¤ä¡I”<”Ìßèr’’…&hRrS&†fg(hr„¡™C)�³$C2“ ̦”&†xe!Ì)’œ"LÿȆJPÎC”””(s4ž’‡"ˆa¦JfM0”2P)Â�IO”ÃOC”)9…3$¤™“32S&!“œ„I„C38Y”"(r’…“9ÎdˆL¤é‡’™"ÊC:B‡&dœÉá<“Ñ…”2PÉC'Ê™1 ”ÌÌ)(Rs332S’!“ÃÌ)2……8S%3(s?)™Í Na¤é4(ry)’Ì<ÉLÎsœ,™™™…&Ðæ…&S0¤¡CI…“9™Â“˜y(RR�ˆX B!(D%(r�Ê% L¡)Î&%Ì“ä‰À‰(R|¤¡0‰2e!Ð"BœÌÌÌšN†só8P§ p°ˆJH„¡aNÉ”æPáœÎPó'þ†p¦OÊJ(PáB“,Îe$üüå$¡IžP¡I…3™”8D32rS$C0êàÿøÉ­@µÆà!™”’S NaLÉ”””2P¤ú愞ffJffR¡“™)’” °“C9¦M% L¤¡Êô8D4(y:”3˜D9)(… dä¡IÌ”ç,"†PÃáèffd”™ÌæÌ̤Â!Â!ÉB“?¡œÊL¤œ¤(D�¤òyI@¤"%2ä,¡Ïò“4r††S <§2”‡C9IB˜s>‡‡&PÍIÓ �L™ÌÌÉC@ˆJaN¡œ<¦OÊI"%†NJJfd¦aœÊdô J„I2„Ð)ÙÌÌÌÌ¡IÌŸ?”Ì"ÉB„ÎI RPÐÏ 2D2S$C%2D&D'2†rs9…9?”ÌŸ)…8PÌÉžg9þ‡(frP‰ áLÌšL‚H�¥&S2„¡”(i’™œÊ™C™å L̤’&INJRBÊáÏC”)2“ÐÌ¡ÉBR�²’…'0§ s“?þe$.Oò™:%<°¤¡= ó@¡"gÊdùNt8D‡¤)Ê8r’�¥%% Ì)œ(S&SR B$2!“™”9‡3LÎd¦B$ÂÊfp¡¡B™)œ¡¡9“9žP§ 38P,¡LÌœÃL”ÌÎPæg(s™ÌÿÐÉC9B…% Jaʇ †™†RIL)“™…8S…3’DÉò™3”% JJáB$2„óúJfp§&r‡% B”’˜S‡å9Ó%$@ЈJPÎ L”šLˆp¡ÊJ™C2e39IB™)™’™4ÃÉLÊÊ2f} ”3(s4ž“èd¡’„ÊO)™™œý æ… �ˆO0òNg”)0ˆP”Ï„Lœ™™™™˜P¤Ï!32Ri(Rs% !Iœ3ž„ÐÉC””)2†Ra&RRD 2S'C 3B’‡"¡9@ˆs(p‚!N¤¡L„@°§”ɔÙ̡œœ¦g†rN�Iå0Í …'(På ó”%™")™œå&s„@°¤þ†Re&…!C”�$ˆd¡Êœ)™™œ¦eæH’aá‘&s™”9ùLœË æffJp¡I™¡œ‘ žP²e2S9@²…33�2På ¡BD9L))’™‡“B‡3B“):)<§†rs"„B™É)“B‡2˜S…9™™)˜RgC”)“œ"(D%&PåÌ™gÒP¤šœ"…&†J(p¤¡2$…Ã90¦(S I¦f!JND H�CœÊaædÐÉC”)“)=0¦Iæe$󔜈J”3(p RgúJÎaL™IBÂ…’R†fJœ)&dÊ9’‡3œ¡ær‡(g Ê™“L<”ÌÉL”‘ ”„BP‰'>�IB‡’|¡¤¡aÿС–IÊS!L�‘„ˆD2R†p¦aI”ÃɦI<”,(sȆJ}’…†Y2’JP2D)2™4)(S' ¡œ=Ì"Í3™Ì‘“™Â D…„Ê“"(d¡œé‡ÉФ2Â…&e Iá9(p‰ “„C˜Y@²e9Iˆdä¦J”3Ÿ9I@#0ÿ‘LÌÌÌÌœ¤ô 3èg(Rf“"aäæs”™C”P,94�fNRP)3(O3ÊÊÊ”2R†JaäÒ„¥% Òzd¦På™ÉL–fs9)™™BdBNz"= ¡Â!'(Pžt(XpˆJ@‚¿ÿøÉ ª@µÆ� g™Âœ(Y%„BP‰% LÊ“(r’…2J™””9C”9Ièg(RP¤áI@³?ä@æNg)'œ)’hd¤þ†g�M!) RPˆ¤äBe'L‘É4𙡙@¤¡Bz¡L9šaLœÌ¡’‡†…2†pé%33„BP°¡I™B’”)™4ž“¦¡C™¤¡aO9C… Nd§™™™”<>dæffJ‡ô3’™™ä¡LÉNaЙ9††M!šäHICɦH†Jd¦fg$B“:ò™“æRg)2“9By)CÉ)’YРD™™IÓ†x !NC…$C9œÏ= IèJ%(r‡(e&P¦Ng9I”ÉÎs–9™œ¡C3d¡Ìú2’…%’…… dæ™IIINáfK33339B’‡2XrÂ…2rd@¡¡Ã””ÉL”š4(S2s s3339’!œÏ(Re ”9ILÌÌ)3ü§:9� =ÉÊœŸ>e$ó)3”œ²„¡C38P°§å8XD $ÊNPС̤¡C9ž… É”Ÿò™?СÌú"s&På ÎáNÉ”) ’t3…”8D2R�fS%32D2S9Ê™I)’„ÊB!C)3’Pæe$¡IOB„æL¦r’!ÉC“9™˜y4Îg30¦L¤¡Î˜y… ”)œÎg3) hÌ4ÃÌ”"C"I”“)&g3”)(RP9™Îá¦H�Ìô3Ô42PœÊaÊ&JIÊœ,"ÌáC…C–çùʆ’fJÊaIœ¤ÊdŸ2’�IÉý ffa†LæH†p‡<ÊI"9B™œ"„Be å IB’…$C'(d¥B!·(sB‡“"(Pæò“9Ìó™ÌÎPæPäÎffM0òS$B“ÏIé= ™C’‡3”’„@å 8yIš33&@Éažç)3”™B“%2t3”9ò˜e%! D9Êg‡' J32†Jd¦Jpˆs')'BdC'2e&$Î)’™˜D8YùÊIò™I<”Ì”ÈD˜S2”ÂY„BP¡äô…9,"…2e ¦¡BS…%3(JfdˆP”"(g&†L¦Id¡f'B�ú%?èfP”“2†…g(g&d¤¡ÊÉäÙ…9œ¤ô dÌÊI¡†” RaCœ§=30ˆd¡LÂÂ’“L>JR¡áÊåB”�³3”)œÂ$Â!œ(fRe339…2e$@¤¤ÂÂ…'% J™¡™Â!HR‡:aNe Lü¡I…3 ¡š” :4 P™@æS8SœˆPæpòP¤ÊJœÉI2RP¤æfxÐЧ'(PÍ ó”8D’†�aI8P¤ÊJÿB~faÍ !BS”Ìå% ')ÀŒ’YÊp¡¦S0¤Ì¤Êfe áùLÎhS9™”&D…)…!Jdÿ)’‡‡@³))“L)ÉLÎt(rfJ%œÌΡ’…%% L¤¡I”ÉÉáNPáær“”9™˜RaáC9”Ì� áI”)†Xf“‘ œ¦fsÿÐòPˆ)¡Cœ(J|ù”8RD%(y<¦dç30ÒP²adšaL%Ã<ŸC'å%Â…†C%))™)"™ÎPæK˜D˜YC˜D8P§B@­ýÿøy CÔ@µÇ(©i*”´¥¥-*ZUd«(´¥-IKDÊJYeDÂÒÊRË*YJ”¨µ¢©KQT¢ÒÉ•)ZXš,µ%,©(¹)QjJZ”©IjRL¨šRÒªT²¥)K(­%rWJV*X©bÊ‹R–T¢ä¢å)R‹JVT¬´¥©J–RÒKQj‹R•µ*KRZÉU%©-EI‹E­*¬©U’T¤˜š-,©Jª\²Ub¥‹KJZ-eKZJÔ––¤©¤‰ªER‹‹I”–´L´ZÊR¥©–Tµ,–RRÔ’Ò•-*²Ò–•YJ‰”¥%“%JK%T©eIeJR¥%–”\´²©,´²Ô¥%©.-,¸²Ô•”´«J\YZ¤ÑeJª¬¥JªURÕ*,¤²•,´¨µ%I2’Ô¥)--IjR’Ô–YQKR#)-U•*©2•Ee¤Ée¥+RZ¨µIJ¢eJK*Y*²ÒU%eJªªª¬¨š,–+,©)J‹TZ¥)e%”¬¨šYRËRT¤´«,¬µ*&I‰”¨¥ÉZ¢eeKRU*É+)JZJ¢Ê–TªÑk*R´²µ)R¢å*ZX¨šQ5"êT²Ê”¤ÉdÑKJYQ4¥R©eJT²¤¥¥-RZÒU(¸­JRL¤©EKK*’­,©ieRZ’Ô¥)R•-%R•*Yqbhµ”´•IZ’Õ)R¥–”¥©)2’–)&II’ɢʕ&QYKR”©U•,¥J«)j*Yh²¥V•¨µ%IeDÊRR¥JªUTµ)QiUJ¬’Ô”¥¤“IjJL¤µ¥¥¥•+)Q2”¨˜ª¢É•Y*¥e)iEÉe¢©JR¥)J‰•**R–’ªUU–\¤©eIJQieÊRÒR”¢Ô\YrTL©JRÔT¥”¨˜´²²Ò¥(™(µ\Z”¥KR©+K-%K%”–”™iIeIIeJÊ¢•)j•V¢–”µJ-J²U”©UK.)T²¥UU”–T\²´µEÄÅ¥R•,ªJÒ¬¥J´«J´¬´±kE,¥%-)UK-*IU)U*LZYUKJ”©R•JT¥)&J–*TT«QK)--QrÊ–R’–R¥,¸¥ÉU,©JZJ©eÅ‹R¤\¢âbÑ2¢eE©E¥*²’Ê•ZYRÒ¬¥”¬«,²T”¥)R‹’Z”R¨¥RZZZ”©e))UeK*Š.J-JK&’”¥¬Z¢¥¥*T\L©KR‹”Z¢eEe%KJ––-QKIU+KTªË*RËK,©JZ’Z’«)*T¥JZKRVJLZQ4YyU¥VYIjRÑe©)j,´¥JR–’–”\”¥)IjKR”¥*R¥)JR”¤µ(µEdÉdÉT¢Õ%ZJ¢–’¥–”µ%©--Dµ%©e*Qr•”¬¥K)JŠ–”¥”––\&T’«*-IR”¥JU*Yh¥¨€q¦beetbox-beets-00724b7/test/rsrc/space_time.mp30000664000175000017500000003102415253035401020535 0ustar pieterpieterID34TIT2fullTPE1 the artistTRCK2/3TALB the albumTPOS4/5TDRC2009-09-04T14:20TCON the genreCOMMhengiTunNORM 80000000 00000000 00000000 00000000 00000224 00000000 00000008 00000000 000003AC 00000000TCMP1TENCiTunes v7.6.2COMMengthe commentsTBPM6TIT1the groupingCOMMengiTunPGAP0COMMengiTunSMPB 00000000 00000210 00000A2C 000000000000AC44 00000000 000021AC 00000000 00000000 00000000 00000000 00000000 00000000USLTengthe lyricsTCOMthe composerTPE2the album artistÿû`À F=íÉ‘A#ô‰¹ÿÿÿÿF0ÃßÿC ÿ_ùïÿÿÿÿóÏ£)çÚa”2ùŠz<‚žyõ=xù=O `ÐÊÇ�  ¥à�Æyé>`øÜá ÐÀXè" z)ãBœ"À$)‚ �A„ ÿÿÿÿÿøÿ×?ÿûÿÿÿÿþ¾Ývb£×B�¬¦ ³4Àã°²+¸µÂ¤Ír¹Á�ÔR°Ä%;�îR£Q[ÿÿÿïÖÜîÿ³¾Ú7UW6dTUT!ub8´Çø çèx?ñ.Ì€ˆˆˆˆ�ÿÚÚ¢³<ŒaeŸDY/ÿÿÿ½ÿPœ¼·$D¬(躡ïPŒi§ÿû`À€Š9à… éâH#4•¸‹RÒAbÉuÏ&Ž ü:=ÄÝL´2!Ô¶#9îŽÔ#"5¿ÿÿÿú­ÿfE$ìȉ,ª1HËez²1’ª!ĨR ˜‰Ì§)¢((â¢,Êc°š)ÄÜX¢¬,qE„T9N@øˆtÿÿÒþ÷ÿ?ÿû`À ò= mÁ¸È#t�¸¿ÿÿóËäܯðÉ÷IN¡æiÞÿ{ÞžYg§S—ÜëdE/'ÿÿÿÿÿÿÿçþ§Ì¸g Wëï&%ÍirÄDuñ6.ÝítÜ‘mtP&ê,Ž�«¢’Duhâb¨D›ÀN±ÿÿÿÿÿý`Zÿý{ÿÿÿÿÿçÌímÞó¥/Þj¾GH„<&ñÎC¥ÿü„žl÷ÿÿÿÿÿÿÿýþÿçJÎÉP��1•¥I’òÔä»ò9£3³ZHFÊ;ŽÔr/viƒÃ�1  Ü‰…£2‡ ìÁ�ÿÿÿÿÿÖõÿþyÿ?ÿÿùz\¨Û+dDΪ�1ˆÆckTIw˜ÿûbÀ æ% „MɬH#t‰¸™¨…¶R²¶Í´öÿÿÿÿdÝꓳÐ÷1êr© ÊϳîÒ»³lÖ• lΆmC‘Uê÷c,ì$(tÈ4BKÿÿÿÿÿëåý²ëZSÿÿÿÿü¹QRÅ­ÝŒ‡>³Ìl®®è§1Œ¨ˆËf:V¨m&¾åDGB;?ÿÿÿÿÿù­RÌé+ƒ9‡}•+ϳ+±ÍUÐèÊbPSú;1Œ%Ü; Š…R•Ìwt”€Î9Bÿÿÿÿþ¶ƒÿëÿ•ÿÿÿÿäìúRwó5�lª„s>ʸõ#ÌäºuFlëÐêɕћÿÿÿÚÿ³«ÔªFJȪyŒEus–ÿû`À" ? „­Á¬Æ#t•¹a2ft*3άVwVl̸â•êc�@@Ç‚o2ÇåQÇ;> ¢£€?ÿÿõ�sÿÿÿÿÿü»µ®å:=¨îïv:ºº•VB/Îlêèö-ÊZ$Û™5OÿÿÿþÍ'*MD£�'» È.–z¹›S«”ÌêW!„Ça溡Z!3#NǞ#!ƒ¢âcH5VA¸ò¨`†`±�óõùþ¿ÿÿÿÿ®•g;RWT�ÙUÕ½ÔÝQeÑÑTľÎB%OÿÿÿõùÑgêÕ9F F‘�T‡j9"Î(cJb#!Ç�xˆÕ3³ ªEÿû`À, Ú= „­É¯È#4‰¸vcœqL8áaàÊPq¢�Ñ2$48ÿÿÿÿþÖ¯uÿºÿÿÿÿÿ?£‘Ý”„5›Rl›ogGÐŒªöi7ºÕŽ·ìKwÿÿÿÿÿÚÒ"1Ý_™Ü§8¤T„Dg�ä;YƒœFä%PìÆ \ÈäRŠF €‚äS3: ÁÈQBªà•Ü(ÿÿÿÿþÍ�—ÿ/ü¡ßŸõÿÿÿo‘œíbnYØz(‰‘ëu×J:ä·Id£ïZÐÔÙÿÿÿÿÿþŸJ'»Jƒ Ff®ï©Ne+ È 8ä*&*†q2 0�Ì AŠAD…0’�Q!2ª”¥A§aQEÿû`À6€ ¶A „­Á¬E£t�¹0ÿÿÿý°/ó׿ü¿ÿÿÿÿò]s¹œÐô… 仪Dþ9FzÓ¦[7‘t¥+M¹2ä³ÿÿÿÿÿÿÿéÿ9æÓ*FE‘D‰»ë2³×r™9“Ò·I­|¼UèÊã±Áz°spÂ+† JÛØ8ÿÿÿÿþ��©ü¼ògRfÒÏåÿÿýþ•$íc1üý§º!Yz:d÷#ê×*º%Pú?{¯ÿÿÿÿÿèɦ·5\ÎR£¾ì‚ŠTv{˜Ä$A™ RkÑi†ˆ!£±ÅÊ�Ö(|¨rˆ˜pðé¢î<ÂÁÀ+)�h0À5�"ü¿ÿÿÿÿÿdîÿûbÀBVA „­ÁÄÇ£4•¹�F±:¼Û>yê­)Ý�ì¬åºQò²+7cfTÿÿÿëÙ[óÉW£•hr¿ÿÿÿÿ�iO‰�&�׊aÒ¶§ö’ѺkL“ÔW0÷?ÜpµpÝÿÿÿÿÿÿÿ1ÿ×ýúÚuz÷¤sò8ë›~9�çˆ^;Ž’˜…ìar:¦hZ—Ro|†AwÚÖìXòo®Ü**>@Ö0ÿÿÿÿÿëËWuûJ�FÑYìîåˆòYÙræ\ˆîjí»*"±Hßÿÿÿÿ~î‰m¨—g*:˜…+"ofi•ÞÂ#E� �¨²)JçWACê,$aqÊÇ)„€p1Œ"Pè‘ÅH‡(Ñ¡`8�ÿûbÀo€5 … ɽH"Ì•¸3èòÿ¯ÿÿÿÖ×Ýzè¼ì×»Èr/È¢ Ê®”d£3Ñ—yN¤qÿÿÿ÷ä{"Zåu#ÌeR ¸ñŽÄsî®e-ESi‘�pÕ( ›0“�„bŽ3‡Àãs�†�yNEr”ÓŠˆ¨€� ŒÀÿÿÿÿÿí�yïÿéßÿÿÿýz.¥1,o5ä+9·Ežuvf±Îõ¹v}ÈÈ–NÿÿÿÿDû}l³µ+3UTŠCo¼¥>%èOyS!�XŒ‡‘Æi;�\ê8#)Ń:‰cÅ•Êt(P‘À?ÿÿÿÒÿùÿóÿÿÿÿù´š÷fÿû`Àx 9 ­Ù¤G£t‰¹b$„vºftgdû©kU-™œèƤÆVäfÛÿÿÿÿìŸêR>Ó­ÕK5(i5; Îñ“•ÑŠwiÇ*¹ˆ¤"âŠ*.*1â¦c´x´çRH@“ˆ#•bÀÿÿÿö@¿ÿ-»<ŽÄjµ=]ÖÓTª¤®Æ96Kä<îäsn³¼ó—ÿÿÿýv"Ñõ{Ñ]LëgR�g©ªF5ŽFuõZÇQ3�QÓ ‡Ç°›”a‡¨Ô ˜µÌ.tP‰GQCå<ÊÿÿÿÿÖþ]ÿþ«¯ÿÿÿþÞˆy‘žr3ÚÛg§Ÿ¤m4U++!d“Ö¶_J´Í{ÿû`Àƒ nA „­ÁªG£4¹ÿÿÿÿÿÿÿÿöù7ÈqyiHsC0¤Er_?* –gÐNP�‰îF¸v#UCªˆ9ŽB!* jè�A‡1Y(0ÿÿÿÿý`_óòþ_ÿÿÿÿüßíÑžïzJ_¹K&´išôE3Šeu!&>ˆˆþFÿÿÿÿéÌý<ˆs±Q#•ÞcÚï39’Àœ“Ùœ[%ÜÑÝÄÇ8s¸Îd†; áXä …C0­ƒÿùZõº�Výi ­b¹*ªOf3U§,ÍD=®E%^ÝËÿÿÿÿóHêí³=Uή¯­]�™žØâ®ª9ÕŒfd#9ÿû`À� òA „mÁžÈ#t‰¸Ñ�Ô�¤C»Tˆpø…Å”HƒbÈ s‘� E,*Qÿÿÿÿÿý`9oËêkÿýýÿÿÿÎë"åE§KQîÖÝ�Jî·<†aG TGȪW›F}]iÿÿÿÿêÞªú#f«¢Ì¨ÅUTH̵Eç̪·;f¤€ÜâÀÙÑÕN]Dœr¬¨qNÈaÝ(ÿÿÿþ²ûçþ}~_]ÿÿëïôìÌÇûèw.šQÞrØÌÌäb-lzèÒÒšÿÿÿÿßé­ÝíSUÐæg«DL†îB�ÓœxÝ� ¶QE§™ˆc±îD €Ñ3‡PƒÃ¡ÿûbÀœ 2A €­Á²H#4‰¸$)Ÿ1Qd‚ £ýÿçÿÿÿÿýÖþ—tÍT!˜¦ÈwS5îêëfº�ÐÅ*”�lý؈ŠßÿÿÿÿôºµYÊÊKžÓÊÄB²¢�Ïvj±•QXÌB *”a”£¤q3”Á7 áº¡b±Îƒ!¬k **�6Hÿÿÿÿ¶ü¿¿Ëå_ÿòùß%é,«¿uÜöeæBÊìöJ¹Mwº®í­]Õr«7ÿÿÿû¢Ú®d+Tµ#!•ˆDeœ‡æ)Øì…F•®q`³�QËÊ·K ‡!:ÁÎÂÃ�ur‹C˜®àÿÿÿÿú@¾_âüÿû`À©€ ž; „­ÉÁG#4•¹¯ÿÿÿÿçïÿ%2ó¥xzžõËa©—ÝßÈͶMŸšÃ™);þe­Ûÿÿÿÿÿÿÿÿù~~KrS¬[uvzŸzYq¢ñ òlQ�wÑß#}¨\‰jZ |‹T �¸Ä!ÌéÀÀàÿÿÿÿÿ�Ÿž Øç —Ne9Ÿÿÿç eR!áçÖVê¢õœ}!wÂOí3UUÚZWU>ÑÿÜWÿÿÿÿÿÿÿÿ?íñó÷+kLÖÃùŽ*Øëk‘s*—gJ�4`ž¹EÆÇviF"‡$˜z©†9‚XõÂa�Ë”9pèP·XT]Çÿÿÿÿÿc`qîyÿû`À²€ .A „MÁ­G£t�¹‰#±’¿%¾§ÿþY¸tûîú㙬ꙉy¥˜†ýwŠõÚ©¦÷ÞÒ¥©S»éºæÿÿÿÿÿÿÿþÿ¿ÿû¿Ž¹šk¯«YO›­²<6<’±…&TÉ눢Æ!wB±E2ˆ ¸ö³J‡4\V…K1`°’ކ6Ëq1Š@ÿÿÿÿý±ƒÍ#˜Wå¿Ì«ÿÿÿý:*\Ȫuo™��H(έb+JB{1¨¦î·±•jjÿÿÿþ�7¥®·tT2+9#ÝÖ<–ºœÈ©*­ ayŒQ1§3•Ú&=¥B�:``ë‘‚¢§Š ‰Zpð[JQÿû`ÀÀŠA … ÂÈ"´¡¸ €k?ýþ½ÿÿÿÿÿþÕdR•¨É¿WDJ2oR›±ÎÓêUd©Šf3¦Óo5ŸÿÿÿÿòKk­Ê„y™bêìêt3–S’È5‹Ž «�,† 1 áòŽr�JâŠ0¢„#(@Xêè$,�âŠ�8Š4xD*…„ÿÿÿÿÿ’Ëäû×ÿÿÿÿûνey5v}úº*±K÷U2‘ÖgR™–tK"µoEÿÿÿÿÿéîíLÊŒE:2+Ù’}Hî8†fc ‹³)†ÅÌîìBˆaÇds¸“!…„XPr˜xñÊ,Š($0<*5 †4lüÿû`À³€²A „­ÁÛH"ô•¸Ö|ÿÿÿÿÿÿôM‘Û[VÛ²NI”¬ÚÖçbk3›ß¢ªÕ‘Z~¿ÿÿÿõ¡j‡»µ¶g*•Ø”ssB«¥r”¬QGª‰ ”„)å1˜0‚ädÆw<)]Ì($aE8pj‡ÐhÀ³˜À¢¦‰€ÿÿÿÿþ��ßüÿF—=ÆÚþ¿ÿùå®›±÷õÌk*"§f5§¢*YÕC^bºê§»LÜÕ²ÿÿÿÿÿëî‰wcª¦UÎ<Ê;0Ô=QÖ«žŽ¤�:³ó¿ÿÿÿÏé¹&q…+T©µ'ÙTU•ŒgeR á‡B32)—ýž·D|ïÿÿÿÿÓ]«Mɺ+YŒ[Ö¦0Ò)ÊbŽ¥Ž5EQ„ÄEa!˜\h˜AÂ!ذ ³BÃîg À(ñá‚ÂC &P 8|DV&Qÿÿÿÿÿû`À´€ÂA „­Á×Ç£4•¹ÿéä^¤–ú,‹ÿŸÿÿžÒ÷f»‘×d[Òº½ V¹Lës ws)P§z^¬t252]koÿÿÿï§£÷]»ÍÊS2•gsƙٞDkaœÔ9�Ç#˜Â"%F âƒDL*£¢ (B" ‡XÂŽAìb¼>ÿÿÿÿÿ±…åþY//ÿÿÿüæ©J$î”Y?RºÑôVT}ÞŠrQKjßZmu}vÿÿÿþ«ëzttz%¦TS•1ä#ÌÆ½�j=‘Òª”ªQ!0c ÓH,¢å £ÄÄÊ,¡Ñw‡È 8ç1Ðå†0¸ÐÛ ÃjÐöÿûbÀ¶€A ­ÑÙÈ"ô•¸}s—ÿþ¿ÿÿÄ@÷:XÈ®M*¨Cc¹§r”ü­#çDQz­ªý§µ)ÿÿÿÿýþ–ÑNbç›-LQl„0׳ )�Ük ;˜Â,5ܣŃ‹;"Š 8ЦA¨$ÁÑqÆ�\M…EAB@Áç( *ÿÿÿþ��ÿ-ã4Ñ—pþRÿÿÿ³¢îVlìU·K&öu+<Ï™‡tLììv3¡ŠÔ³I{×ÿÿÿÿúûû•YÑ ¥*«“êçªîR†Ð<Ž=ÇÔLU…aÅqáL (sˆ”ñ¨§D4P€È�‚Ä !˜€8ÿÿÿÿÿû`À·€’A „­ÁñÈ"´•¸ÿìŒ w"šçÏ’–«ÿÿþMÿÇýwóó¯÷Üu]fFÌÕH÷SR‰õô±×K¯×ÿÿÿÿÿÿÿÿÿÏw§qóßLò°»O¥O3r²1GÔ­mÍ»±å;=šSÊ8y£2lÏ#•0ÑÄÃHˆpò �¢¥�% « €ÿÿÿÿÿ²ŸÏ_åËzÿÿÿþþŠŒ÷Z2>ô±• ŒÌ]ªC\�È„VGGuyÕ(Êr¢J´ÿÿÿÿû[BUÝŸaj«ö£[‹Õ™HŠèãLRˆ˜«yŒ‡œ¬C%Üq]Qbì->A!Y�â†`£1\Xâ@`Ò y?ÿû`À·6A „­ÁâÈ"ô¡¸—#ÿÿÿÿÊ­ä&ʪË�ÕèêÊ}V¤1Ö³Fnn¹:û[¯ÿÿÿëmjÌës¡ÒÕF!ŠbŠê®Æ)˜†‹‚*‘LŒcˆ°�j¡¬*‰¢ï0p¥>$av!œXè4DHÁÁ5‡ÅĨU(p@1@ÿÿÿþ­ƒüŒÿ¥ÔËïëÿÿÿ7êˆìµR!Ÿ#£µŠè¨~ܦf5æfb1ÞŽÝS"ÛÿÿÿþßèÍiš£P®vJÖ®d1qèq”2ÚÈ0:Å+‘Tƒ6aÂbEl?2‡DD…‡‡\M"B £¢† ”Ácˆ4\6à ÿû`Àµ€.A „­ÁçÈ"´•¸´ý¹~öÿÿÿþT«Û"£—ÜÇž—ÑsÙÑhê®DÎmYd½îdSnÛÿÿÿÿéí¾­:ª3š§š•c%®5HQU<§!ÅEHcDH@8â(‡E`=‡(¹Ã§qR¸²:$&<(j¹‹ÆŠ¸  ˆhˆØ6­ƒóæ¿ÿÿÿÿ#í%)sMªØí1ærÚì·IUkwG‘rîGtTe÷Ñ—ÿÿÿÿÞÕêÛ++Jζ%ƱÞÈÄÌ<‹;‘XÇ8qˆ‚:‹ Aa6qe- @ÊAA¦`‘Dˆa"ÄÆĘ„@ð™”:?ÿÿÿÿý$ÿû`À·€A „­ÁïÈ"´•¸/þN_¬™ôëÿÿä ÷Gõ>¾J¥Ó:²�—G4¸±Q(„tC\î{+©•®gOÿÿÿÿ쮕½Ôˆ³!O<®ë!¨Žd,ŠæR1>‚%f0°¬@ê>qâ¡ô (¨˜åœ4ÖQ!0ø€ºX‚eQC€ÿÿÿÿÿÒäþgì?ÿÿÿÿÿ-‘œ¦ŽI"*ÌD£™•̧Y§In–jH~­’Vkg»T®Š¬‹ÿÿÿÿ•úÑÌŽäRËÕ®¬–K¦í[ÝF"Ψpá®ås ƒ”<îƒáC‡A r$ò 0ˆ×R‹ŽÌWˆ€ÿÿÿÿÛÿÿûbÀµ^A ­ÁéÇâô•¸½ÿÿß›ÿÿü¿->ùŞó/ß&@ºÒzšºË)¢Ô-^Ÿð¼Ž½Ïmûÿÿÿÿÿÿÿÿå‘ßæe ·îV›E‚˜6��Þõ$4C¹»¼­dPÀŽŠ$B¬ŽAÅ£E "£,†8SW©9 € €`5‘çÿËækúëÿÿòÿZšçTC£ú^5Ýõ‘œ¨bT©‘Üz-®–™=¤½ŸÿÿÿýiCž”èËB)©au”‚o,ÑÈ8‡c‡ ""@”AÐD¥*<:*‡ °x:@ùDEEH8:.Œ…Ї†ÿÿÿÿ¶ü¿ùëïÿÿÿÿ©ÿÿ–ŽÍ­îGH¢’°»NÞ±™ÄW%²zÕóØøDo“eÞÿÿÿÿÿÿÿþ_ü?)¹leyX†¿ç)ΜzR̈Ÿ"]Ë•L´'dxÈÐtS 3j±Û é àÿÿÿÿÿÀ~˜dsÿû`À½€>A … ÂH"´•¸æ½ ÿ#ÿÿÿ˲µÐÕc0‰&V‰ZâBÅrÌdpëFEyFˆm ¥*³¬Î¾ë×ÿÿÿÿÿ¿¿mYÊŠVÊÆ}LêÆ+>j=‚¨,å-*UcÅB²=� QSÎPèÑÎ"ÊY˜H  ÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿ¯ÿý~Æ(`JEª*!ÙÙÊbª”Vs ` �#³±Š©ÿ³”ÁB(ÿû`À³€ n? „mÁÑF¢ô•¹ÿûbÀ»€&@ÞMÀ[Àÿû`Àÿ€ÞÀbeetbox-beets-00724b7/test/rsrc/playlist_windows.m3u80000664000175000017500000000012615253035401022133 0ustar pieterpieter#EXTM3U x:\This\is\Ã¥\path\to_a_file.mp3 x:\This\is\another\path\tö_a_file.mp3 beetbox-beets-00724b7/test/rsrc/unparseable.flac0000664000175000017500000005260215253035401021140 0ustar pieterpieterfLaC"÷ Ä@ð¬D!îÄvoWeƒ×l°÷�( Mutagen 1.22DATE=Oct 3, 1995� ÿøÉ•@µÇ!Ì¡'†hPæhRs%… $¡aäÌ̔Ô9C9)™<¡C™”ÌÌÓ%8Y”Ÿ)…% aœ(r’‡49CL9C%RY’Ì<ž… dÓ ”)™™œÎd¦M 礧2…&yùgÐÉågÊaá94�% L³9œ(Xp¤¤¡ÃB…3™e% B‡ ˜D™¡= ¡@³ ) !ý Ì’˜s(NN’…2P¤¡åe&faʤÐå3$C'3™ g$³ 3”%8RS%™"Bœ,’” IC„By— °ˆaNˆ”„Lä‘ ”Ê”¡”’yC“2i…9ÿÿ¤¡a))™B‡ f,0©@¦„¡IÉþ†Re ¡(XS� …†Ng:OCž†s¡C™C<3Ì4ÉL(hÌ9å”)“"))(Rp¦Jg3™™˜S39òÊ�I’‡?)“)9C3'(e äžPÊI,)(S L”)'&p¦r†œ¡Ìáae ”2P)2�HD%B†”†Je2yB„ˆP‘‡‡(~y@¤¡4)“L<™2“¦K(y(”2“‡3ýPç)3™™”)<ÊaC˜R�¡g)“)3æS0¥ 䟔ÉÒ2d@°å$晡C…†s,Î�C“™ XzBœ)™’�a@Ò�¦�ÌÊÊI伡I’‡%0æRe'ÊPÉB’PÌÃI”'&RP”2yNe2 ‘ 9ILÂ$2™)"% L¡Iš”þXRe&P¦pˆ(L¤þ†r…Pæ…$ò–,2’Pˆ”2’g JÉ43š¡CL)™Ìó”3' Ðå$C„ÉMRS%330%3 p¡I”2“†�IBr’�aÿùL’™2“ 3”É)'œ¡Ì§= ’˜x|)C9'èe$Δ dæsÒ$"I…9ô” 0§2̦g4) )(J¦g p¦fs)†œ¤¡…™¤ˆLÌ“ÂPçÐ)’„@ÐäBr� D…„¡á¡’�¤¤ô<'BP,(g(aaNÌŸ)ÊC930¤“ÃÌÌÌ)(RrPå0¦L¤ô9C””9œ¡Â!™HD fJ ç ÉB r“L‘$èg= 4Í ”9ÿ<¡É™™Ê<Ì™L%”’JL9ü¤ó9™C™L硜¡IB!(D9™ä§ L¤ÒS%2RRPСáI…†i4ÌÌÊ” fr’r„§9HD93ç@Í Ê3ÐÎPÌÉ™™™ÌÌÌ‘r™% 8d¡ÏBPÉÊLó9)C9”3’S32†JdˆL¡Ê¤¤¡Lá¡Ì")Ì,™Iè””90áÉL¦O”(g e&Rt3” D99I¡IL4)(y‡(g?@§ L™I”Ÿ)œ)Î�IB’‡))(r†PáC””9Ë sL2’O)%(O<æJJJJùÌÌ,™I$C!L9B„ʦMçB…‡(e$”¡2Â…8y”“çåŸÿ‘L¤™™%0ç”)'�IáNL)3å I™’r‡™ �œÊ)“L””ádÌ”š9�'IL”””9II)3?ýœ(g…2R†fLÿô2“!(D ™C32Jaœ™L,ÊJ˜rfH„ȇ“<)™…&hfPáC…8r!9ÊJrPˆJ”Éèffd¡Iå9¡B�§ÐfxÿøÉ’@µÇh!)œ“4)2™™œ¡I™™Âœœ¡ÌæfH�¡™L3”3ŸC”ÌÊå&s9Cœ¡IB“ÊÊàS‡2D2RRP¤Êý ðÊL¤Òz:†e Ì™çÿ¡Â$Í B…�Ð"LÄ2S„I„Iœå&|ÊLå&P¡Ìœç(fdša¦M™ÊL¤Ê”(JLÌ)(S'2PÓ g!d–JfP¦ffLå$§ fL¤ÏBP¤¤¦fK3Ì¡BP¦aIÌ”)2†hg4(hD L¡œô' S% r\3„@°Ïå&PäÊ"žILå p§8D9™ÊLÊœÎffaIB’…% NPžaL”)(y(S“)0²aIÂ’…' J ™ò…&P9@ær„§ fL¦¦M… LáÈ�N(RfP¤Ï(RP¤ÿ‘& Έd"rfs9B“™“òœô(Jr™(P� Ì” J¡œ D”)™”(s'3œˆ¤§‡3ЙL)3ÌʘYœÎPæRe2JJ’På æ™4Ô)8P¤ÎfJåž’™""ÎS’’�IIB˜p§33%8\9žff4e$ÊIC„I?(RaLÃɦÉÌÌ¡IžS…9È“4Ì)Éš Nr!(RyB’xJDPÊ99”9ùe‡=0ÊLå…%™3™ÌÊ™¡œ¡Â!(S&RæaJIáœ(S'0§' 3ÉL”)̧ dó‘ žPæg0‰2PÐÊL°³B�¡’PÉ”šg>i'Bee I…8RP¤È�Nd‘ œáNLæIL(Rg æS% ”�ˆ&JLˆIC¡BPˆJhPäÌÊB”“œ¤ÏŸÐå%%% ¤ÊJaÊB„ó–r$™He$ÉB!†™?"Éʘ~s”3™LçÐ))ú(I¡ Rg(g0‰3Í’ž†s¡È�BÌ4“œáœü¦ffL¤œ¡ÉLšOIô9CÃ2|ˆ%PÎ ”Ã)%2PˆJ ”(p¡C9333š…0ÎhsC� œå Ê,ü.)=!å ¦NRg” &rPÎIfg0Ó'aš…“3æRfe B!3™)˜Pá@²J8PÉ |ôÃ(PáN†PÎJB…&PáÎae%32’~dBag2’|¦s@‰0ù™’˜S33' ” ”&D'0²M ”(P§9Cœˆ¡Ìç3œ)")’!2!ÉÐ(RPô9èd¡Â!†g(Re'ü¦JB!HS)“)’�L”)8XDe0ó ™”)2“þS'”Ÿ)2“”ÉùB“2“úfs9™C93% ™ÉÐÂÃ)2†rP¡L”?)2… æ'ÊL¡Ìå'¡ÊsÊdò˜s†JIL”Ì)™2!†“3) RLò�aILšaIɲR‡&sœæH… LÌÌ”ÉLÌÌ¡œÌÐ)(D39%'¤"‘ œŸ”2S%% 礡I”ÉL”3’™™?(S0РRgŸ”Ì”2P¡)ü¡É”„@Œ€D…„ÊM0”Ã33&“¤¡Ê™'ÊJ”™ç)™’†Éœ(2e„Ê¡ÏÊNP¤Ê)’g%„ÊJœ¡2!“™’†�IÉÈ„ÊY&’t&S$³,¤é†…'% IC% ¦™”8“ÿøÉœ@ÿÿµÆP!9BR‡™“ÎPðå”$ò…'3% ”šdˆp§&†NfaI”ÃÌág2’eB„¡’†O”)™ÌСÊ”¡œ"9’…&i)Ï"(fg?C'ÌÌ™9œü°ˆ@¤ÌÌ¡œ™C8D2p¡Îfs9œÏ$Iœ°ù”…2†s rP<“9))"˜xL¤Ì¡Ì.I¡�‰˜RR†r„ô œôÌÊ’” JH|¤ùgÓ0¤¦e áLÊI4Ÿ”Îç–ÉL,"8r™)’™œ)3I¥ ¦Â!™…“3„@°å$ÊL"ÉB’ŸB„ÒI¡BR‡�‰™“Bae2S’…2O …(M ”š™aNfe…% r“)%$¦)(ú¤)(d”™ó"y2†…'¡’†L¡“˜\žRe'”(p¡fS „¡¤ÌèfP)™(hd¤äC‡¡ÊfRdBe ”ÉòÂ’‡)4(g0ˆd§)<Â!„I<3’…&yB“œÐ¤Ê“ÉèfPç%2R�ÌòÊáBÉ™”ŸÐÂÃý&…&t�0òtÉNL¡Ì¦r‡˜RS aä:Ï¡’… Ìœ3C9C9$C…3$C”„ˆ™Ìó dÍ'L<”)2™œå$¦IB�æfrD)ffg% !JCL9”3% LÄP¦NM0òP¡IœÉfL¡Ìç9C™™C9œÉÃäÌÌ”ÌÌ”) "™™’”š™¦˜g(sò’P¤,Ê™43ŸC'™Îg3™I”™L„LŸ)™:ž, ™I¥œ3C')’s$@¤¡I)(S%2XD$Cœ"B”9œ¡œœÏ9C 9ž~Y¡C˜S… Ð3�§$¹œ)“™™œÎPÎgå2J“)(r„¡C“2e%œ2™†…%™")œ¡ÌÌÉB’g fg2’rS2�áaœårD)3‘„B„ˆPÊ™C”„Cœ2““4ÉLÌÌæyÊÉOÐááC38R†rd¡’…'8D9ÌæS!°"dèr’…&2e%PÊB‡“™2 P¤ÂžS…9ÊNPСə)˜Rf’…&Rr!C”(Rri…2s2RP¡ÌÓRtšaä¡I(p RfP"9Ì‘ ”)(RO% 2D9™ÌÌÌÌ¡L™@ç)œË3”3“™á,(hRC (žJP”¡=ÉäÓ åS3œå æe2hPç (d¡’“"�r!3ÎRg(L¤ô̦B”“ÿ)(ICý’’‡…&|¡C“™ÊÂä/”™C“(s …|ÐÉü°¤äB| (Iò…&r†�)™9™™)?”ÌÎ}“‡3”<<’…!BÉ”3Ây™”9”ÎdI'”™d¡¤¥ Ê9BrPˆ„BO’ F,ý ”ÃÌ9’Ê“2rS3%%%% IB�¥�fP,:R†B%…�JI”3%‡3(g0³3™")’™:JfP"\¡IŸ2’fs9™‡(̙ʔ"IæD) ™>P¤(RrR�¥!BÂ’…$”(JPç¡IBÌÌÌ)9™™™™)(r“Òçô'ü¦aðô%Ô̔32P)3ÏŸ(y…2p¡Ãœ)I<9”9™™™)™Âœ(S3™™™)’˜S&D&D3„I”Ÿ)9I”ÈD˜ÄÇÿøÉ‰@µÆè!339œÊað§ dóÎfaÊ!�s LÐÉB‡ N“L<”)8g?Ò…ÎP¦L¦JP”¡4(JBa&P¦Lä@Í °¦fM çÿ¡Í L¤¡”38Pæ…&RS‡˜g=De É”„I”3…0¦NJJHD)9‡’Y@¤¡™å2P¡áäœÿ)(L¤”“å9ÒzM0å Ì,Ϥ(X&xD™”4 J)9’™’„@ááe'I”” JÉå2|¤¡(p¦NP¤Â!Â’’…P¤ÊM Jfd¤äC'30§!a”Ù”8D8D)(Dœ¡)™†R NÏ)>èr„¡’�L™@ÎL¡Éæs0¦aIB‡“ˆL¤¡™™‡’áB˜hD $ð¡I”Ïœ¡™)™’ P¤ÂŸË 9ÎRg33338S3'333$C'%'IÒP¤ðä@òdC338D4(Y3”% “2D(JJBP²…&fffp³ p¦e J“2Pä@å%(OPÌÌ“ÉJ™)’™Ê̤”™IÊd‘…3 fg3™ÌÊ¡œÌÉL””ÉLɦ“å2t °”ÈDÉ32S&’†„C™ò™9L(D% ™I9„C%'(rPÎe&S'¡BR�ˆs:œ)’Xe&r’e!¦JaL™IL–g9C„C'2S dä¦yùL<…2hfp‰3IÒt(d¥ èÉÌ”'C &RM% s)2™(”<¡Î¤Ÿ 4ÉLÌ¡š<ÉÐÊLˆL¤¤¦g dÊ™“IB“†p¦N‡"8e Ì™B‡3ÿèp‰(æJB�‰“™™’!Â!Iœ¡ÌùLÌå!9ærS%2S9’’†xs¤ô32|¦NPæRz9Êdé;&ɦ¤¡LÌÏ’’�ÌÊdèr†fL¤ÊfS3™ùNÌÌÌÌç¡ÎD’RhP”ò™:Ô93™Â™9™ÊNS$ГBe$¡H_üó9CÌæ’…&)“òœé(Re0§$ D”)ÌÊÉ”332S<ò…d¡É™4ŸèäŸ)“þ’…&RzJ¡C… ‘R…PÌÉ”™Ê(SPˆÉI„”))˜RP¤¥ ä”ÉLæRIILÂ…!O¡= ý&”'˜S$òS”™Ê™(S0¤Â‡ (s,¡Ê2fr’†fs¡Iš™Â!Îd¦M0òP¡ÌФ"!JIpÊNfs<¡aš,"Ê¡“æRe‡(Nd¦fJd§ 3™C%% B‡ =%RP¦g„¡äÌÉ”‘ æOš?ô(JÄ@°ÊM0ËHD  R š™ÏI‘ Ð)HR’˜Rf“C„I…)$¡ÏI¡N¤™I”” Na¡4(9B�ˆž¡43™žyC@¤Í äˆd§Ð¡Ìÿ)“ y'3”(s39™…2s L¡”™IB…!BÎYô2r‡3”3“3%9Ÿ””2zÎ�I’�ˆd¦ˆgÿB’S!IùL9œÌÊ̤”,>�`A“)%8r!)ô2„Ê|ùBÀˆrdˆd¥$å B– J™’™™æyÊ y‡(dÐÉBLæK32P¤ç)”%�èf‡)’™))(RLçÐÉBe&†y™œÌ˜e&)2’’†‡))(sÒzaòî’ÿøÉŽ@ÿÿµÆÈ!å” 0¥ B’�IBÊÐ" XAP¡2˜y…™L””33 Re BœÉL)’”)8PáLÌÌÎdˆað§2P¡’”% Có”3™Îd¤¤¡Í'I¤–P<ÃB†…32‡(PÎå&S3<9 0ærS%0¡IB™…… Ÿ”Ì” NdÐ)�ˆd"LΔ)3Cœ¤ f†r„¡IIBÉœáá‘ 43…2JL¦OC”š2S”ÌÊdæfg8Y’!™…2Pˆg„ÐÉB“‡‡%gþ~ÿ”ÈDÌ)Ì"pÞ Y…È\’Ê… Ð)(“ÃÉ40Јp¤¡IBœ…™™Ã”2�džáe ù¡&„…�òi(Rp¤¡aNH†fNaæg”9…(pˆ…™Ìæyù¡BxPæg2…!9Ìó$C%(‘’‡&p¡I™Êœ4¡”ÉÉ32P°ˆJs3%2i…2hs>RPÏ0¤ÊJžg(y2Â!<ôš2†p¥$B‡2fJfP¤ÌÌ”,)"&fsCB“Ì‘0øP²N„¡Iša)†Re3ÿ¡…˜Sž… Ðô”šd¡Ê’‡˜y(RIr8S39ÎRr…�ä̇É&PÉáË JfPç†�áLš¤"ÃB’œÏ™”&D˜D8e&’†…% H�)I”Ìæ‡ p¦g ‡PæfPÉÔ9IL”ÉIB“)’…&zB„¦OÍ!))(Y2„È„Êfr‡(L‰2’’ Rg ¤È„ó2“’M ”<�2P¡Ì–P,2‡ fPÎsÐÎPÎe™JË…8RP¡Ì¤ˆP§(faÌ,™C˜S… 3™™(s)…(JfRfK0§„„³%)‡Â™2†s<¡ÉÌæJ9”ÌÉL“†pˆR¤ü¦N‡"(r‡‡)˜Y0ˆdÒIfrS3<å&y™…&S32†g�NICŸÈ�¡BPÊaòg2†rPÏP)’”<”)”™LÜÍ…&fPç rap’Èr‡)(hP”å2PÉåLÌÌ"L‘ @‚œ¦L¤Ë J™(™(g&e ˜s%% ÊaðÍ ÏC”ž‡(S33'% J,8RP))ž†sB�f¦ÊL°¦OžP¤”)39CC”„B“9C„C™LžS8P‰ ç(g&PæRJa̤Í™”“™˜S2P°¤³330ˆdæO…8hR9C)&p°") PÎÌÎRe3�2S2“"…&g 3Êp§'(g0ˆLÊ… C$¡C…9C”2Pç)9œÌÌÌÌÊÊaÏ)™ÊHPáNdI„IC)2’’!ÉB’g�LÉœ3’œôÂ’…3' (J3CB‡&ffe$ðÊB……”<3… È�)èdˆ%% ”$ˆdˆR) d¦H�HYœÊaÎP¦aC33…8P°Ë f!Jdˆœ“Ã9ùC8D9ÎdˆL"d”Τ",,"ÎP¤ D™�IC’!BSœ¤¡=™“% ”ÌÎr“œ¤"Lç3ÌüÐÉCš™C””ÌÌÌÌÂÂ’!(S…9™Ìå ”’�IžP¤¥ ðΤ%0”) RSúÐááC”2“(S$¡H|3IB™’™"Í æD’|¤že'ý0øhD!0‰ s™™)(Re39”ÃL§�aBÂÊ’�á¡NÌÌæp¤ÊN™6‡CÿøÉ‡@µÆØ! (e&J2„"d¤¤¡L)�Ð,Ê)�ˆXRR~RNdˆNaÏþ‡9Éœ¤že$¡IÌ”) 2RD JæRO3” dÌè™Cœ²‡™)“IÐÉóç”) PÌÎL¤’˜Rs 0³ JI„C%9O&™)48YCÉB‡'’„HP²fH‡9Ió PÒO@³4(rO”œ¤Â&O P“LùI”(RPô&˜0¦g$¥J…)%2hd Rd¡I”$¤’!2 s‡˜y‡˜xffN†J†hNRP4åŸÓ…933&˜Re!äËɤô9C”9é†hd¡…’~S'9C8D%8DÙ32RRD NL¡”™¦J B$)ÊaN‡4ÉrD) ÉB†… Jœ(s4ÉfáNs̳)HP¡CB‡(sB‡'(På d§(Sd”áfP¤)HS3%3%%P¦frJd¤¡IB’…“9C)3ÿI)BJd¥0¥ ”Ìå ÌùLžPæÉÌÌÊaNLÉþ…&S39""ÎffPùB™™2 s4'BJaIš"(dÒzJœ”¤(fPæP°¡aB“=” ̡̜Ê% NRO2‡Â™™?@§ 9”9é(PСI”<šd¦r…“)(RS3”)3”32rS&’™,ÉCIÓ ¤™Ê¡I”æy”™IÿùC™œå¦K‡ÉIL”ÌÎPСä,¤ y™:)“)˜S&e$ùȆJ|¡aÿúaL“2z8s)&PáÌ¡œ)™’!’™)™™Be'"I432� FáL™Iç"Ì¡œ¡Êd§ $ˆR"LŸ)…ÈS3%™”8\¡IL¦™)…% 8Y(pˆRNIL%RbÏœÎd°¡¡ÿ”” Nd¡C“8e2P�!BÉœ)9CÉù)<2ÎS'ô(g&sÒtš¡áœèRp§'ÊÌç(ry…’S3Ÿ?(Y3”ÉJ“˜y’!žC% ‡<¦f™Ïþ’†„Bg%2Y’™†…%39’!“™)(dùLÌŸ”ÌÎPæ‡4)0ˆp Y� áB!3'3œá¤þ�N™™˜S<� ”ÉК¡äÐå%2„æJfp§ fd¦J@°¡NtÌÊL¤”ÈD™Â™œü¤Ì””)(S“(pˆsú¡”%3"òs(d¡LÉðÒ„ÐÉL”ÌÂ!HSÿþY”ÌÉBP,™ÏÐÍ0°ˆÉB™@³'33 dÈ�Êd¥!BÂ’!(D%&IˆdÊd§0°¡ÊJf™¡ÏB|ˆL¡3%… °¤Ë%9ÎR ÊÌ)™žS'Êp¥$çü¦fLˆLÐ,(pˆrfO 3œ¤Êa̤”É(Rs)8S“9†… OCž“"a”…48S2J"™4Ìå')“”2s3ÌÌ8S” (ÊfffLÊI”˜D8s%&…&S$Bd@¤¡IL”É)(S9š¥$å&RLÎPÎd‰0²ff|Êa™œ"™3(™Éé4<„He˜S2e%2S&’… LΓ¤¡LÂÂ……39IBP, s'ò™%!æa¡’�aLÌÂÂ!ÉÌ””Ìχ fg p¡IÌ)Éže&R~hD(L¡œ))“LÌ,Â!¡šy2k»ÿøÉ€@ÿþµÆh aœœÌÉB�¡HP¡Ê¡™™œôž…9IÏ æg332R†re ”¡É"Hy™ÊOèg?¡œò“(PÐ"LÎfaL™L2Àˆh&rÂ’„ÿþe!¤-”'"9L”ÃÌÌ)‡3¡™Â’„ÊfO”“ÉNäùó9œ§)™™…8S3%2tÃ)“Ì生)‡˜e&39C3%É9”3’Y‡)(hRP¦NaB�¡I(s)œ¡C”(|4ÉI¡)ÿèaf} 礗'IICšaò†hg™ð³3P”(y9™”’…&J˜Y„L2“9fSfe ”(J™ÏIèdèN†r™œ”ÉIB!'%™2†P¡ÉÂ…$¦M’�áBPçL”Ê…0¤¡O'BP"B„C% )�‰2…P¡¡C”�0"J”3ŸB‡3C9”¡<¡Cœ(y™Ê9<šaÏùæs3(g2‡9)Ü)™œé= @¤æe$æD2P¦IC˜hD% JJ2“ ™™(P”"% ”’™)™™Â!™™(RO&’… dòg9C% N9'Ês‘&i’™)’™)(XS0°¡L”"̦Oÿþ†eaL’‡%&He$¦ffJ%&r“ç(s9CÌÎPÎS$@ˆJ,’˜PàA B™’†Oʦdä@¤¡B“"BœÊL*"B™„C<…(S!|¤ÿèPÎLÌ¡œ”2S)“úç)ÔÂy„BP „¡B“ÉL‘„ˆPòS™™"3¡HPСäåš¡�‚™áLžI2„¡aI@°ô2’„Bg ÌÌ(Ráae á™HYBS0Ò„)“IC@) dô™fR�Ì”2R†fdð²�ä’!„²hP²äÌÎe2†Jr“Ê™)% B dáfe%™ÃЙI„C…(sÊœ"œ’äˆP”Â…‡3”9™œ”)2™)™’!Â$"&LÉùL“”’P)(PæffJf¤(D†R¤ž<ÃB†˜y…s„šd³8R„Ê“B‡2…�¨‘Ì”¤žP¤ÊO9À°¡Î†sC”„C… Ê44,,"2“¡I˜„ÊJfså3 J2S39ÂÉ”9œÎg(Rs”,Ï(rs„C’^SŸ”̡ aN!@°ç(O…)33™”8Pð� ç)0¤ä¡I”<”Ìßèr’’…&hRrS&†fg(hr„¡™C)�³$C2“ ̦”&†xe!Ì)’œ"LÿȆJPÎC”””(s4ž’‡"ˆa¦JfM0”2P)Â�IO”ÃOC”)9…3$¤™“32S&!“œ„I„C38Y”"(r’…“9ÎdˆL¤é‡’™"ÊC:B‡&dœÉá<“Ñ…”2PÉC'Ê™1 ”ÌÌ)(Rs332S’!“ÃÌ)2……8S%3(s?)™Í Na¤é4(ry)’Ì<ÉLÎsœ,™™™…&Ðæ…&S0¤¡CI…“9™Â“˜y(RR�ˆX B!(D%(r�Ê% L¡)Î&%Ì“ä‰À‰(R|¤¡0‰2e!Ð"BœÌÌÌšN†só8P§ p°ˆJH„¡aNÉ”æPáœÎPó'þ†p¦OÊJ(PáB“,Îe$üüå$¡IžP¡I…3™”8D32rS$C0êàÿøÉ­@µÆà!™”’S NaLÉ”””2P¤ú愞ffJffR¡“™)’” °“C9¦M% L¤¡Êô8D4(y:”3˜D9)(… dä¡IÌ”ç,"†PÃáèffd”™ÌæÌ̤Â!Â!ÉB“?¡œÊL¤œ¤(D�¤òyI@¤"%2ä,¡Ïò“4r††S <§2”‡C9IB˜s>‡‡&PÍIÓ �L™ÌÌÉC@ˆJaN¡œ<¦OÊI"%†NJJfd¦aœÊdô J„I2„Ð)ÙÌÌÌÌ¡IÌŸ?”Ì"ÉB„ÎI RPÐÏ 2D2S$C%2D&D'2†rs9…9?”ÌŸ)…8PÌÉžg9þ‡(frP‰ áLÌšL‚H�¥&S2„¡”(i’™œÊ™C™å L̤’&INJRBÊáÏC”)2“ÐÌ¡ÉBR�²’…'0§ s“?þe$.Oò™:%<°¤¡= ó@¡"gÊdùNt8D‡¤)Ê8r’�¥%% Ì)œ(S&SR B$2!“™”9‡3LÎd¦B$ÂÊfp¡¡B™)œ¡¡9“9žP§ 38P,¡LÌœÃL”ÌÎPæg(s™ÌÿÐÉC9B…% Jaʇ †™†RIL)“™…8S…3’DÉò™3”% JJáB$2„óúJfp§&r‡% B”’˜S‡å9Ó%$@ЈJPÎ L”šLˆp¡ÊJ™C2e39IB™)™’™4ÃÉLÊÊ2f} ”3(s4ž“èd¡’„ÊO)™™œý æ… �ˆO0òNg”)0ˆP”Ï„Lœ™™™™˜P¤Ï!32Ri(Rs% !Iœ3ž„ÐÉC””)2†Ra&RRD 2S'C 3B’‡"¡9@ˆs(p‚!N¤¡L„@°§”ɔÙ̡œœ¦g†rN�Iå0Í …'(På ó”%™")™œå&s„@°¤þ†Re&…!C”�$ˆd¡Êœ)™™œ¦eæH’aá‘&s™”9ùLœË æffJp¡I™¡œ‘ žP²e2S9@²…33�2På ¡BD9L))’™‡“B‡3B“):)<§†rs"„B™É)“B‡2˜S…9™™)˜RgC”)“œ"(D%&PåÌ™gÒP¤šœ"…&†J(p¤¡2$…Ã90¦(S I¦f!JND H�CœÊaædÐÉC”)“)=0¦Iæe$󔜈J”3(p RgúJÎaL™IBÂ…’R†fJœ)&dÊ9’‡3œ¡ær‡(g Ê™“L<”ÌÉL”‘ ”„BP‰'>�IB‡’|¡¤¡aÿС–IÊS!L�‘„ˆD2R†p¦aI”ÃɦI<”,(sȆJ}’…†Y2’JP2D)2™4)(S' ¡œ=Ì"Í3™Ì‘“™Â D…„Ê“"(d¡œé‡ÉФ2Â…&e Iá9(p‰ “„C˜Y@²e9Iˆdä¦J”3Ÿ9I@#0ÿ‘LÌÌÌÌœ¤ô 3èg(Rf“"aäæs”™C”P,94�fNRP)3(O3ÊÊÊ”2R†JaäÒ„¥% Òzd¦På™ÉL–fs9)™™BdBNz"= ¡Â!'(Pžt(XpˆJ@‚¿ÿøÉ ª@µÆ� g™Âœ(Y%„BP‰% LÊ“(r’…2J™””9C”9Ièg(RP¤áI@³?ä@æNg)'œ)’hd¤þ†g�M!) RPˆ¤äBe'L‘É4𙡙@¤¡Bz¡L9šaLœÌ¡’‡†…2†pé%33„BP°¡I™B’”)™4ž“¦¡C™¤¡aO9C… Nd§™™™”<>dæffJ‡ô3’™™ä¡LÉNaЙ9††M!šäHICɦH†Jd¦fg$B“:ò™“æRg)2“9By)CÉ)’YРD™™IÓ†x !NC…$C9œÏ= IèJ%(r‡(e&P¦Ng9I”ÉÎs–9™œ¡C3d¡Ìú2’…%’…… dæ™IIINáfK33339B’‡2XrÂ…2rd@¡¡Ã””ÉL”š4(S2s s3339’!œÏ(Re ”9ILÌÌ)3ü§:9� =ÉÊœŸ>e$ó)3”œ²„¡C38P°§å8XD $ÊNPС̤¡C9ž… É”Ÿò™?СÌú"s&På ÎáNÉ”) ’t3…”8D2R�fS%32D2S9Ê™I)’„ÊB!C)3’Pæe$¡IOB„æL¦r’!ÉC“9™˜y4Îg30¦L¤¡Î˜y… ”)œÎg3) hÌ4ÃÌ”"C"I”“)&g3”)(RP9™Îá¦H�Ìô3Ô42PœÊaÊ&JIÊœ,"ÌáC…C–çùʆ’fJÊaIœ¤ÊdŸ2’�IÉý ffa†LæH†p‡<ÊI"9B™œ"„Be å IB’…$C'(d¥B!·(sB‡“"(Pæò“9Ìó™ÌÎPæPäÎffM0òS$B“ÏIé= ™C’‡3”’„@å 8yIš33&@Éažç)3”™B“%2t3”9ò˜e%! D9Êg‡' J32†Jd¦Jpˆs')'BdC'2e&$Î)’™˜D8YùÊIò™I<”Ì”ÈD˜S2”ÂY„BP¡äô…9,"…2e ¦¡BS…%3(JfdˆP”"(g&†L¦Id¡f'B�ú%?èfP”“2†…g(g&d¤¡ÊÉäÙ…9œ¤ô dÌÊI¡†” RaCœ§=30ˆd¡LÂÂ’“L>JR¡áÊåB”�³3”)œÂ$Â!œ(fRe339…2e$@¤¤ÂÂ…'% J™¡™Â!HR‡:aNe Lü¡I…3 ¡š” :4 P™@æS8SœˆPæpòP¤ÊJœÉI2RP¤æfxÐЧ'(PÍ ó”8D’†�aI8P¤ÊJÿB~faÍ !BS”Ìå% ')ÀŒ’YÊp¡¦S0¤Ì¤Êfe áùLÎhS9™”&D…)…!Jdÿ)’‡‡@³))“L)ÉLÎt(rfJ%œÌΡ’…%% L¤¡I”ÉÉáNPáær“”9™˜RaáC9”Ì� áI”)†Xf“‘ œ¦fsÿÐòPˆ)¡Cœ(J|ù”8RD%(y<¦dç30ÒP²adšaL%Ã<ŸC'å%Â…†C%))™)"™ÎPæK˜D˜YC˜D8P§B@­ýÿøy CÔ@µÇ(©i*”´¥¥-*ZUd«(´¥-IKDÊJYeDÂÒÊRË*YJ”¨µ¢©KQT¢ÒÉ•)ZXš,µ%,©(¹)QjJZ”©IjRL¨šRÒªT²¥)K(­%rWJV*X©bÊ‹R–T¢ä¢å)R‹JVT¬´¥©J–RÒKQj‹R•µ*KRZÉU%©-EI‹E­*¬©U’T¤˜š-,©Jª\²Ub¥‹KJZ-eKZJÔ––¤©¤‰ªER‹‹I”–´L´ZÊR¥©–Tµ,–RRÔ’Ò•-*²Ò–•YJ‰”¥%“%JK%T©eIeJR¥%–”\´²©,´²Ô¥%©.-,¸²Ô•”´«J\YZ¤ÑeJª¬¥JªURÕ*,¤²•,´¨µ%I2’Ô¥)--IjR’Ô–YQKR#)-U•*©2•Ee¤Ée¥+RZ¨µIJ¢eJK*Y*²ÒU%eJªªª¬¨š,–+,©)J‹TZ¥)e%”¬¨šYRËRT¤´«,¬µ*&I‰”¨¥ÉZ¢eeKRU*É+)JZJ¢Ê–TªÑk*R´²µ)R¢å*ZX¨šQ5"êT²Ê”¤ÉdÑKJYQ4¥R©eJT²¤¥¥-RZÒU(¸­JRL¤©EKK*’­,©ieRZ’Ô¥)R•-%R•*Yqbhµ”´•IZ’Õ)R¥–”¥©)2’–)&II’ɢʕ&QYKR”©U•,¥J«)j*Yh²¥V•¨µ%IeDÊRR¥JªUTµ)QiUJ¬’Ô”¥¤“IjJL¤µ¥¥¥•+)Q2”¨˜ª¢É•Y*¥e)iEÉe¢©JR¥)J‰•**R–’ªUU–\¤©eIJQieÊRÒR”¢Ô\YrTL©JRÔT¥”¨˜´²²Ò¥(™(µ\Z”¥KR©+K-%K%”–”™iIeIIeJÊ¢•)j•V¢–”µJ-J²U”©UK.)T²¥UU”–T\²´µEÄÅ¥R•,ªJÒ¬¥J´«J´¬´±kE,¥%-)UK-*IU)U*LZYUKJ”©R•JT¥)&J–*TT«QK)--QrÊ–R’–R¥,¸¥ÉU,©JZJ©eÅ‹R¤\¢âbÑ2¢eE©E¥*²’Ê•ZYRÒ¬¥”¬«,²T”¥)R‹’Z”R¨¥RZZZ”©e))UeK*Š.J-JK&’”¥¬Z¢¥¥*T\L©KR‹”Z¢eEe%KJ––-QKIU+KTªË*RËK,©JZ’Z’«)*T¥JZKRVJLZQ4YyU¥VYIjRÑe©)j,´¥JR–’–”\”¥)IjKR”¥*R¥)JR”¤µ(µEdÉdÉT¢Õ%ZJ¢–’¥–”µ%©--Dµ%©e*Qr•”¬¥K)JŠ–”¥”––\&T’«*-IR”¥JU*Yh¥¨€q¦beetbox-beets-00724b7/test/rsrc/unparseable.opus0000664000175000017500000002010715253035401021214 0ustar pieterpieterOggSte¿/ä\ OpusHeaddD¬OggSte¿/ó®YOpusTags libopus 1.1&ENCODER=opusenc from opus-tools 0.1.2 DATE=Oct 3, 1995OggS€»te¿/dYoá3ÿ@š™›——‘™–�•™”“––—“—–—–™•˜š›š™—’”˜™™˜–“–š—“”—•˜——•–øøø™�9Ü>ø-ùèE½BSu53œ¬ù€$/bÊ0•Ó”:ê'X*[|äàRˆ‚ûc»} :£$ÖzØúÕì§sD“÷INÀrF›wå¡óß.!^x*iVñº}´üÞð×]ë{�¯àpT� Ì�ŽØ2ÃâÝ*©À`þKùÑkd1¤œ%Ý£¡è\ý“ŸèˆŠË|±‹]­(hÎÒ®�䨒)4¾‰±«ÀFž•[ =Lj„¹nåü{Ì>žor3±@Žlc¬ý7 ìVU«§ÐÔ qx[»Žã�t]{ŹbêС‘1ãDt>í¨çרo�ÖB«¾KÊŸ’qÓAm·Ï]ή¬·1%6ÀÎ ao»¤iâÆ¥e¦¤,]”Ø“ït߉Bs…F¸mFŒyó;&øaß:¶WrÌÛ�ÖÈr‡0–¾ i1U·…ž_-@X)/C’®Î�{.j݈Û*�ç§‘>‰LÖ`/±Þ!8®ù‡=­—}‰ÅµމćøD®ø#òÂVmR Z�›Øà;ÁÄ ¥ì{ŽT>¸vSBû ›¼<û‡­c‹Î>˜+ëðá�h¸}«¶´LU$#r¹!Q¦\øaÕ™ãÓ�Øe¦¨X,ÞR.bn²o<“Nïðî\«ãq ˜Jª–ûš˜|®£2ˆÔÝp¼QûahG —L”oEÏ5€qžŽ¸¬')„Ó½¹Å½”Q<5¸"ªöŽ‚t”nÁ;5úç8óü˃fû 3â)ò½‘…´±Ã\³))…òª¹Aà’⪫þi>|5|/9ÇÞBf³Ï1Ž-7/5,ã…øaÕ¬wè¨�¿ñÔžüJàrU•íÒÏ’=¯7eŽÜ#þ$z�Ôž ï¦Ò…7 ¥´^6r•âÊoUâ�ZË ›®X*ÖØêe4^è>òG®íÛßä^à|¨é1¡MìÙu'r]oˆ1H¯Àrü%¸­´ 0æ,3Veªª—xD®?·1­K+,Iq� 3YÏw,k¿r ˜�e�LøaÕ±›Ààv��âÄB Ýœ[Õûüaõ†Pcž»,DY°¡©µKuæ?‡öÛ^kùéÿÏý0<�õòFWÒã¤~•ãºx›vø†¦Ä#޽ìq䞦×Ê´Á þvÞÅ þù§Gúî+bGÙ©VeöàI�T`ìÜ)‡õäL¦ðø3ÕͼÁɯ3¦Ë÷ÈjŒøaÕÔ�Ásc0fx�‹ë{Šžâ##½òYÿéƒ i„[•~€ é¤×Pz À¿ò6 _ýÊþ4 øaÒ�Ú§ÁçÌXZ1§gºW·b°úÌÚ³‚]­�*ˆß~ÒSä„$“툈œ�fÏÑ+ˆ3ju[#v›òÝ$XHe\n§§Áj£’»*ß5zŸº™c—� ¥[Éêo®„eës¿‘ágɇžÂÝȘ¶¹ ÷ù€²| ¾›|–å»-¨O# b±k0úó¤þ)BøaÕ­]xúë|°òd¡Û�‘Ñ‹,–0ä]ZÕšIë­"”1"¬0j�;Zj#ÛR�-—£§¿7Ê·ãYC½â¶º+Í/8ïùêíÛ/õàæþmíOžùGÏZòå^Zfe ¢5,k¸tÍ…—`\€@ÌòãŒQûgºJìfËž™o=âp,ª° F�“H¼NVŽ”ùL<ÃøaÕ°¿ë+…'µ²cÇìùcI]¿}(ñ»ª�q6#�ghóJðwÖMQj¡q)H6$HæzyXW«8‰9vý¢¸]_YóoDóõ§þm6PÞæ<}WÎ\Oµð%îh‡:㨃.�¨�Ü"®6Ñs ÑKeG»îvd@9ˆ‚Ӹ󟕞ÕÝ/­øJ|2ÿT=�/øaÕ¬Öé÷‡†8ƒ©z #<öœCݸEÈéˆ|Ñ&ökÈÏ�áT{SXîwÕ¡•´a³äõTÚ-ÚEy S/ó^:9‚@ÜùÑ¥ãM Ù©±ÓÙ•¬°EBFÒ—<°ôx>–2°Ÿ�|ó'í¥v„ýWg*uaôR–76AøaÞíÛ¬!ÂÀ�‹˜­³ô¿³7­*Šs 0of £´ÄH!Þvæwꑊþp•ÆyE#U Lƒô%í.µG.#ž� µIŽ4I(j g^ލþ˜f"~÷Ãoæ +µsW(š—4<ñ~íÞå4ÑfÄviÆ:ƒ§¶LΕZΞ'üÔpÆå.�œL1Ý-54UNü] ÎøaÞÌÐ[J2ÉŽ]ïF·ñ@Ü1r\¨ýÓe(lþ¨<¸i t[æ¹Øëÿölg5ÁiF`éq­IÁíÌyP±71àa-Ýï>B\6™&vÎUõ;ú HŽgÒm‹Zrç#±XFÄûí (qËñ\ÿdøaÒf/1@÷qŽ#'•zíûú.ˆB޲%C€‰yG¬òK¯öRfQk*¥ÿ1ͬõsËb°6ûOÃ8á) TP¨pNøeï0!óÆ1îØ™½‚îÙ§Léd˜ÐNâ,Š<19d«Ð"ÅÑlïÔÜó•&aÇËêo1»±ª vJd ÊÁ¢êž|o,/b¼ bl%\;Ï“vÆøaÕÙ)[" áX‡GImìpßÙ?…!ÞÑûðÉBç¡û2<·Pù�•Ï?¨$9îNß[œþø°ß¶¹¤êmÐñs¾ <=ƒýú š²=U‰—o»‚zƾä�ƒe äž[¿¨dÉ‚ÝXšŽp †f á Wð [^fSãú®LxÙ?�AâÑ÷6ù,ë`ÕÄ¥{l?@ù#føaß(ùí÷÷cï�Ÿv°TÕf^ªì“Y.ÙXÃFåÛ‘o«ÚÍn�„Y)o-ü¿Tÿ¤ˆ6AÎ&c@ŽôϘ*@ñ+D¡-úD}N�  ¤<–…)˜þϤ¿z²ÛÍî–±‘ˆ�³hp�—¢½.¬7’¹Aš7S‰<Ÿq=·=zÒÿaSsZÁ,…:ï’Ð[Q ¬‘â ëøaß&¾³ñ4DP{uömÄ€N—ùÜéÀÆ}œzIX¼¬¼i«ô‡s ¢&éÛqØeX¯˜ >!B¬Qˆ—A‹1ú”GäaÉs¦(a?ÚþUº_Ì 8d~ƒ?û¡dZÝ5Ðæ?Ó@mâo�pÔ�DnB`t·Úž;ú yûÎéaŒ?2X"¥§õ™M;�lȰ,Æ™kåíøaÕÔ�Òì”ÁÁ›08n"Oj ÅEõ¶'ؘ¶z�=ŽÁr®¯ÝzÆ.HtÒ0Âu/÷}ëŽ<{ÒMú ðioò�†é@€“S«öèx8‚+÷À¡�uÃ𾊚NJ1õ'¨Jäîb; `Û´<—G$&Ë5¡,þ*ñíë¯3óÿûÖ„ìÖ³3Ëç"ᛟv×ÔÇ\ øaÕ¬�ï±Pžªº*›oqÞ6Q [3!¾ÿF@)P{°²áû€Ï‘gÇtþ™ÒsY…rɈ(/?B„ y rÞxËm_ôÞÁè«`–/ïãšZQ?´ e ƒú?Fggýòèê�æAxß-G&ݦcIkÈ�çNá7;�”&)àFj0'6óP´Ô;*øaÕ›Y@´«Š•æ ž ã†c �t¦¥¬/Ó/ÊVàfLª•ÅqkˆIÓy‚êBð�+Ð?¨„z§¸C¿®έ(Ú¿äýÅ»S¢¸‰$Ájz{åAà€ŽÒÒmÏw?Ì_v÷;üùA©ÚÜwÃ�’ï'CMºÌt…u ðÇæ·áœAÁm‰tåûJw®¤%`­øaÕ«G¥ÄáA0à^.a�¶E*èŒ)@çïþ”ÃX�˜bù3ËXrDð–)–-6«B\!ž¸Ø¤‘‹Ï1BÝ¡€q¯Rmj>݃0’M„‹âí…{6‚QSñVչè ªëm¤§,ÞúÛLõï±Ã[Âþ ¡‘8}•¦¹¹î€Ž *·wh�8;)ƒßÛœf ÝN¡xÓ†2JûøaÕ¬žØé”W"ט“¹0"J­®>òX‹iäã‰U&A3J¶Ÿ?7£ ¸S4âv"£9Ù›úŽª×âñáNn=Í™pÛóÖ;pU�| cpŽZå !+ï“‘¦¹šx,V%Þ.:¿ÆÅÈ L,àz1àç·ÌٻѰïÈaOS˜Â«ÆÆ�Cîì¦È¬r4¼àm„ؼøaÕ›b`®éðàÝ÷'³#p' H{™¸Æ^ÙïÃÛq±ßw2z¹ýþø\ÑzÇ&ꓺB"LªkÊó*8ËM1P’çņ›h<Éî»àðA‹hMM<‘ŠMû†ªÃUÄ•¶=¸a-y#¯h×£SÓ š³Sç˜<üªï4xþ�Ù´“ˆËXP '"¥ðÖjÚ�›ãVÅUóŽR–˜”ÿµžøaÓ,{Qwšs¶µq²þcšAºÔ!<ÀE{mݤëý0•OêÐ_QAY§ß' �oìÔ˜DßJDvêÍÈÚ„÷ð7mÐ`fŸÍî'ÑúàB‰Aç¥R:ƒN°e>ˆ7�Õ!Ö÷-�èŸ�àM™Œ˜c†Z1ÅÏ÷Ñ?TØf¢DPèJ3 f›‡áEx *—œÝ|͵¥ª©.R¿áøaÞÌ0�§Ü \}$—ë-§d’‡Ž«ÙÝ€õWù‡CTNI´Ò3Œº³\޽ø2pg&¢WvÔ-¨Å4Ù‰í÷2ãe?òŠå­MG®×vn‹ê˜™�u›œHÿ¦á¢¿i0¥%Çnj¶‹£–®ñŸrü6àU‡& Z¬�’QCRÌ£Õh ˆL=µZàøuˆÀã=Tܽ±pŒ¼4óèøaÕ›öÿª­•–Ò±3,öD©¨:¬Â€]\ÓËü²6ßk Ê‹?GoÁ»ïCiôÄõh’‹› Õ³k «£–ë™-´¸CSÄ�¹¡O�ìç‹·¬Äµ´(@ •±„6O×¾l6K.òÐíŒK�AÏ|ˆÚ˜¿Q[gïpöUа�u³ªÅy ¦±8eïí2½ò ÷½´øaÖt\ntþÒQ•ʺÇU Ã�`Ž#î,mÂ+ic¶ôÚGà>úAã é#…Ý€F÷òõœ:lžÇâç٤͵‘O3UCÁ[z÷ÒÝY§.Bß# 1oå å»>áǯ£1>e²…ƒ{x=G Â*b�¿ºÕT×ͧÓ|½|¦%ê?Ô3Ǭ6Eiç/“ïªbTá›ËAh˜wТ/dÜøaÞòûèr^|ùxh¶´%�ãà'•ØGJC» _Ö6¡ÚK5(¥”]Øn¡§Û-OrŠd �7�Mµ•vr¼UüŽMܸ!5„M;ƒÓÅ�wøV�Y‘7±û½äÜ.öÎ�)’´Öúxz‡“zQœþ:ÀßàÙò´„ºâæ(:áúºƒjŠƒÉ%×# Ñwœ3”n44·.}A-hìøaÞì�g×îÜgµR=Øþ¼g£Ï¾š9d� t©´/-ØVx*Þ¡�+ã{ŽíûÛ÷l›(R2›öMĬéÔOê@Æe³‹î¤Ù ƹ’øcÿ<É.e#èäOP8ÈáJÅò=Ø­¾J€µÝñøßU8¿ [^îl»¬9¦îíDK¾\ËÁD#‡øaÖtq0Ô‡†gåàƒœúÌKØd¹Ì.Èïý›^ŸàýR6H Å"*ªÞ!�Í—ŠãªvO¯îQçN™YßÇ@„ãÚÂqå ßXÒ(ï�ÔøD®b& üz>Ú¦[™S;9•L‹tNöÔ•‡ƒ'#�e¥HÛ†]“öœ\eL°.ùþÚò@hÿT�¶Ù›DGAŸèOeÝ[­Bƒá$:ØnË^áì$$?§Oâ›ÝÚ&*èôÑYìøaÖqê¨*ûñ:¾Ýôý�R¹†ê¨Ø&ý)ÿ0)ó1L¤ï¹ºúe -Ü`Ýœ›ý«¾v"ZÄn,9t£ü¯Hp°²ÖC Žá%¸ß¨/F¨öÄKŠ+ι½2}ï(,#B¬çŒú×i4Øû]ÅxçY¿²Ó ±Ë½—lQ-éBÒ aÖe8‚9ÞxMÝýY²à.b½LC\@euøaÓYÀ®vÃÛ¤tì|¦ åÞïar·°×M ž{Àq†$¨2¯ÒC4T’]ºOµàøw†¼ mÎÏL—D3ƒWöØÙS¦@9uãݶV®l5a—PãÕG™ aEH˜^¯"kòpHnºñw×°÷©™5GæÇF®e…¹eÄÔÕôÄ�XaÕŸ  L¶[‘q„­øaÕªºh�8Óü:¡ÄQ}6‘(aæf4¬\Á;Š_Y¼­´ðþOT±Hÿ•,îÐ\mÚœ+WW�]ÙpW=Ù.‡¥Óí¶°ä6¿K§ŠÊ»5~ùª8œd”ô7O�,Ëú],Í3�zrš¹OSóžPÔÁŸyiÚCÁ¢W�ÝÅ�[#m~a!X[×UÁ‰zò0øaÕ¬É&ö®NEoJ5�ã_¬ä.‚m{(%™Ëû, ,YÄàóª�EôŒ3÷Iõ3M(ßpLØr&}t®ô¿çNë5R³›ÅÀÓ‘ýÆåŒ`f .IŸs®ý6°©öt±¼º €ívé'3‹¬)²Ï%N³°z›páRo\› ´ç�žvò÷íÏêÉlÌ/Œ7 CøaÖt Zx’Q‡D‚W9I¦sÅ-÷Å0ïèiirŸØ^:jûÎ?ÅPT-ô7ÕN pÿ�›�XYÉs€ªÚúÔuo—¿OAŠa"ÉB--g©ð¸Íšnܪ‘*œ�äƒ8Ó–ÔÑjRtL-/jyÜWŽQÆ• u‚~….þÌ!`h¼>BÐ<�éàð)#,~³)øaÓLuÛ*Du=fÍQÍpåùay�±�GB鯸B¯¨Eéùr/£ (£­%è<™ûÜØƒ“Ü´²‚ŤáΙ<´üçP ºg· ïïHaob–iªU/ÁÁ,§ËÖþ c&狈 ¸¥êz¦â•÷ûZКÜTÚé¥o‰øßöŸêœA˜õÝyQå*+öVýó&ªÑÂøaÕªÐÌLÙíÄLÌ¥lëNoŒg"ü©é\=ZJñòŠ Ïô¹Ô¦ ßiÍ+vÜb/:túÙš ~^kçY¨D/5ÍlT·½è$k}Õq¼¿1—²n”³’òÅ QÛ_঺Û*�"µúNoÆ�ƒÇcjNÁºg4fDÆß7Ñ»­Êt“ç×bH¢Ïüt0Ž ŠTSøaÕ¬�uPú�Ää.ÞÐ#m‡¶ìØ;†åžy,J•�"ĉ)ìá¶ipݹ8ݧ"®ý1…¨Wü€QcC�S_t7Éø°ý÷‚./¹?]Èž÷ɰ«%¯� /±¶n†…9�Hã% ¼ç‡Y—99u63[Ó¸‚üˆ\hø‹'Ž—ÇMfžt½Q›ÙÁXMsR½ÑA/ÏøaÕªÙ¼ãZ Ö†ÿI!vŠu›dH®ÅÇ<½ ‘Ÿ{o¨ Ä<@å<@ìj†C%¨TáäDs[kâ­oÃñÝÏàt³ÿ÷ìÖpªÁ~“?lÎ1Ne$Ä}úE‚Âth9üÿ•ÕEÖt@VNU}qŽ&._+#ò°sÿZ´Èé‘>Zäûky°¾FwÝŸ–…ˆŽ`…OêZøaÕ°jß ½Ee m›þ¤¿ò0Ú^;£(87ù—Æ ×µ”k¢ühP(N©ò–@_#äÔœÀœmû§¬–(¬?T‹eá“ÁË2¯l Ð’¤n"-–lÏðŸYXì˜_ü›Ž¬¼-o^�|4 BÏê�ˆL“W=Tz +H�„å.E­^fk¯3°+©ÙÎÿäÜG½ù§W3r˜ÚKn>œÒÚ+{ç²òô·Š¬´ &…ñ6u¿_zêmeS)K+2òkò± éØ8ôÝ‘c¼3L®ÝÚí�Žªv²WܸÚßèÑ‘�¶Yຓ@§1"kâr}õqIÆþu ¸ ¡©[#ØÈôð¦‘w“f•—C?s·”b Œ[XAÅÊ Ã=‰‹\ ú„yäü�vJe¹•ÙׂfÁ$0²¤y£ž}:ŽÎ Ø­ô[èr‰zØ>Q†Áx �„“(® ~ 9Å5QþK�¸ÓÓÈÓ&)±¶‘9jÜa¥«`¾ê‹A8¤Ì×– ”©¿ƒÕ"“à†;bR3¸ “D©�W væÇ)ãϳS›Î£Ž�ÚÊ̲A}ÏÐꂇTÖ‹¾DcXHwüWE>Èà‘'•:Ð�•ÈœÄqqoie4>#�÷ -&}ì#}F�í5pÅã�±ã³*"•(taà¡ÂàÅ“"Ñ)®BÜ -·,AEexj¥ŸòÚ†›ûu®R�H×n_¶n¶(ö¶Îâg'v9HÃ^%Ü!?¾"XÎ@µÛÚ6×›R÷…­‰¯ÌÎyÔÆá=ÀÏ‚ö¯–8/Ö3VõMæÂ»8¿±ÿu!ð™rP@ÄÔ¯ ›“øqSzá~åjwñ¤xTèv¨TÚ.'ÿî†>ÐäÒš?Î`XºùÊT÷:™—ýÌ Aã?”1²\@ðd±Fâ|ɶÆD½‹°6õ Xõœ“4„,ˆðÁMÝR¿#÷°Œ¥&ìeõ¾­E„›ŸväÊýS²š+vWÈãsJÿËžýxñ¢Ìœã{ö[·>¦pQ… tÿ³òŽ)®Ì ¤Ç`ãmnX±^xõÚ-Ç®“©=®æ�´|�t¢Àr…βþ‰¹!ɰvÈ ^T¿ ßN‘k1½9¥#œÞiÔ[@ÝöSÉ‘’è&ÀÏvš¶¦_Ö.¯oþUœ�æ÷ÙÕt÷xLÚ½êø‰H/ ‚Ïm…Òfè¿ÃÉ‹.y Æ8Ô÷KüQE¶p:•7'§Nn¾„ì 8lh˯îo=›}¯¾•9P}Ví{sÔèÿŽ�ïnsÀXiVÓ”íEI€íH=ÒƒõsºK—Î{ÍÁ»ØÒcyO€g›¡P˜û‘–õ‰¿ÉÅþµ\3yy8#;çtº2‡ÿê[mš ©í‡ÿ‰y0˜ÚäQv{DŸ×®ú3@ä ã­h½lXÂqKž!®!õÐÖ¹ú§çÚ‡ŸîÀø–�%5Pú]×|¹õ´††#i2‰öíÍý Eäùì›êLÿî­ 7X¥¢)E»[Ýá[Z$ѾƺÅ–½¿îKšW¤¥ÒÜíešY#ñÙ,‰í�Þ„ì.eÀÒ<Š[èÍ؆,�I#ŒôÒ·5´BÚ ¢6Ìå)¥ÙùMP™12]ž Bäã'‘i"’-,¹XQ3Á™€Ø_@øå©ÆY5ÎŒDd�m P Uëe*zï =ý…,òc‡-¿gCó½6a‘¢1ucô°,a$õÖ×zܤ æV‚òÀRå “”$}ôÇÅ~ï¸9EZç1°H.1.–j¸¢î¿Ÿ{—N]aL·.7 ¦¯€DQ‰l¨°Ùñ‘±89Ågg˜­vDm˜ê^żäžïðDUV‰.’‹ „OX“EV½ñúůſ>qáz¯™Q}(¯#¸MoNªþ‚,–-ç~bûc–97þƒÛ W_ýÚ 'sžNYO j]feÈu´Ê6ó݃3¬¥Nâ‘+1g¸`äjÄ;Vn6ý²pf_OBdkàžpìuÕqž\HM…k�ûÇbµY2}¶PÏe'¼ÒqCG¡[J�ì7‰P~Oëê ’k¬™‘Õ3“/—A ]%†°h@ ozWÇlýÒ0—u¹rî[ÿ˜KŸ}–ún²gþÌ@)E¢ …/ï׿•A ãì�š¦›ŸÝéFz ‹ìӓ͸B‰@[Ë %Û×á!Ê~nÂ8o¦®H#7±=ªðG Ÿö¿qÍÐóв`Kaÿ„íHÃPXÙóú{ Œ¯Þz“ð|\+Èç|+Nn{W´*ã›Òý2†usá1\$«J÷‰µ®E3Õÿ°Û (ÓÁò‰¥Ql µÓâû¦ˆ\õ€V 6°ì¶†RÐ-]ú–SÑM¬´«}.ÒZ+í)BÏw{”û]ò�×¼BôŽ £[Ú~š–’‹©–uÖêk‹§*ë[“Réù½¼ÈƒKñ^ÿWñ.ý�yx^èS¥`¹ÇXñ T�9 Á‰}­ ,f%cò¶z¤Cdð°‰/oûXfÍÁgî/òŽæÖLb ãz¹IÑ9z,çik߸m2ÃHßè:ÚÈ™U3±6ê›ÐÔVà-­!S)­Tµþòt —Ãߊq‚üãÎ4zM’î=03mcí(f4E×Ù9¨˜Ji�#çØ$Ö€²‡.¼¶½î—f¹OÛša—¿ÇFaöæoËFV¹68qc•ò:u[P¯_«eÒžfàëf›ÛÖ»�$;R¾íŸÄ=§Œ‘!M�Æ—íS±(ÙbéLI�çoWÙ>òŸ“î铳ÒÓ¶—S{Iî=C.…ŠÛÍ'ÃÎ?^“Hut†q§¹›Yn—¦´ˆ®1o2²�òz.½ :L�?ÑÁmt‘¦×x) Lìå\èíöó¬�©K•a¿´¬p\!)ó §÷¯P#û…?#™ðÆÎêX58æ»ù޵¸*l¦&#àp(müL‡3–B±AóéV$®ò÷\Ö^›G�4–Øï”y³Þ°"Q’©s¬¯aò—R%VªwPRõ±ûo�ÆuÒÍ‘?ºËèðÔø| ÑjÅÆ ˆßFZ© Uíçíw¦³ÊåÝLeòt—Þ¡£±ß\®]�nfÈ yø*e6úŒ.ü¦”P��èZ Öâ‚ º!ýi…ï«{ï¤Ý†S¶hÚëêØgeyäÎy&úñ —Ê6#ˆýF(;`;S÷íþX·à‡«¶~Nþ>^„Æjß½#䬭VÏ%Þ†„Ød8tLí¥ƒÚF:änœ_ îõÈxrr«åô± „àŽV¡ÿ—;œ!ÑÆüHÙ¥©½IÄA�º_\d™êÞYšštˆI˾§ãzÒ!¦%,¼"{–( –ƒÆiðÅůÓïI«»ö�e²¢mnøq¥ŒÉ…w³ËX!qõüm­~"œ.Ã5Ì08¡8’ëA&›k÷y»pÌÝg¸þä¡!O úÆ5Ò/#Fv²Ñ¾»AßaI$¶öùIM$éV]ÆŽÎtõº˜ ¹ˆ\€�^ö*­B§X/e�`{Æh ÎLóê¥5ÎV4híE@òEÁhŒ�2²H1C|ggÍʳÏß® :O­ —B¿ ¸9’Œ0²ïXwTl}Š$4¨é�]¸ô‘“l“ÎôFÝÞ¬½0ÆeSbŽ+¿’í‰<ÑL¸J‘õ^‹!h�òï¡SiûA �fa‚B$?é×ZAt¸# – =š ü¿ÎGú—çTûÔûõU¾‘‘+FèX §L7ÿ»-áãx»µ¿˜Nƒ`¯Á�„6$cöÓ ÁÂBÚõ:—þN’mkCØ=ŽãF/}8âÖã^ÚDðAs¹´®#x_™•C«KT]˜ÖƲÔ¾½møa×á}üo† Vú´âä‚€ +Z*³N÷·G�°.™ IÊ›êáS \†Ä?ΤRý}-Jzã¡ÖbÍ­wêµØµ„ �…È�™_’ä7¥Æó¥sRáÁÅtÍ­n—’ëT;×ñŒl CŽS÷Q’ë¥Õ>T¡ã‹#A陡¯:^¯hõQ”ŠåÚÆÐÌU fB\ÿœm˜\ÕMrYó^ù`—A‡ô–œEëQˆïZ‹’�ÿ̪™¾Ð8#”Ú:V:ÞgJo’C‚ß0~×}”ætž4$¥ºóÔò°Ái“@b8epÚµÁµíÆE+˜b÷y–ßb´è³ò„«.ÓÐî˜v0ù›™H9û('�%™ÎqÓÁ‰‡N«)†{œ‰b²§?›,-nþ x½k Î?UT…áʰ4vl”¥P{%ªÝ‹vÄuݦBnðC¿jI÷4CLJ§�ì³Xk?fC¯åjpõß¿h×q”«ì�50RHU*‡ÒØÌ-m‹:Á|ã5´;Q•›µß&¼ùì¶PérçÕnŽŒ�L‘Uçò×5ƒ÷©yéšI,OY¡*„áùŽ“)XLÐN5 8ð‡L¨Vá6«³W 9Q R#+ކ K¢ìýäXÜg.náá2Šá»í2KÒØ—ïTõÂÞËÇÝ„¥F0XC‡,S_ç-ÏÔ,ÞÇñäÄÜà–¸‚ ö3"¤m²wr•‰kBÇR‰žÎrêK¦Éå.yú°V:±Ü;â *� 0èk½—V¼!¾“ŽBçýê ÔŠ¬±ˆì¿´Šú祽ò´D…¶ïbhtÄ·+ǵ!dƯ¢t'UNa¤…‘øÃÈÆ³RV»3J†™¢ñqôòï(Öô�<xm%cw†8Òž gVlz/˜ZÀφ“é{ꇕõGï@îv�•“pذU×ML-wmÕ<õ[ü ‰ŽêiAå8\0"k87Êž??—…� Zî"¶B'ì�ry/ Œ¬G’ñ)Ê•Hœj¾d/¦EÞLÑÆÿ4×8éG©Vä^LÁÊr1ÿ›¤äP =£¿g�Œ˜(F݇VÅÙY´ü4Åd•SÐL×ZÄÈÿ@,Ú†qñ­Û÷sUwOéB©Ø�‹ðáiñŽ$B¿ü(Ü»/ÞœSÀÑùdñëŽ3{Y¨¸¶ÛAò¥ ÙS'¦êçX*=eB3;näŒ1 îr§ír™‚ÊGÛ¶šãÍ®TóÄÍ <¼Ìžá—‰šy³sWûCáÜ=ªÝÃIjÐyg!=°Š¤�m¯\2£ö}bD!bë¯}ÂWœš�¢åÐÓÝ=XØj´:×…*hýøA81 #$ÄcØWfš'çF]iJo·âY…ÿ�d çmdÃß B~!=9- •ÔµþÞ yMMfª¿l�p‹ÙÞuÁßá°æ•¹6¹•]«Ùøk²¨6´%{둞: µ·Å³ë₍ï�û`眺!T̺p=�ygxæ(q–˜®ÈZn¼@Š�E¾ûö½aœe¯c6ho†Uè�Å[óuø"Ðï¤}†aÌä�“ÐÉ>:óˆŽ)ß»^]Q¬˜#õy«‰Câ«9åÜÅÎÞÑÅ…ÿG¹DZjœ³í&⥎Aà=ä²½um©q>©jJF¨’!ÙÍÀZ »{Ê^Š©óf!— o:Kç\tÚJ8™X@ —úÎj Ü4«º;07:MóÑ!©çñ3Vï‚€dܱ MÝppËTýµ]÷?l��órˆÔÔV/b „Ö†68¨º.'“[±$ƒ<בiﮂ¶æŽˆ¿4 Í®§ðú€1Ü�ñ.†úôÂ~pç”d>?ØÕ¾æw‰8­±P¹Lçbð\8Q·Ì²mï�f\ ƒe+‰õ½Í® ù?Êìªd)dœ“ÉóŽ�¥µ„�…®W™®´ÑIr$YB8v�@Ø 06�Šf%¸.ý·�Ê+1_Ê£€Ìî^Ѥà <•ºîp[GépÏŒwÌ ‚ìÙ´EâÔq6ÛªƒñË´×›ý�_ƒ-/¼‰kç qNúãKŽñLDu÷ïá’ c_DM!ÌâçwsV·¨¹ -ðUÓ÷ãØŸA¯�Š´¼q®g@Ukwíìp~SE9½tݲduÍ�tÿ}*Á&ïYe�zÂîÛSÙñEóÝâ=|çÁ Ʀ ;ïÐ<_�oâLÜ�òÔ|’'Y÷ûÈá=‡2¶y¢nï²Ì}VœúRìtOæ¼ þ•A0gÎ:KÉ{‡ìµÂ]è­I‰}/àÀjóÒ�ah•_t ®I$5‘uÌ&.µÒq¤2ÍÎ^¿w…dMMOè1-)zàuñÃX<Û]ÖIâ ŽÈ" Ý,ˆ/g® €ã|õ¯˜>éŸu¦¶ËÀ9ÃVÿ�ûžÉÒ/ò5k€ì-!“[Äø&þñŒ FÖ Ö{ëñq±ØõwhŽ¥ æéyõ3²]—æäéˆÛÛP\5NDùìÙžožcAÈSéâVm>[þâ}kE:Ž"üºÍTÆ ?WŸ î'aï3QíjŠuØxgÇúnrj–èMQyµäçŸÏ�høV´W†–&ÞÿÛEÙ)ó–È«<ªýLÓmÿѵJEöíÄDâ|ødæCj¹žßA§+äˆ׉Ôwˆ,Ý rcÆýMÜ­«M“Ïפ�kFKg˜ÓÇ ü¡ÇZcxé ìÊ)lQYŽ*Ru¹tO’2¢¼^½òµW@ýäÞ‚½ƒÄÐ`þÜÂT�¯šÜ† fCpK:©Þl)Ü9Øc––Mž¸¦ß®&)n,•ì‹Nñ%ù»ß4�ç{Ä?3�Ð^@>èÈJ„.òE|ƒ 0¡×\�ì§=e÷7üØsÉZ$ 5Þ«w? \."<$Ó)´�ßpäRwèƒÌß6Î;nì\+@°ÃiÍõ”ë–Rxã7Öî.V€~傦Bmk4ñ@áé‚%?-f$1¿²ÍFbñçšã•²ßPïeCS r:ýJ(üqÀf‹µ9âç˜äˆ¶L iáØÕÁNS(†î)»%w–yûyðS(Ô$("­�¤-­£H2Á‹²f>šËÙVïà$xbƒ‹žsÆhÃ%uÎIíòm+'ðNÝç�d럈?¿põË—8}ÖÖÊàpÝb�è�î§‘™ßè¬�à̈ŠPÄ«¯(KL.Íg ¼kH¼a+Œxé‚3ü1˜›+éOéçÌ…ar±7& ëÁvõdVóùOÉËê6!ï3ÞB4ÿø,F|sÄ·¡ž¦ë¿õw@*B`Ð_]æq>ù/ �èÃñ�½ø�×Ô"êÎÇNiK&”…=.ÿh¾À-JÓìæÎ;RvÓõ¨„À;YD¯ŸðÂpâšôT>JmÑØ„§3a¿ÕS ¬J+`Õ=*ãŒ1o05ÖY¼ò1¨k¯2eîÉÒÚÃ:ÅŽò5IrÝ �å¬WÚ1Ë1(£ X=~É`ä5ø;B,ƒd—´5ŠB KZOù>üS.�TÝ Š é%*¸ŒźþíoOú4yJ˜Ô8"B‘¶`G YSôâ#Ÿ‰ U¨I• 1ú÷nùäîy)~Nj7��÷•ZÜg¹\|¢¢EÐ «ÿ«0‚ŽínSîÅ�À¼“UúP Rf=²ÎÒòUE¹!¿_’šïÛ?~ åŽ+æΰÔ[£!W;þ#�„µ‘ú%‚tqšeŠ*ÚÅö»˜ÊŽLð û‹òY9WTd Ê+¿vsÓ~Vò!@œº’š�Ý ;éWÉïl�ÑÚUéf€æ6€ÒG¾�´y ²ü–¥%rŽŠLb@çå-���,ßÚy Á¥Ý MxR ä¼�o^‹ÉüdçN¬Ÿôf¤ÏóÄåmà% Û1÷[òKÇ;‹.žúBºÅ,ý�¢á:þ£þ^§ÁÌ&µ> ê/!†3|Ö«SÞ—yTßF?øË0E22¢>¤jQu?ìžx€©’ûî~$[Ó«™8ô¯ù{Üw!?I‰’a ×)!ö@à°½È@¶ jTz\žù+þU¼•øÐêêÆüß¼–T½Œ‘£ºBŒ+.ú€Ý%Û'±Zú oMO™œ8b(ºÔßg.ÙØE·�ácGZÒËêŸB—æ¾Wx‚»5õÔ0¤'œç##9]!@&˜Ìó�Ý¢FýL†FŠÐ*ß•Âa¤6˜ï`­£ 1\j¶Œ©ûܦ#ÂôÊÁ«ÌÀ5~µZ œ¬;s–í¹ØŸ¯o9­5 :!Ï$½—¡`môŽJºÒ¨ÑC+œþH;q !LO‚ñ�ªá’b�5­O~ 6D„o§õÉòÑkCZå¹@ȶD›©t†xÅø Ûõ˜¿4‡ï¬Ž<œŒU§9ë—žægù²Ÿ•ë–zÛ"rU¯ BœŒ‡,¿|¼?;Éùñî¾²ñ0sê�@aŠ€Ë³�éYòó:‰’@5¦1ñq±0ÆYDãc:âPoBê.Õ­²WZ²ÍDL÷·ÞÜ ÅìZ­°ezž> \_¼7tm–îÓë9&¢DütÉð—Ü•hI >kæ…F€‡þÒLöÑqWPBX`á#¦´«ÚæAßùþƒ#ÎÓXn³$u1�Y ÀuÃ|þE)èx†H¿õ.®-¿\t¿<7¶dÆ®(ìTü¾%ž(Í‚%Çê–¨«¸™Ç¨-’7ï±=ªaß’Ö±ü@†?À‘ÈT¡}ý‰öó·p ÷§àp(¶�RW‚»\ŸT@² �ž½îâ²;)BhôR9ïþ÷ïß®�ã«´ßì?}_™‰l¿ &°Y–ˆèê½odŠ‘ô*ƒïðÊ¿d�D«´âí€�Ì ³ûª]›õëha >ôyTMp´2‹¸e q¬±�8/ߟjÈ ÚǫɿÀÏ k³ Y® ¾ m’èº].Ê}ûß`æ4Ê�1Sy˜;€à,ɯt r!Mƒõ1Á�:°/i)¸X£ŽŸçÌa‘Xö–ø 4ðˆRš(Œ”ŽÕÕxºäIfQ3så/ŒÀ†Ñöž5ÒÕÃ',ö÷,½Ç²ªu[rwÝþ ÖÏn i á‰Tç†Ó9�XÏs§³Šè \·Ø =ºœôî˜1 "¸coäÅ/ê¡ã……¶“ ƒéžk?'-ÍHWªk …ukÈ1 0f›-Ý�Д˜¬5²gñéãªøÖc˜» q�;ˆZÀî5\ÂÓY5*÷[àØx–Àñ¯ß R»Y b¢úÄ_(%�…×L™ëa h²§5(·yÓn>�‘›éDŠ-¤Á»ˆ/HòÒ{uäef�/TCIÇ·R+FlÁ±øÄ» ÷UãÚ8ïúfBûa¦Þ<š’9 ¡ŒUvnɆŒ`g K³1–ŠN�Dß·¬ ÇL§? :ÚYS3oÜ 2b~ôg ó(š/¨y'æ”´¸ç@I%�JšZÐö3 lülŠY±=± ^!ua¯¼eAöè(†Ÿ34þܵÿÏSºaþ^ÀrŠÑrmgG`+n]8Ôī¿‹ù¨ˆ_Ã`ñ øHpn]á¼.2Dìò{µ¨ðDáÁí¶|’�>– ÇÓö~­mW�ÌÚxI�#¯g—zžÈ;‡*Õ~¶ïÅ ¦ëÞzi�9§6@û<û²ÂÔÆºI&o /Þ…t¯Ô,ˆ=?«v•s»Ü¥ÒÎ @™R)e~3ÛÑë�ûcêhiI�—·Ë�¸¥9«¾9Ü|F{ÿC2V1��°÷ÞSYêôše�@µ 9_,˜ í ñ9%¶ó£ùÂúÃbŸ…#æ2ä`O\úÈf+e^ìϦ�ê«_~úÆaÕgÛÖ;¸i † ï‘:§3mmØÁÚþ„ Ÿ{w©!dP-ÆæSêg£0ºÂÁ[Ü{efOŠ ˆ–s@¶ôÏÑ_!”um²hñM}õ!�å‹ë+Ò&�‚6YH C‹DµÕ{_ÅÅЧ0T7m`)C/4 Õ/a‡ •uâ©}XÛãcF ‰›Çš“SéºÄGÔÀbý�zðó¹EísÚ‚X¥çs ÚÿÙ‘žÿ:°÷dþ%ÎN—fÉóá ôVÍó ç掶¤CXÏIýóê +{A:3�Î×\4ñ&0]-k•ÈM$8£Äúâþ…éã§�jë]at ¸ÿ±/æ‰h& Ì(ÞŒj MΜûÊ+˜«ó½ãϹ¡ÇÉ8,'ÂC²Y0‚ùnù­eCÄ«®"¡Å«B¨û1øêåŒù�N>R.pñ1ü§)L­©Ó…WRW‡ÛZû°Ålÿç„£ª–ÝŒµé¤ &Ì‘ÔÜ+UáÌ&Ú«u´ýÝÖ~XªÏ"cÁ"l@u¸Ñ0¾ùòÈý×Ó'Ø ‚S¢XŠÀãZ¨\%téÔrŠ‹n¤¥5Ìç*¨\QzáÆ=@%â|¿øÑû.TÂO"µØ¸dGúE"sXYà!¾äx�­}M§ÖÎAdL¹Öï�„\•«üóͽlö·¦²ñeQMY¼’ãÆÓÑêìÎâ�Ðò^§ŸºŠÚð­)è›òê)—*ñæö} q ç‡ 0‹ãe¨ÇpwvšÓ æ¥I¯¼ØW‡ô,2_FüZl�à:Ô%,,�Ü!º9¾…yÓ”)[�~CZD,ÚëM“ß|NÀù_¨ÃJ[‘1hëäÔn¥Å-ª^÷rsÌ«§ymLBÁ÷Py‡…ÿk#”ÑQ{óxÅôgü[ ØH¬­a¼ ù¯¤w¢wGÕŸù^;Œ<ó?ó¨<¡Ý!ÆbNmÖð<^Ë´™É ýPÖË�Ò6»y^‹ù¡Ð†¤¿•;Ñ„@Š¢¤vf+]û²2{æ¡ÜVFªÚó¨e¦&™k1ÕVîj6¼_£™f½×L2bJ¯SÌÙmý�«3QIÜ]¹»ÜÖæ_Ÿ£‡ð8øŸ`øÜá ÐÀXè" z)ãBœ"À$)‚ �A„ ÿÿÿÿÿøÿ×?ÿûÿÿÿÿþ¾Ývb£×B�¬¦ ³4Àã°²+¸µÂ¤Ír¹Á�ÔR°Ä%;�îR£Q[ÿÿÿïÖÜîÿ³¾Ú7UW6dTUT!ub8´Çø çèx?ñ.Ì€ˆˆˆˆ�ÿÚÚ¢³<ŒaeŸDY/ÿÿÿ½ÿPœ¼·$D¬(躡ïPŒi§ÿû`À€Š9à… éâH#4•¸‹RÒAbÉuÏ&Ž ü:=ÄÝL´2!Ô¶#9îŽÔ#"5¿ÿÿÿú­ÿfE$ìȉ,ª1HËez²1’ª!ĨR ˜‰Ì§)¢((â¢,Êc°š)ÄÜX¢¬,qE„T9N@øˆtÿÿÒþ÷ÿ?ÿû`À ò= mÁ¸È#t�¸¿ÿÿóËäܯðÉ÷IN¡æiÞÿ{ÞžYg§S—ÜëdE/'ÿÿÿÿÿÿÿçþ§Ì¸g Wëï&%ÍirÄDuñ6.ÝítÜ‘mtP&ê,Ž�«¢’Duhâb¨D›ÀN±ÿÿÿÿÿý`Zÿý{ÿÿÿÿÿçÌímÞó¥/Þj¾GH„<&ñÎC¥ÿü„žl÷ÿÿÿÿÿÿÿýþÿçJÎÉP��1•¥I’òÔä»ò9£3³ZHFÊ;ŽÔr/viƒÃ�1  Ü‰…£2‡ ìÁ�ÿÿÿÿÿÖõÿþyÿ?ÿÿùz\¨Û+dDΪ�1ˆÆckTIw˜ÿûbÀ æ% „MɬH#t‰¸™¨…¶R²¶Í´öÿÿÿÿdÝꓳÐ÷1êr© ÊϳîÒ»³lÖ• lΆmC‘Uê÷c,ì$(tÈ4BKÿÿÿÿÿëåý²ëZSÿÿÿÿü¹QRÅ­ÝŒ‡>³Ìl®®è§1Œ¨ˆËf:V¨m&¾åDGB;?ÿÿÿÿÿù­RÌé+ƒ9‡}•+ϳ+±ÍUÐèÊbPSú;1Œ%Ü; Š…R•Ìwt”€Î9Bÿÿÿÿþ¶ƒÿëÿ•ÿÿÿÿäìúRwó5�lª„s>ʸõ#ÌäºuFlëÐêɕћÿÿÿÚÿ³«ÔªFJȪyŒEus–ÿû`À" ? „­Á¬Æ#t•¹a2ft*3άVwVl̸â•êc�@@Ç‚o2ÇåQÇ;> ¢£€?ÿÿõ�sÿÿÿÿÿü»µ®å:=¨îïv:ºº•VB/Îlêèö-ÊZ$Û™5OÿÿÿþÍ'*MD£�'» È.–z¹›S«”ÌêW!„Ça溡Z!3#NǞ#!ƒ¢âcH5VA¸ò¨`†`±�óõùþ¿ÿÿÿÿ®•g;RWT�ÙUÕ½ÔÝQeÑÑTľÎB%OÿÿÿõùÑgêÕ9F F‘�T‡j9"Î(cJb#!Ç�xˆÕ3³ ªEÿû`À, Ú= „­É¯È#4‰¸vcœqL8áaàÊPq¢�Ñ2$48ÿÿÿÿþÖ¯uÿºÿÿÿÿÿ?£‘Ý”„5›Rl›ogGÐŒªöi7ºÕŽ·ìKwÿÿÿÿÿÚÒ"1Ý_™Ü§8¤T„Dg�ä;YƒœFä%PìÆ \ÈäRŠF €‚äS3: ÁÈQBªà•Ü(ÿÿÿÿþÍ�—ÿ/ü¡ßŸõÿÿÿo‘œíbnYØz(‰‘ëu×J:ä·Id£ïZÐÔÙÿÿÿÿÿþŸJ'»Jƒ Ff®ï©Ne+ È 8ä*&*†q2 0�Ì AŠAD…0’�Q!2ª”¥A§aQEÿû`À6€ ¶A „­Á¬E£t�¹0ÿÿÿý°/ó׿ü¿ÿÿÿÿò]s¹œÐô… 仪Dþ9FzÓ¦[7‘t¥+M¹2ä³ÿÿÿÿÿÿÿéÿ9æÓ*FE‘D‰»ë2³×r™9“Ò·I­|¼UèÊã±Áz°spÂ+† JÛØ8ÿÿÿÿþ��©ü¼ògRfÒÏåÿÿýþ•$íc1üý§º!Yz:d÷#ê×*º%Pú?{¯ÿÿÿÿÿèɦ·5\ÎR£¾ì‚ŠTv{˜Ä$A™ RkÑi†ˆ!£±ÅÊ�Ö(|¨rˆ˜pðé¢î<ÂÁÀ+)�h0À5�"ü¿ÿÿÿÿÿdîÿûbÀBVA „­ÁÄÇ£4•¹�F±:¼Û>yê­)Ý�ì¬åºQò²+7cfTÿÿÿëÙ[óÉW£•hr¿ÿÿÿÿ�iO‰�&�׊aÒ¶§ö’ѺkL“ÔW0÷?ÜpµpÝÿÿÿÿÿÿÿ1ÿ×ýúÚuz÷¤sò8ë›~9�çˆ^;Ž’˜…ìar:¦hZ—Ro|†AwÚÖìXòo®Ü**>@Ö0ÿÿÿÿÿëËWuûJ�FÑYìîåˆòYÙræ\ˆîjí»*"±Hßÿÿÿÿ~î‰m¨—g*:˜…+"ofi•ÞÂ#E� �¨²)JçWACê,$aqÊÇ)„€p1Œ"Pè‘ÅH‡(Ñ¡`8�ÿûbÀo€5 … ɽH"Ì•¸3èòÿ¯ÿÿÿÖ×Ýzè¼ì×»Èr/È¢ Ê®”d£3Ñ—yN¤qÿÿÿ÷ä{"Zåu#ÌeR ¸ñŽÄsî®e-ESi‘�pÕ( ›0“�„bŽ3‡Àãs�†�yNEr”ÓŠˆ¨€� ŒÀÿÿÿÿÿí�yïÿéßÿÿÿýz.¥1,o5ä+9·Ežuvf±Îõ¹v}ÈÈ–NÿÿÿÿDû}l³µ+3UTŠCo¼¥>%èOyS!�XŒ‡‘Æi;�\ê8#)Ń:‰cÅ•Êt(P‘À?ÿÿÿÒÿùÿóÿÿÿÿù´š÷fÿû`Àx 9 ­Ù¤G£t‰¹b$„vºftgdû©kU-™œèƤÆVäfÛÿÿÿÿìŸêR>Ó­ÕK5(i5; Îñ“•ÑŠwiÇ*¹ˆ¤"âŠ*.*1â¦c´x´çRH@“ˆ#•bÀÿÿÿö@¿ÿ-»<ŽÄjµ=]ÖÓTª¤®Æ96Kä<îäsn³¼ó—ÿÿÿýv"Ñõ{Ñ]LëgR�g©ªF5ŽFuõZÇQ3�QÓ ‡Ç°›”a‡¨Ô ˜µÌ.tP‰GQCå<ÊÿÿÿÿÖþ]ÿþ«¯ÿÿÿþÞˆy‘žr3ÚÛg§Ÿ¤m4U++!d“Ö¶_J´Í{ÿû`Àƒ nA „­ÁªG£4¹ÿÿÿÿÿÿÿÿöù7ÈqyiHsC0¤Er_?* –gÐNP�‰îF¸v#UCªˆ9ŽB!* jè�A‡1Y(0ÿÿÿÿý`_óòþ_ÿÿÿÿüßíÑžïzJ_¹K&´išôE3Šeu!&>ˆˆþFÿÿÿÿéÌý<ˆs±Q#•ÞcÚï39’Àœ“Ùœ[%ÜÑÝÄÇ8s¸Îd†; áXä …C0­ƒÿùZõº�Výi ­b¹*ªOf3U§,ÍD=®E%^ÝËÿÿÿÿóHêí³=Uή¯­]�™žØâ®ª9ÕŒfd#9ÿû`À� òA „mÁžÈ#t‰¸Ñ�Ô�¤C»Tˆpø…Å”HƒbÈ s‘� E,*Qÿÿÿÿÿý`9oËêkÿýýÿÿÿÎë"åE§KQîÖÝ�Jî·<†aG TGȪW›F}]iÿÿÿÿêÞªú#f«¢Ì¨ÅUTH̵Eç̪·;f¤€ÜâÀÙÑÕN]Dœr¬¨qNÈaÝ(ÿÿÿþ²ûçþ}~_]ÿÿëïôìÌÇûèw.šQÞrØÌÌäb-lzèÒÒšÿÿÿÿßé­ÝíSUÐæg«DL†îB�ÓœxÝ� ¶QE§™ˆc±îD €Ñ3‡PƒÃ¡ÿûbÀœ 2A €­Á²H#4‰¸$)Ÿ1Qd‚ £ýÿçÿÿÿÿýÖþ—tÍT!˜¦ÈwS5îêëfº�ÐÅ*”�lý؈ŠßÿÿÿÿôºµYÊÊKžÓÊÄB²¢�Ïvj±•QXÌB *”a”£¤q3”Á7 áº¡b±Îƒ!¬k **�6Hÿÿÿÿ¶ü¿¿Ëå_ÿòùß%é,«¿uÜöeæBÊìöJ¹Mwº®í­]Õr«7ÿÿÿû¢Ú®d+Tµ#!•ˆDeœ‡æ)Øì…F•®q`³�QËÊ·K ‡!:ÁÎÂÃ�ur‹C˜®àÿÿÿÿú@¾_âüÿû`À©€ ž; „­ÉÁG#4•¹¯ÿÿÿÿçïÿ%2ó¥xzžõËa©—ÝßÈͶMŸšÃ™);þe­Ûÿÿÿÿÿÿÿÿù~~KrS¬[uvzŸzYq¢ñ òlQ�wÑß#}¨\‰jZ |‹T �¸Ä!ÌéÀÀàÿÿÿÿÿ�Ÿž Øç —Ne9Ÿÿÿç eR!áçÖVê¢õœ}!wÂOí3UUÚZWU>ÑÿÜWÿÿÿÿÿÿÿÿ?íñó÷+kLÖÃùŽ*Øëk‘s*—gJ�4`ž¹EÆÇviF"‡$˜z©†9‚XõÂa�Ë”9pèP·XT]Çÿÿÿÿÿc`qîyÿû`À²€ .A „MÁ­G£t�¹‰#±’¿%¾§ÿþY¸tûîú㙬ꙉy¥˜†ýwŠõÚ©¦÷ÞÒ¥©S»éºæÿÿÿÿÿÿÿþÿ¿ÿû¿Ž¹šk¯«YO›­²<6<’±…&TÉ눢Æ!wB±E2ˆ ¸ö³J‡4\V…K1`°’ކ6Ëq1Š@ÿÿÿÿý±ƒÍ#˜Wå¿Ì«ÿÿÿý:*\Ȫuo™��H(έb+JB{1¨¦î·±•jjÿÿÿþ�7¥®·tT2+9#ÝÖ<–ºœÈ©*­ ayŒQ1§3•Ú&=¥B�:``ë‘‚¢§Š ‰Zpð[JQÿû`ÀÀŠA … ÂÈ"´¡¸ €k?ýþ½ÿÿÿÿÿþÕdR•¨É¿WDJ2oR›±ÎÓêUd©Šf3¦Óo5ŸÿÿÿÿòKk­Ê„y™bêìêt3–S’È5‹Ž «�,† 1 áòŽr�JâŠ0¢„#(@Xêè$,�âŠ�8Š4xD*…„ÿÿÿÿÿ’Ëäû×ÿÿÿÿûνey5v}úº*±K÷U2‘ÖgR™–tK"µoEÿÿÿÿÿéîíLÊŒE:2+Ù’}Hî8†fc ‹³)†ÅÌîìBˆaÇds¸“!…„XPr˜xñÊ,Š($0<*5 †4lüÿû`À³€²A „­ÁÛH"ô•¸Ö|ÿÿÿÿÿÿôM‘Û[VÛ²NI”¬ÚÖçbk3›ß¢ªÕ‘Z~¿ÿÿÿõ¡j‡»µ¶g*•Ø”ssB«¥r”¬QGª‰ ”„)å1˜0‚ädÆw<)]Ì($aE8pj‡ÐhÀ³˜À¢¦‰€ÿÿÿÿþ��ßüÿF—=ÆÚþ¿ÿùå®›±÷õÌk*"§f5§¢*YÕC^bºê§»LÜÕ²ÿÿÿÿÿëî‰wcª¦UÎ<Ê;0Ô=QÖ«žŽ¤�:³ó¿ÿÿÿÏé¹&q…+T©µ'ÙTU•ŒgeR á‡B32)—ýž·D|ïÿÿÿÿÓ]«Mɺ+YŒ[Ö¦0Ò)ÊbŽ¥Ž5EQ„ÄEa!˜\h˜AÂ!ذ ³BÃîg À(ñá‚ÂC &P 8|DV&Qÿÿÿÿÿû`À´€ÂA „­Á×Ç£4•¹ÿéä^¤–ú,‹ÿŸÿÿžÒ÷f»‘×d[Òº½ V¹Lës ws)P§z^¬t252]koÿÿÿï§£÷]»ÍÊS2•gsƙٞDkaœÔ9�Ç#˜Â"%F âƒDL*£¢ (B" ‡XÂŽAìb¼>ÿÿÿÿÿ±…åþY//ÿÿÿüæ©J$î”Y?RºÑôVT}ÞŠrQKjßZmu}vÿÿÿþ«ëzttz%¦TS•1ä#ÌÆ½�j=‘Òª”ªQ!0c ÓH,¢å £ÄÄÊ,¡Ñw‡È 8ç1Ðå†0¸ÐÛ ÃjÐöÿûbÀ¶€A ­ÑÙÈ"ô•¸}s—ÿþ¿ÿÿÄ@÷:XÈ®M*¨Cc¹§r”ü­#çDQz­ªý§µ)ÿÿÿÿýþ–ÑNbç›-LQl„0׳ )�Ük ;˜Â,5ܣŃ‹;"Š 8ЦA¨$ÁÑqÆ�\M…EAB@Áç( *ÿÿÿþ��ÿ-ã4Ñ—pþRÿÿÿ³¢îVlìU·K&öu+<Ï™‡tLììv3¡ŠÔ³I{×ÿÿÿÿúûû•YÑ ¥*«“êçªîR†Ð<Ž=ÇÔLU…aÅqáL (sˆ”ñ¨§D4P€È�‚Ä !˜€8ÿÿÿÿÿû`À·€’A „­ÁñÈ"´•¸ÿìŒ w"šçÏ’–«ÿÿþMÿÇýwóó¯÷Üu]fFÌÕH÷SR‰õô±×K¯×ÿÿÿÿÿÿÿÿÿÏw§qóßLò°»O¥O3r²1GÔ­mÍ»±å;=šSÊ8y£2lÏ#•0ÑÄÃHˆpò �¢¥�% « €ÿÿÿÿÿ²ŸÏ_åËzÿÿÿþþŠŒ÷Z2>ô±• ŒÌ]ªC\�È„VGGuyÕ(Êr¢J´ÿÿÿÿû[BUÝŸaj«ö£[‹Õ™HŠèãLRˆ˜«yŒ‡œ¬C%Üq]Qbì->A!Y�â†`£1\Xâ@`Ò y?ÿû`À·6A „­ÁâÈ"ô¡¸—#ÿÿÿÿÊ­ä&ʪË�ÕèêÊ}V¤1Ö³Fnn¹:û[¯ÿÿÿëmjÌës¡ÒÕF!ŠbŠê®Æ)˜†‹‚*‘LŒcˆ°�j¡¬*‰¢ï0p¥>$av!œXè4DHÁÁ5‡ÅĨU(p@1@ÿÿÿþ­ƒüŒÿ¥ÔËïëÿÿÿ7êˆìµR!Ÿ#£µŠè¨~ܦf5æfb1ÞŽÝS"ÛÿÿÿþßèÍiš£P®vJÖ®d1qèq”2ÚÈ0:Å+‘Tƒ6aÂbEl?2‡DD…‡‡\M"B £¢† ”Ácˆ4\6à ÿû`Àµ€.A „­ÁçÈ"´•¸´ý¹~öÿÿÿþT«Û"£—ÜÇž—ÑsÙÑhê®DÎmYd½îdSnÛÿÿÿÿéí¾­:ª3š§š•c%®5HQU<§!ÅEHcDH@8â(‡E`=‡(¹Ã§qR¸²:$&<(j¹‹ÆŠ¸  ˆhˆØ6­ƒóæ¿ÿÿÿÿ#í%)sMªØí1ærÚì·IUkwG‘rîGtTe÷Ñ—ÿÿÿÿÞÕêÛ++Jζ%ƱÞÈÄÌ<‹;‘XÇ8qˆ‚:‹ Aa6qe- @ÊAA¦`‘Dˆa"ÄÆĘ„@ð™”:?ÿÿÿÿý$ÿû`À·€A „­ÁïÈ"´•¸/þN_¬™ôëÿÿä ÷Gõ>¾J¥Ó:²�—G4¸±Q(„tC\î{+©•®gOÿÿÿÿ쮕½Ôˆ³!O<®ë!¨Žd,ŠæR1>‚%f0°¬@ê>qâ¡ô (¨˜åœ4ÖQ!0ø€ºX‚eQC€ÿÿÿÿÿÒäþgì?ÿÿÿÿÿ-‘œ¦ŽI"*ÌD£™•̧Y§In–jH~­’Vkg»T®Š¬‹ÿÿÿÿ•úÑÌŽäRËÕ®¬–K¦í[ÝF"Ψpá®ås ƒ”<îƒáC‡A r$ò 0ˆ×R‹ŽÌWˆ€ÿÿÿÿÛÿÿûbÀµ^A ­ÁéÇâô•¸½ÿÿß›ÿÿü¿->ùŞó/ß&@ºÒzšºË)¢Ô-^Ÿð¼Ž½Ïmûÿÿÿÿÿÿÿÿå‘ßæe ·îV›E‚˜6��Þõ$4C¹»¼­dPÀŽŠ$B¬ŽAÅ£E "£,†8SW©9 € €`5‘çÿËækúëÿÿòÿZšçTC£ú^5Ýõ‘œ¨bT©‘Üz-®–™=¤½ŸÿÿÿýiCž”èËB)©au”‚o,ÑÈ8‡c‡ ""@”AÐD¥*<:*‡ °x:@ùDEEH8:.Œ…Ї†ÿÿÿÿ¶ü¿ùëïÿÿÿÿ©ÿÿ–ŽÍ­îGH¢’°»NÞ±™ÄW%²zÕóØøDo“eÞÿÿÿÿÿÿÿþ_ü?)¹leyX†¿ç)ΜzR̈Ÿ"]Ë•L´'dxÈÐtS 3j±Û é àÿÿÿÿÿÀ~˜dsÿû`À½€>A … ÂH"´•¸æ½ ÿ#ÿÿÿ˲µÐÕc0‰&V‰ZâBÅrÌdpëFEyFˆm ¥*³¬Î¾ë×ÿÿÿÿÿ¿¿mYÊŠVÊÆ}LêÆ+>j=‚¨,å-*UcÅB²=� QSÎPèÑÎ"ÊY˜H  ÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿ¯ÿý~Æ(`JEª*!ÙÙÊbª”Vs ` �#³±Š©ÿ³”ÁB(ÿû`À³€ n? „mÁÑF¢ô•¹ÿûbÀ»€&@ÞMÀ[Àÿû`Àÿ€ÞÀbeetbox-beets-00724b7/test/rsrc/empty.flac0000664000175000017500000005260215253035401017775 0ustar pieterpieterfLaC"÷ Ä@ð¬D!îÄvoWeƒ×l°÷�� BÿøÉ•@µÇ!Ì¡'†hPæhRs%… $¡aäÌ̔Ô9C9)™<¡C™”ÌÌÓ%8Y”Ÿ)…% aœ(r’‡49CL9C%RY’Ì<ž… dÓ ”)™™œÎd¦M 礧2…&yùgÐÉågÊaá94�% L³9œ(Xp¤¤¡ÃB…3™e% B‡ ˜D™¡= ¡@³ ) !ý Ì’˜s(NN’…2P¤¡åe&faʤÐå3$C'3™ g$³ 3”%8RS%™"Bœ,’” IC„By— °ˆaNˆ”„Lä‘ ”Ê”¡”’yC“2i…9ÿÿ¤¡a))™B‡ f,0©@¦„¡IÉþ†Re ¡(XS� …†Ng:OCž†s¡C™C<3Ì4ÉL(hÌ9å”)“"))(Rp¦Jg3™™˜S39òÊ�I’‡?)“)9C3'(e äžPÊI,)(S L”)'&p¦r†œ¡Ìáae ”2P)2�HD%B†”†Je2yB„ˆP‘‡‡(~y@¤¡4)“L<™2“¦K(y(”2“‡3ýPç)3™™”)<ÊaC˜R�¡g)“)3æS0¥ 䟔ÉÒ2d@°å$晡C…†s,Î�C“™ XzBœ)™’�a@Ò�¦�ÌÊÊI伡I’‡%0æRe'ÊPÉB’PÌÃI”'&RP”2yNe2 ‘ 9ILÂ$2™)"% L¡Iš”þXRe&P¦pˆ(L¤þ†r…Pæ…$ò–,2’Pˆ”2’g JÉ43š¡CL)™Ìó”3' Ðå$C„ÉMRS%330%3 p¡I”2“†�IBr’�aÿùL’™2“ 3”É)'œ¡Ì§= ’˜x|)C9'èe$Δ dæsÒ$"I…9ô” 0§2̦g4) )(J¦g p¦fs)†œ¤¡…™¤ˆLÌ“ÂPçÐ)’„@ÐäBr� D…„¡á¡’�¤¤ô<'BP,(g(aaNÌŸ)ÊC930¤“ÃÌÌÌ)(RrPå0¦L¤ô9C””9œ¡Â!™HD fJ ç ÉB r“L‘$èg= 4Í ”9ÿ<¡É™™Ê<Ì™L%”’JL9ü¤ó9™C™L硜¡IB!(D9™ä§ L¤ÒS%2RRPСáI…†i4ÌÌÊ” fr’r„§9HD93ç@Í Ê3ÐÎPÌÉ™™™ÌÌÌ‘r™% 8d¡ÏBPÉÊLó9)C9”3’S32†JdˆL¡Ê¤¤¡Lá¡Ì")Ì,™Iè””90áÉL¦O”(g e&Rt3” D99I¡IL4)(y‡(g?@§ L™I”Ÿ)œ)Î�IB’‡))(r†PáC””9Ë sL2’O)%(O<æJJJJùÌÌ,™I$C!L9B„ʦMçB…‡(e$”¡2Â…8y”“çåŸÿ‘L¤™™%0ç”)'�IáNL)3å I™’r‡™ �œÊ)“L””ádÌ”š9�'IL”””9II)3?ýœ(g…2R†fLÿô2“!(D ™C32Jaœ™L,ÊJ˜rfH„ȇ“<)™…&hfPáC…8r!9ÊJrPˆJ”Éèffd¡Iå9¡B�§ÐfxÿøÉ’@µÇh!)œ“4)2™™œ¡I™™Âœœ¡ÌæfH�¡™L3”3ŸC”ÌÊå&s9Cœ¡IB“ÊÊàS‡2D2RRP¤Êý ðÊL¤Òz:†e Ì™çÿ¡Â$Í B…�Ð"LÄ2S„I„Iœå&|ÊLå&P¡Ìœç(fdša¦M™ÊL¤Ê”(JLÌ)(S'2PÓ g!d–JfP¦ffLå$§ fL¤ÏBP¤¤¦fK3Ì¡BP¦aIÌ”)2†hg4(hD L¡œô' S% r\3„@°Ïå&PäÊ"žILå p§8D9™ÊLÊœÎffaIB’…% NPžaL”)(y(S“)0²aIÂ’…' J ™ò…&P9@ær„§ fL¦¦M… LáÈ�N(RfP¤Ï(RP¤ÿ‘& Έd"rfs9B“™“òœô(Jr™(P� Ì” J¡œ D”)™”(s'3œˆ¤§‡3ЙL)3ÌʘYœÎPæRe2JJ’På æ™4Ô)8P¤ÎfJåž’™""ÎS’’�IIB˜p§33%8\9žff4e$ÊIC„I?(RaLÃɦÉÌÌ¡IžS…9È“4Ì)Éš Nr!(RyB’xJDPÊ99”9ùe‡=0ÊLå…%™3™ÌÊ™¡œ¡Â!(S&RæaJIáœ(S'0§' 3ÉL”)̧ dó‘ žPæg0‰2PÐÊL°³B�¡’PÉ”šg>i'Bee I…8RP¤È�Nd‘ œáNLæIL(Rg æS% ”�ˆ&JLˆIC¡BPˆJhPäÌÊB”“œ¤ÏŸÐå%%% ¤ÊJaÊB„ó–r$™He$ÉB!†™?"Éʘ~s”3™LçÐ))ú(I¡ Rg(g0‰3Í’ž†s¡È�BÌ4“œáœü¦ffL¤œ¡ÉLšOIô9CÃ2|ˆ%PÎ ”Ã)%2PˆJ ”(p¡C9333š…0ÎhsC� œå Ê,ü.)=!å ¦NRg” &rPÎIfg0Ó'aš…“3æRfe B!3™)˜Pá@²J8PÉ |ôÃ(PáN†PÎJB…&PáÎae%32’~dBag2’|¦s@‰0ù™’˜S33' ” ”&D'0²M ”(P§9Cœˆ¡Ìç3œ)")’!2!ÉÐ(RPô9èd¡Â!†g(Re'ü¦JB!HS)“)’�L”)8XDe0ó ™”)2“þS'”Ÿ)2“”ÉùB“2“úfs9™C93% ™ÉÐÂÃ)2†rP¡L”?)2… æ'ÊL¡Ìå'¡ÊsÊdò˜s†JIL”Ì)™2!†“3) RLò�aILšaIɲR‡&sœæH… LÌÌ”ÉLÌÌ¡œÌÐ)(D39%'¤"‘ œŸ”2S%% 礡I”ÉL”3’™™?(S0РRgŸ”Ì”2P¡)ü¡É”„@Œ€D…„ÊM0”Ã33&“¤¡Ê™'ÊJ”™ç)™’†Éœ(2e„Ê¡ÏÊNP¤Ê)’g%„ÊJœ¡2!“™’†�IÉÈ„ÊY&’t&S$³,¤é†…'% IC% ¦™”8“ÿøÉœ@ÿÿµÆP!9BR‡™“ÎPðå”$ò…'3% ”šdˆp§&†NfaI”ÃÌág2’eB„¡’†O”)™ÌСÊ”¡œ"9’…&i)Ï"(fg?C'ÌÌ™9œü°ˆ@¤ÌÌ¡œ™C8D2p¡Îfs9œÏ$Iœ°ù”…2†s rP<“9))"˜xL¤Ì¡Ì.I¡�‰˜RR†r„ô œôÌÊ’” JH|¤ùgÓ0¤¦e áLÊI4Ÿ”Îç–ÉL,"8r™)’™œ)3I¥ ¦Â!™…“3„@°å$ÊL"ÉB’ŸB„ÒI¡BR‡�‰™“Bae2S’…2O …(M ”š™aNfe…% r“)%$¦)(ú¤)(d”™ó"y2†…'¡’†L¡“˜\žRe'”(p¡fS „¡¤ÌèfP)™(hd¤äC‡¡ÊfRdBe ”ÉòÂ’‡)4(g0ˆd§)<Â!„I<3’…&yB“œÐ¤Ê“ÉèfPç%2R�ÌòÊáBÉ™”ŸÐÂÃý&…&t�0òtÉNL¡Ì¦r‡˜RS aä:Ï¡’… Ìœ3C9C9$C…3$C”„ˆ™Ìó dÍ'L<”)2™œå$¦IB�æfrD)ffg% !JCL9”3% LÄP¦NM0òP¡IœÉfL¡Ìç9C™™C9œÉÃäÌÌ”ÌÌ”) "™™’”š™¦˜g(sò’P¤,Ê™43ŸC'™Îg3™I”™L„LŸ)™:ž, ™I¥œ3C')’s$@¤¡I)(S%2XD$Cœ"B”9œ¡œœÏ9C 9ž~Y¡C˜S… Ð3�§$¹œ)“™™œÎPÎgå2J“)(r„¡C“2e%œ2™†…%™")œ¡ÌÌÉB’g fg2’rS2�áaœårD)3‘„B„ˆPÊ™C”„Cœ2““4ÉLÌÌæyÊÉOÐááC38R†rd¡’…'8D9ÌæS!°"dèr’…&2e%PÊB‡“™2 P¤ÂžS…9ÊNPСə)˜Rf’…&Rr!C”(Rri…2s2RP¡ÌÓRtšaä¡I(p RfP"9Ì‘ ”)(RO% 2D9™ÌÌÌÌ¡L™@ç)œË3”3“™á,(hRC (žJP”¡=ÉäÓ åS3œå æe2hPç (d¡’“"�r!3ÎRg(L¤ô̦B”“ÿ)(ICý’’‡…&|¡C“™ÊÂä/”™C“(s …|ÐÉü°¤äB| (Iò…&r†�)™9™™)?”ÌÎ}“‡3”<<’…!BÉ”3Ây™”9”ÎdI'”™d¡¤¥ Ê9BrPˆ„BO’ F,ý ”ÃÌ9’Ê“2rS3%%%% IB�¥�fP,:R†B%…�JI”3%‡3(g0³3™")’™:JfP"\¡IŸ2’fs9™‡(̙ʔ"IæD) ™>P¤(RrR�¥!BÂ’…$”(JPç¡IBÌÌÌ)9™™™™)(r“Òçô'ü¦aðô%Ô̔32P)3ÏŸ(y…2p¡Ãœ)I<9”9™™™)™Âœ(S3™™™)’˜S&D&D3„I”Ÿ)9I”ÈD˜ÄÇÿøÉ‰@µÆè!339œÊað§ dóÎfaÊ!�s LÐÉB‡ N“L<”)8g?Ò…ÎP¦L¦JP”¡4(JBa&P¦Lä@Í °¦fM çÿ¡Í L¤¡”38Pæ…&RS‡˜g=De É”„I”3…0¦NJJHD)9‡’Y@¤¡™å2P¡áäœÿ)(L¤”“å9ÒzM0å Ì,Ϥ(X&xD™”4 J)9’™’„@ááe'I”” JÉå2|¤¡(p¦NP¤Â!Â’’…P¤ÊM Jfd¤äC'30§!a”Ù”8D8D)(Dœ¡)™†R NÏ)>èr„¡’�L™@ÎL¡Éæs0¦aIB‡“ˆL¤¡™™‡’áB˜hD $ð¡I”Ïœ¡™)™’ P¤ÂŸË 9ÎRg33338S3'333$C'%'IÒP¤ðä@òdC338D4(Y3”% “2D(JJBP²…&fffp³ p¦e J“2Pä@å%(OPÌÌ“ÉJ™)’™Ê̤”™IÊd‘…3 fg3™ÌÊ¡œÌÉL””ÉLɦ“å2t °”ÈDÉ32S&’†„C™ò™9L(D% ™I9„C%'(rPÎe&S'¡BR�ˆs:œ)’Xe&r’e!¦JaL™IL–g9C„C'2S dä¦yùL<…2hfp‰3IÒt(d¥ èÉÌ”'C &RM% s)2™(”<¡Î¤Ÿ 4ÉLÌ¡š<ÉÐÊLˆL¤¤¦g dÊ™“IB“†p¦N‡"8e Ì™B‡3ÿèp‰(æJB�‰“™™’!Â!Iœ¡ÌùLÌå!9ærS%2S9’’†xs¤ô32|¦NPæRz9Êdé;&ɦ¤¡LÌÏ’’�ÌÊdèr†fL¤ÊfS3™ùNÌÌÌÌç¡ÎD’RhP”ò™:Ô93™Â™9™ÊNS$ГBe$¡H_üó9CÌæ’…&)“òœé(Re0§$ D”)ÌÊÉ”332S<ò…d¡É™4ŸèäŸ)“þ’…&RzJ¡C… ‘R…PÌÉ”™Ê(SPˆÉI„”))˜RP¤¥ ä”ÉLæRIILÂ…!O¡= ý&”'˜S$òS”™Ê™(S0¤Â‡ (s,¡Ê2fr’†fs¡Iš™Â!Îd¦M0òP¡ÌФ"!JIpÊNfs<¡aš,"Ê¡“æRe‡(Nd¦fJd§ 3™C%% B‡ =%RP¦g„¡äÌÉ”‘ æOš?ô(JÄ@°ÊM0ËHD  R š™ÏI‘ Ð)HR’˜Rf“C„I…)$¡ÏI¡N¤™I”” Na¡4(9B�ˆž¡43™žyC@¤Í äˆd§Ð¡Ìÿ)“ y'3”(s39™…2s L¡”™IB…!BÎYô2r‡3”3“3%9Ÿ””2zÎ�I’�ˆd¦ˆgÿB’S!IùL9œÌÊ̤”,>�`A“)%8r!)ô2„Ê|ùBÀˆrdˆd¥$å B– J™’™™æyÊ y‡(dÐÉBLæK32P¤ç)”%�èf‡)’™))(RLçÐÉBe&†y™œÌ˜e&)2’’†‡))(sÒzaòî’ÿøÉŽ@ÿÿµÆÈ!å” 0¥ B’�IBÊÐ" XAP¡2˜y…™L””33 Re BœÉL)’”)8PáLÌÌÎdˆað§2P¡’”% Có”3™Îd¤¤¡Í'I¤–P<ÃB†…32‡(PÎå&S3<9 0ærS%0¡IB™…… Ÿ”Ì” NdÐ)�ˆd"LΔ)3Cœ¤ f†r„¡IIBÉœáá‘ 43…2JL¦OC”š2S”ÌÊdæfg8Y’!™…2Pˆg„ÐÉB“‡‡%gþ~ÿ”ÈDÌ)Ì"pÞ Y…È\’Ê… Ð)(“ÃÉ40Јp¤¡IBœ…™™Ã”2�džáe ù¡&„…�òi(Rp¤¡aNH†fNaæg”9…(pˆ…™Ìæyù¡BxPæg2…!9Ìó$C%(‘’‡&p¡I™Êœ4¡”ÉÉ32P°ˆJs3%2i…2hs>RPÏ0¤ÊJžg(y2Â!<ôš2†p¥$B‡2fJfP¤ÌÌ”,)"&fsCB“Ì‘0øP²N„¡Iša)†Re3ÿ¡…˜Sž… Ðô”šd¡Ê’‡˜y(RIr8S39ÎRr…�ä̇É&PÉáË JfPç†�áLš¤"ÃB’œÏ™”&D˜D8e&’†…% H�)I”Ìæ‡ p¦g ‡PæfPÉÔ9IL”ÉIB“)’…&zB„¦OÍ!))(Y2„È„Êfr‡(L‰2’’ Rg ¤È„ó2“’M ”<�2P¡Ì–P,2‡ fPÎsÐÎPÎe™JË…8RP¡Ì¤ˆP§(faÌ,™C˜S… 3™™(s)…(JfRfK0§„„³%)‡Â™2†s<¡ÉÌæJ9”ÌÉL“†pˆR¤ü¦N‡"(r‡‡)˜Y0ˆdÒIfrS3<å&y™…&S32†g�NICŸÈ�¡BPÊaòg2†rPÏP)’”<”)”™LÜÍ…&fPç rap’Èr‡)(hP”å2PÉåLÌÌ"L‘ @‚œ¦L¤Ë J™(™(g&e ˜s%% ÊaðÍ ÏC”ž‡(S33'% J,8RP))ž†sB�f¦ÊL°¦OžP¤”)39CC”„B“9C„C™LžS8P‰ ç(g&PæRJa̤Í™”“™˜S2P°¤³330ˆdæO…8hR9C)&p°") PÎÌÎRe3�2S2“"…&g 3Êp§'(g0ˆLÊ… C$¡C…9C”2Pç)9œÌÌÌÌÊÊaÏ)™ÊHPáNdI„IC)2’’!ÉB’g�LÉœ3’œôÂ’…3' (J3CB‡&ffe$ðÊB……”<3… È�)èdˆ%% ”$ˆdˆR) d¦H�HYœÊaÎP¦aC33…8P°Ë f!Jdˆœ“Ã9ùC8D9ÎdˆL"d”Τ",,"ÎP¤ D™�IC’!BSœ¤¡=™“% ”ÌÎr“œ¤"Lç3ÌüÐÉCš™C””ÌÌÌÌÂÂ’!(S…9™Ìå ”’�IžP¤¥ ðΤ%0”) RSúÐááC”2“(S$¡H|3IB™’™"Í æD’|¤že'ý0øhD!0‰ s™™)(Re39”ÃL§�aBÂÊ’�á¡NÌÌæp¤ÊN™6‡CÿøÉ‡@µÆØ! (e&J2„"d¤¤¡L)�Ð,Ê)�ˆXRR~RNdˆNaÏþ‡9Éœ¤že$¡IÌ”) 2RD JæRO3” dÌè™Cœ²‡™)“IÐÉóç”) PÌÎL¤’˜Rs 0³ JI„C%9O&™)48YCÉB‡'’„HP²fH‡9Ió PÒO@³4(rO”œ¤Â&O P“LùI”(RPô&˜0¦g$¥J…)%2hd Rd¡I”$¤’!2 s‡˜y‡˜xffN†J†hNRP4åŸÓ…933&˜Re!äËɤô9C”9é†hd¡…’~S'9C8D%8DÙ32RRD NL¡”™¦J B$)ÊaN‡4ÉrD) ÉB†… Jœ(s4ÉfáNs̳)HP¡CB‡(sB‡'(På d§(Sd”áfP¤)HS3%3%%P¦frJd¤¡IB’…“9C)3ÿI)BJd¥0¥ ”Ìå ÌùLžPæÉÌÌÊaNLÉþ…&S39""ÎffPùB™™2 s4'BJaIš"(dÒzJœ”¤(fPæP°¡aB“=” ̡̜Ê% NRO2‡Â™™?@§ 9”9é(PСI”<šd¦r…“)(RS3”)3”32rS&’™,ÉCIÓ ¤™Ê¡I”æy”™IÿùC™œå¦K‡ÉIL”ÌÎPСä,¤ y™:)“)˜S&e$ùȆJ|¡aÿúaL“2z8s)&PáÌ¡œ)™’!’™)™™Be'"I432� FáL™Iç"Ì¡œ¡Êd§ $ˆR"LŸ)…ÈS3%™”8\¡IL¦™)…% 8Y(pˆRNIL%RbÏœÎd°¡¡ÿ”” Nd¡C“8e2P�!BÉœ)9CÉù)<2ÎS'ô(g&sÒtš¡áœèRp§'ÊÌç(ry…’S3Ÿ?(Y3”ÉJ“˜y’!žC% ‡<¦f™Ïþ’†„Bg%2Y’™†…%39’!“™)(dùLÌŸ”ÌÎPæ‡4)0ˆp Y� áB!3'3œá¤þ�N™™˜S<� ”ÉК¡äÐå%2„æJfp§ fd¦J@°¡NtÌÊL¤”ÈD™Â™œü¤Ì””)(S“(pˆsú¡”%3"òs(d¡LÉðÒ„ÐÉL”ÌÂ!HSÿþY”ÌÉBP,™ÏÐÍ0°ˆÉB™@³'33 dÈ�Êd¥!BÂ’!(D%&IˆdÊd§0°¡ÊJf™¡ÏB|ˆL¡3%… °¤Ë%9ÎR ÊÌ)™žS'Êp¥$çü¦fLˆLÐ,(pˆrfO 3œ¤Êa̤”É(Rs)8S“9†… OCž“"a”…48S2J"™4Ìå')“”2s3ÌÌ8S” (ÊfffLÊI”˜D8s%&…&S$Bd@¤¡IL”É)(S9š¥$å&RLÎPÎd‰0²ff|Êa™œ"™3(™Éé4<„He˜S2e%2S&’… LΓ¤¡LÂÂ……39IBP, s'ò™%!æa¡’�aLÌÂÂ!ÉÌ””Ìχ fg p¡IÌ)Éže&R~hD(L¡œ))“LÌ,Â!¡šy2k»ÿøÉ€@ÿþµÆh aœœÌÉB�¡HP¡Ê¡™™œôž…9IÏ æg332R†re ”¡É"Hy™ÊOèg?¡œò“(PÐ"LÎfaL™L2Àˆh&rÂ’„ÿþe!¤-”'"9L”ÃÌÌ)‡3¡™Â’„ÊfO”“ÉNäùó9œ§)™™…8S3%2tÃ)“Ì生)‡˜e&39C3%É9”3’Y‡)(hRP¦NaB�¡I(s)œ¡C”(|4ÉI¡)ÿèaf} 礗'IICšaò†hg™ð³3P”(y9™”’…&J˜Y„L2“9fSfe ”(J™ÏIèdèN†r™œ”ÉIB!'%™2†P¡ÉÂ…$¦M’�áBPçL”Ê…0¤¡O'BP"B„C% )�‰2…P¡¡C”�0"J”3ŸB‡3C9”¡<¡Cœ(y™Ê9<šaÏùæs3(g2‡9)Ü)™œé= @¤æe$æD2P¦IC˜hD% JJ2“ ™™(P”"% ”’™)™™Â!™™(RO&’… dòg9C% N9'Ês‘&i’™)’™)(XS0°¡L”"̦Oÿþ†eaL’‡%&He$¦ffJ%&r“ç(s9CÌÎPÎS$@ˆJ,’˜PàA B™’†Oʦdä@¤¡B“"BœÊL*"B™„C<…(S!|¤ÿèPÎLÌ¡œ”2S)“úç)ÔÂy„BP „¡B“ÉL‘„ˆPòS™™"3¡HPСäåš¡�‚™áLžI2„¡aI@°ô2’„Bg ÌÌ(Ráae á™HYBS0Ò„)“IC@) dô™fR�Ì”2R†fdð²�ä’!„²hP²äÌÎe2†Jr“Ê™)% B dáfe%™ÃЙI„C…(sÊœ"œ’äˆP”Â…‡3”9™œ”)2™)™’!Â$"&LÉùL“”’P)(PæffJf¤(D†R¤ž<ÃB†˜y…s„šd³8R„Ê“B‡2…�¨‘Ì”¤žP¤ÊO9À°¡Î†sC”„C… Ê44,,"2“¡I˜„ÊJfså3 J2S39ÂÉ”9œÎg(Rs”,Ï(rs„C’^SŸ”̡ aN!@°ç(O…)33™”8Pð� ç)0¤ä¡I”<”Ìßèr’’…&hRrS&†fg(hr„¡™C)�³$C2“ ̦”&†xe!Ì)’œ"LÿȆJPÎC”””(s4ž’‡"ˆa¦JfM0”2P)Â�IO”ÃOC”)9…3$¤™“32S&!“œ„I„C38Y”"(r’…“9ÎdˆL¤é‡’™"ÊC:B‡&dœÉá<“Ñ…”2PÉC'Ê™1 ”ÌÌ)(Rs332S’!“ÃÌ)2……8S%3(s?)™Í Na¤é4(ry)’Ì<ÉLÎsœ,™™™…&Ðæ…&S0¤¡CI…“9™Â“˜y(RR�ˆX B!(D%(r�Ê% L¡)Î&%Ì“ä‰À‰(R|¤¡0‰2e!Ð"BœÌÌÌšN†só8P§ p°ˆJH„¡aNÉ”æPáœÎPó'þ†p¦OÊJ(PáB“,Îe$üüå$¡IžP¡I…3™”8D32rS$C0êàÿøÉ­@µÆà!™”’S NaLÉ”””2P¤ú愞ffJffR¡“™)’” °“C9¦M% L¤¡Êô8D4(y:”3˜D9)(… dä¡IÌ”ç,"†PÃáèffd”™ÌæÌ̤Â!Â!ÉB“?¡œÊL¤œ¤(D�¤òyI@¤"%2ä,¡Ïò“4r††S <§2”‡C9IB˜s>‡‡&PÍIÓ �L™ÌÌÉC@ˆJaN¡œ<¦OÊI"%†NJJfd¦aœÊdô J„I2„Ð)ÙÌÌÌÌ¡IÌŸ?”Ì"ÉB„ÎI RPÐÏ 2D2S$C%2D&D'2†rs9…9?”ÌŸ)…8PÌÉžg9þ‡(frP‰ áLÌšL‚H�¥&S2„¡”(i’™œÊ™C™å L̤’&INJRBÊáÏC”)2“ÐÌ¡ÉBR�²’…'0§ s“?þe$.Oò™:%<°¤¡= ó@¡"gÊdùNt8D‡¤)Ê8r’�¥%% Ì)œ(S&SR B$2!“™”9‡3LÎd¦B$ÂÊfp¡¡B™)œ¡¡9“9žP§ 38P,¡LÌœÃL”ÌÎPæg(s™ÌÿÐÉC9B…% Jaʇ †™†RIL)“™…8S…3’DÉò™3”% JJáB$2„óúJfp§&r‡% B”’˜S‡å9Ó%$@ЈJPÎ L”šLˆp¡ÊJ™C2e39IB™)™’™4ÃÉLÊÊ2f} ”3(s4ž“èd¡’„ÊO)™™œý æ… �ˆO0òNg”)0ˆP”Ï„Lœ™™™™˜P¤Ï!32Ri(Rs% !Iœ3ž„ÐÉC””)2†Ra&RRD 2S'C 3B’‡"¡9@ˆs(p‚!N¤¡L„@°§”ɔÙ̡œœ¦g†rN�Iå0Í …'(På ó”%™")™œå&s„@°¤þ†Re&…!C”�$ˆd¡Êœ)™™œ¦eæH’aá‘&s™”9ùLœË æffJp¡I™¡œ‘ žP²e2S9@²…33�2På ¡BD9L))’™‡“B‡3B“):)<§†rs"„B™É)“B‡2˜S…9™™)˜RgC”)“œ"(D%&PåÌ™gÒP¤šœ"…&†J(p¤¡2$…Ã90¦(S I¦f!JND H�CœÊaædÐÉC”)“)=0¦Iæe$󔜈J”3(p RgúJÎaL™IBÂ…’R†fJœ)&dÊ9’‡3œ¡ær‡(g Ê™“L<”ÌÉL”‘ ”„BP‰'>�IB‡’|¡¤¡aÿС–IÊS!L�‘„ˆD2R†p¦aI”ÃɦI<”,(sȆJ}’…†Y2’JP2D)2™4)(S' ¡œ=Ì"Í3™Ì‘“™Â D…„Ê“"(d¡œé‡ÉФ2Â…&e Iá9(p‰ “„C˜Y@²e9Iˆdä¦J”3Ÿ9I@#0ÿ‘LÌÌÌÌœ¤ô 3èg(Rf“"aäæs”™C”P,94�fNRP)3(O3ÊÊÊ”2R†JaäÒ„¥% Òzd¦På™ÉL–fs9)™™BdBNz"= ¡Â!'(Pžt(XpˆJ@‚¿ÿøÉ ª@µÆ� g™Âœ(Y%„BP‰% LÊ“(r’…2J™””9C”9Ièg(RP¤áI@³?ä@æNg)'œ)’hd¤þ†g�M!) RPˆ¤äBe'L‘É4𙡙@¤¡Bz¡L9šaLœÌ¡’‡†…2†pé%33„BP°¡I™B’”)™4ž“¦¡C™¤¡aO9C… Nd§™™™”<>dæffJ‡ô3’™™ä¡LÉNaЙ9††M!šäHICɦH†Jd¦fg$B“:ò™“æRg)2“9By)CÉ)’YРD™™IÓ†x !NC…$C9œÏ= IèJ%(r‡(e&P¦Ng9I”ÉÎs–9™œ¡C3d¡Ìú2’…%’…… dæ™IIINáfK33339B’‡2XrÂ…2rd@¡¡Ã””ÉL”š4(S2s s3339’!œÏ(Re ”9ILÌÌ)3ü§:9� =ÉÊœŸ>e$ó)3”œ²„¡C38P°§å8XD $ÊNPС̤¡C9ž… É”Ÿò™?СÌú"s&På ÎáNÉ”) ’t3…”8D2R�fS%32D2S9Ê™I)’„ÊB!C)3’Pæe$¡IOB„æL¦r’!ÉC“9™˜y4Îg30¦L¤¡Î˜y… ”)œÎg3) hÌ4ÃÌ”"C"I”“)&g3”)(RP9™Îá¦H�Ìô3Ô42PœÊaÊ&JIÊœ,"ÌáC…C–çùʆ’fJÊaIœ¤ÊdŸ2’�IÉý ffa†LæH†p‡<ÊI"9B™œ"„Be å IB’…$C'(d¥B!·(sB‡“"(Pæò“9Ìó™ÌÎPæPäÎffM0òS$B“ÏIé= ™C’‡3”’„@å 8yIš33&@Éažç)3”™B“%2t3”9ò˜e%! D9Êg‡' J32†Jd¦Jpˆs')'BdC'2e&$Î)’™˜D8YùÊIò™I<”Ì”ÈD˜S2”ÂY„BP¡äô…9,"…2e ¦¡BS…%3(JfdˆP”"(g&†L¦Id¡f'B�ú%?èfP”“2†…g(g&d¤¡ÊÉäÙ…9œ¤ô dÌÊI¡†” RaCœ§=30ˆd¡LÂÂ’“L>JR¡áÊåB”�³3”)œÂ$Â!œ(fRe339…2e$@¤¤ÂÂ…'% J™¡™Â!HR‡:aNe Lü¡I…3 ¡š” :4 P™@æS8SœˆPæpòP¤ÊJœÉI2RP¤æfxÐЧ'(PÍ ó”8D’†�aI8P¤ÊJÿB~faÍ !BS”Ìå% ')ÀŒ’YÊp¡¦S0¤Ì¤Êfe áùLÎhS9™”&D…)…!Jdÿ)’‡‡@³))“L)ÉLÎt(rfJ%œÌΡ’…%% L¤¡I”ÉÉáNPáær“”9™˜RaáC9”Ì� áI”)†Xf“‘ œ¦fsÿÐòPˆ)¡Cœ(J|ù”8RD%(y<¦dç30ÒP²adšaL%Ã<ŸC'å%Â…†C%))™)"™ÎPæK˜D˜YC˜D8P§B@­ýÿøy CÔ@µÇ(©i*”´¥¥-*ZUd«(´¥-IKDÊJYeDÂÒÊRË*YJ”¨µ¢©KQT¢ÒÉ•)ZXš,µ%,©(¹)QjJZ”©IjRL¨šRÒªT²¥)K(­%rWJV*X©bÊ‹R–T¢ä¢å)R‹JVT¬´¥©J–RÒKQj‹R•µ*KRZÉU%©-EI‹E­*¬©U’T¤˜š-,©Jª\²Ub¥‹KJZ-eKZJÔ––¤©¤‰ªER‹‹I”–´L´ZÊR¥©–Tµ,–RRÔ’Ò•-*²Ò–•YJ‰”¥%“%JK%T©eIeJR¥%–”\´²©,´²Ô¥%©.-,¸²Ô•”´«J\YZ¤ÑeJª¬¥JªURÕ*,¤²•,´¨µ%I2’Ô¥)--IjR’Ô–YQKR#)-U•*©2•Ee¤Ée¥+RZ¨µIJ¢eJK*Y*²ÒU%eJªªª¬¨š,–+,©)J‹TZ¥)e%”¬¨šYRËRT¤´«,¬µ*&I‰”¨¥ÉZ¢eeKRU*É+)JZJ¢Ê–TªÑk*R´²µ)R¢å*ZX¨šQ5"êT²Ê”¤ÉdÑKJYQ4¥R©eJT²¤¥¥-RZÒU(¸­JRL¤©EKK*’­,©ieRZ’Ô¥)R•-%R•*Yqbhµ”´•IZ’Õ)R¥–”¥©)2’–)&II’ɢʕ&QYKR”©U•,¥J«)j*Yh²¥V•¨µ%IeDÊRR¥JªUTµ)QiUJ¬’Ô”¥¤“IjJL¤µ¥¥¥•+)Q2”¨˜ª¢É•Y*¥e)iEÉe¢©JR¥)J‰•**R–’ªUU–\¤©eIJQieÊRÒR”¢Ô\YrTL©JRÔT¥”¨˜´²²Ò¥(™(µ\Z”¥KR©+K-%K%”–”™iIeIIeJÊ¢•)j•V¢–”µJ-J²U”©UK.)T²¥UU”–T\²´µEÄÅ¥R•,ªJÒ¬¥J´«J´¬´±kE,¥%-)UK-*IU)U*LZYUKJ”©R•JT¥)&J–*TT«QK)--QrÊ–R’–R¥,¸¥ÉU,©JZJ©eÅ‹R¤\¢âbÑ2¢eE©E¥*²’Ê•ZYRÒ¬¥”¬«,²T”¥)R‹’Z”R¨¥RZZZ”©e))UeK*Š.J-JK&’”¥¬Z¢¥¥*T\L©KR‹”Z¢eEe%KJ––-QKIU+KTªË*RËK,©JZ’Z’«)*T¥JZKRVJLZQ4YyU¥VYIjRÑe©)j,´¥JR–’–”\”¥)IjKR”¥*R¥)JR”¤µ(µEdÉdÉT¢Õ%ZJ¢–’¥–”µ%©--Dµ%©e*Qr•”¬¥K)JŠ–”¥”––\&T’«*-IR”¥JU*Yh¥¨€q¦beetbox-beets-00724b7/test/rsrc/empty.dsf0000664000175000017500000001013415253035401017636 0ustar pieterpieterDSD \fmt 4+data beetbox-beets-00724b7/test/rsrc/whitenoise.mp30000664000175000017500000004032015253035401020601 0ustar pieterpieterID3FTXXXCommentProcessed by SoXTSSELavf60.3.100ÿûTÀInfoU@€  #&&),/2588;>ADGGJMPSVYY\_behkknqtwzz}€‚…ˆ‹‹Ž‘”—š�� £¦©¬¬¯²µ¸»¾¾ÁÄÇÊÍÐÐÓÖÙÜßßâåèëîññô÷úýÿLavc60.3.$@@€íŒ{sÿûTÄs”p²w `t‚]�à@Ͱ†| cÊ:Á÷ñ!Áð~ ƒáÿn°~\'ßåz9wø sÊàþ ƒð@Áû¶Ú]´ÚidqÆšE’@ÅÑÁx-žM3’d NŸ ûyYNäiV’�¬^Sb¡Õ­pðôwØÿš�ó!ô’�X$*ËZ€l͇>Áp²„Ó²åX²ouöÿÿþÕº™·ˆeKm’ L¶ÂÿûTÄ TM�üñ€O�±|Æ (\¤’¶qC.‡Á³4 A��:ú!7cƒ… �e�\ “‡Ê‡ƒ®BE„ÆEMâUÌ„X! 1’·­*ëf‡ÿ¡þ�MUTD9ªÇD€‚xR?�#‹Ã!L {Eæe{sÕÖlûšÜ#h*MДÎR‚1˜& H!†B–••¹¢âŠKš�2WïÀ5© Š7eÈ£îW³Øîµ˜™•ucGjMáü@\~"ÿûTÄ ¸«‹æiÁZ‹ñ¼ö( ‡%…‚„ ™ãOT-õü1vÙÚa¬ Iv+ €dÄiÈ/�·§ègÖV{%AõŽŸ®ç 9LI`L0® @M2E@¦i“ÅŒYSíߤFH¤’Îl>Å�2±å¢˜ÓçŒ5�w~‹¥ŸóKy¦ ¿ôÌÅCº%I$q œb'4’ÔŽ¾>�%ôÏ`g:‹k¼0@¹‹ ˆ¡p<¹hM@„*õ(L*h9[Q›/$(ƼµL³Ý{êKR‹ÛR=5l©•ge>åêÂ:ÒÐ;—‹˜¬èÉÿûTÄ € @c‰Ç°c�C‘ò<ö ¨ZgÌQ¬�TM:®™Óì�Œ¶Á$Q� 88‚+:ã�&.ÇRÏ(ž4{,]=izî‚lïJ é÷1èÌÊÆ‰V[d�”MD@E��t Bû§£ùÀû˜`À›wxˆhì»G6"χ;Ò+ž ŒönÆ\M#ë@ì2ÁÀ¢9i¶ûôÑqqK®¡_ÿÒ»ÛªšxK$l¢pA©)™–˜,2vx(2lIÐ"ÿûTÄ€ u‘æ$l�(�r|ÀŠXiÑ[E[(–|úPŒ›‘™9½È:Þçƒö©çn*°¸öôÓò¨ú¬³UŸ]æ]USÊY$m  GÀ”°8…B Ù‚y8KLñhôψùµô"8‹P•¢™Is­÷ñyãdÅØ5JEŒœÄ¯xP/íQ5=»Zš¬ê¾ª—‰‡gml‘c°�T¼Rp„ Í…˜y~H„œ’kNMkñIñ£ÓëßýHÚ4+I „ÿûTÄ€ P•­æjñ r<Æ(á@DÉ=¹˜�eßóú~û›Ú™‡V•¶Ò óDƒ2€ É$Àd©*�ÑF¡šÑеz(B,ã"Ã^ö›@ÑâƒEì8Ä%!æBÕ¬êØÝ êCÓ­WÅú9ªiVedC+ªP1U‚Ìd9!!/ÅF†ÈÀÊ¡=ƒ…UZ™ž€##Àw€cÇ­÷T¡ hí‚d–ùœ×ÍnÛ\•æÿ/«{èíÝÔËÃÿûTÄ'€ TM‘ǤhÙ&ò<Ä™»kl�« <}ððôÌ:m£Š šöÈ�™mzÒï¢tPyCã@ œJ”5·´ak� ‹‡^¥Ðsþ­[z×õÇUξ™x†I\iç™>Q‰ø¿‹M�,2…ÚiÆù{�2 ñö+’’f�ÝáJ¥ ‘�.M'��S”8íépF·Ní§ÝM•þ¿\34+2¡Ç#m ãu¹ LÔá‚HX™jŒXv MÿûTÄ2€ 4w�ç¤gA.3|ô�ŠÌc•n–©‚Yº¦~ 'O÷ìÄÎÉäz|št¼%‡E¥Ø*8¨€�öB}Ÿ‹*ùœ»˜vKli$ÎW´°$C­!›< ›à'0Â&‰ -�¥3è·?rÙ¼Q7 9Lž%ººòI‘m®Ë[øºû¿RUÓW•SÖHÚ ‹À²ò5Ž¡©ÑØŒM,¬ˆkÒS’5ÐrE� ‚I"ÿûTÄ= q‘ì$hÁ,†²<ÃÈIKG#$‘iu¬rž¹ó½ZÛÿýœU‹ëê‰Þ˜t],i¢ ä#á[[‹ËÁÈô`°)Z–;ó …P¨-çïZ()cŽ ‹ —¹$pJ§,»J ¨@P«å,°I—Zû>˜w‡…TE� @4Ž càä$BX|`®%¨²ÏÇÈc€NHð*RjzNxäJó -8Ô€’‡nü{Õ�ýÒ¿¸-gÿûTÄH€ Pi‘æj�.�1<ÄŒà‹×ÝâôU¨©Š‰uWm�øCEA¤xP=6t` 0búVy8½Â콪ÜX LÃbf‡Ø�Øs&ˆhµ..Ö¢ŸJ¿TçúÿÝWY2ì†R�ÃX@@P8øˆ€ÒÕ°é– àá@E‡`àIèYdÑÌ$ƒ‚w%ÏÃl„ÆZ"í uhK,}ý•ÇMl½Žô*ÞÍÊ»‡kmL€!Ø"ÿûTÄR€ \S�ælÁ1ñx¶ 0;"ˆ¬DheuÃs& m3j5%¾ù=4ÍÉxrY4½Â¤Âã�4 6¦¢‘d&�M�U^MMÄ3ªHÛh€GÆKC� yD(5Lt[`ñU£fÇ xí"#jd®ü›�K¦R)¬¿rÉ­R ø¹¤2ˆ}ö†ƒJZ†×ûµý¿Ûÿ÷"¨ˆVfD?–@ƒ¸ötNIB„ (¸ix©˜PÒV€08ÿûTÄ\ k—æ$h¡0’qüö 8àÒÂ#(Ã}æ’â*Zkw½yÈ«Vf£¦¸oØ÷u‹÷ø¦þÄa ͺ«–vÓ[ ^SŠU sÑ ’•Ô¡…b‡ †@Ì ë!íhŠ�á@¤DÁñ@²É��ˆˆ¢ÀäÔ6 ù;Å�ìF¸�ä,5"¯Õœìʸui,�’TûYm2‰*Y5éQª¥r…0CeEjwJJVK ®¤h~tÜñӫב¢XšpûÿûTÄg P9‹Æ$fÁ1‹r|Ä�€aòÏýÏ/W^Le%¦’.ªâ‰þ[×Ú¿îÚ»»©Ek$‘¢qUˆ¤òÐð;¡bðü¨lh¹b“oN!!¡�〄C :…”"Ô :LB§Qh"@‚�9ñK rC—SW”ÿ¡™Ê‰–EnêP¹‚� ÃÓâ8´–:é% èăZ%;ç!í›5}¢:j‡ÒKïíO3NÏTÞ­åM³¶„ƒlµ=RBÈ»éÿûTÄq àÏ‘ç˜lÁ#²|À�ÀשT¾}¼šÌÎL´E"§ÝH �@nŦX‘¨IDÁ.ä±)â´,A¿}“ ™&*q¢Èq€„>ui*Ä­?¬L]ó&V<Û(°ƒŒHø¦ÿ÷} ±GŠ*i›wf2:™B8Ü~`gdçe䮡:XgVm›("Ÿº7`Œ:ÔL´¦]­Â�õkÓ…”ÊQîZ‚‘•!¬zÒA/[T–C­ÿûTÄz€ D¹‹ÆlÁXqxÆ xôíi6Qµ›&¦aU«¤ã�Š„IÁ0ôÀx”L (–BòoµÁwTi–¹ÍIs)öþæÙR£õN!YöIK…¡È56]`h€©V‹3ì·SK>åÌÑWÑÜ™œ¥U[$h�o bÁ0:*�Œ #�¢u‚9سv\ƒL”…J%s1OàMfÔ,4 Ć ›´+ ûR²/©*;è8ÅÄ�)ÿûTÄ{€ 赇Æ0aÁN“qxà �Õ¯»÷ToV]Ëij²XâHz ©¾x®MôÒUIè E& W+\XõÆïÓW9“ƒØyÀ661'Ã�+FóÎûgÙ]\³<ËÔózw�ÚÕñ`*Š�d{&+îäªý=7uöª¬¨V†TTâD€‡7p>-¶CË#hX*ÊP[UQ‡¬SÑ�nFéªÛ<Ô“”‚˜b°µb8æ Ô(-qðö�gÙ®-»wÿûTÄ{€ TM�ç°aAf±|ö øêKlîFfÕLK™ÛZI"¢Ô‡¬DŦÊHcù™—–XIýïzÏ'æQ¨¦ÃŠbè¦^4QÄ,bmç %ÁPz+z»ñu´78Iƒãìb޳¿êš¹yˆBYH� cˆH®UØ–›P’v²-‰h7ˆpSÚ^®æÓ ”;½�ëœÂd”zšm"â-jB±v¹|bóßF¯_j=”ÃÌC³*­‘ÿûTÄz€ Ôk‹ç¤cÁMŒ±üö0¶Ð77á—‚J�Ð øC$‘ÒàtêYç† D£Ü¯¬ÖŽ&]ܵ_Dæ³µpªEPTjØløØóNjK¸±­uº«ê»ºš¦M,qV+®Ìä¯$GÉ¢i!�'— †F8Ñ–5u’È‚Œé HÍ!<ãa`hJzdT˜@$Æ „A÷]æa ?®µ2®©›™™eD±¢‘™ªK„£7ÑÔਠÿûTÄ „c�ænA/�3½†¢8.Wa–šn.T ]£Ït ˆ:#ÀENšÅ�“¨€æ2µB*j&TýÊ·Nû–ŽÿôUªìª¤fIdM’ ” �àáø7?$ ‡’›0WP) #¨Z}Ž0ƒH£I¡SQV�Kå­&¨�‡&8Y–$ìÇn‡+£NÏBò²¦e™RÈÛDÞs*ú.+(ã…ŬitZ‘VÜûiDA}›ž˜ÉjPÿûTĈ€ �i‘ç°i2б¼ö xt"~¡ áÅÅá!ñ¡ïIp*G¥Ê’u‘—½ßOîÿþµhdeTB*©�U•#ìÄ6ŒWh°¸E‚TbY«˜�Â:颖¬Z–ÑŸ\ÜãæfÛ¨1SB)¹“i˜Dr�¥ °²…�`²ámÂëîzªêaâ8Ú ¼s�p¾î‡£Ö.KÂBTDë�|…ŽªéžäŸ S(¤6.À�/rd„A×Q© -ÎʦÿûTÄ‘ h[�æ A) ±üô� þ½©®åUìo'¿Ñr›¸¹§TI"h€mVeŶŸ=â¡H$&ñ$ˆu,†¼v\ÞÔ­Ïy[¦¤ðèhp©vC̾Ñ‘y Y‚ݵÅÿ«×S::þºº¹™ˆD®FÑAzÜM”j#‚‡L4B=ÉѤ‡<;y{ωŸQBpÀÊ[¬Kä ÅÒÇ�i3ë}6lj[¡µoîVêuÔïýu̪¹hf7"iÿûTÄ›€ ˆ›�ǰg1Œ1¼ö p¢ ÂÐðK¤Â“Ðn$@L0‰TI�zý}!-«êªNl�¹E –iò&Ò]aÅ! #’Âq9ñª…ªxÂx4Šœ»òÊüÕ¨Ûv]TÌÌ!ÆÚI@Éù–ƒäÂD”xð¼À�¨ŸÃ±Læ}s'ixg\‹_3p`éSÅ †„r'ç¶Áã‡\²&ã�`pŽe­RFÚÿêÊʉffHÛI I(ˆ’óÕ ? Ë&ÿûTĤ€ P_�æ<ÁA+‰2<ô™@ULL+·cÖàôdâF³¾Ç©5ßmIYÚÂ"ªêÅdíó?ÞwS‰‡3§ùèe;Ïò|Õèm`4t{>®Ç¿’¸ª¨š…;H€ñX¤œƒAØ|"BqqªØ�&·²­:�cgnïHþ廸`ûF�Òóihp`¨}ÅÏ™Ú+(ùwjoß÷}[ï]·}YE¨™™xT%D Àhr†ð€ § ŸT¼X«*¾ì5ÿûTį Ôa�ç°cÁ=�1¼ö à”jmå$S:2 æ ƒÄ® F €À ,©õX?!k]M1k?ûR‹m³úýoK™¦!�Ù•Q$m¶�&ÄèWÉÊe†YÝ*ª�êø›„ íJï|Äà Ñ]ŽÁ4âê�H°UŒ‹¸€õ°PÕbÊ ª ƒ$Ýö ]õõqEªªÈ†u[#I ‚Ò°Å«ƒ²¡Ñ<’m.`�f¢b˜Bõ«”ò°M7¼†´BÿûTĵ€ á�ç˜l�: q¼Ã È0ù2Æ@_•˜ö©ï"÷ÅÕ½ 6Úb l¦d!HÍÖ%^ôÿ©›/:òba–mbi˜á-£õ:XL¤,¥<DeXËBÖ“0nôª0¨fœ¦ºrrÚ5ióѵ ›È’ ÐÚ6Ò QÄ’~‚Ä:¬m5ò(ëc¿¥Ê©™¸v8ëd’ Å!$~ˆZ†è%*i'�aiÅ w·}¸ä*dgô)*˜¡.‚ÐóÿûTÄ» ¸[‹ær; ó|ó ’Âà„¢¢ÇD¡ë*Z˜íc¹MÇl;OñìŸßu•tò̶ÆÒ$'D5}LVÌDZ`�jY¡ÓŒÒH;Q*|Lš‘Ùž],h’—ÅÀÁƒ Ac1¢�r‚Ó(BÈR:…š!R×}:ÿÝ죪ßé˪ª©vkd‘$PØ}¤Bˆø<¯—ŠªBRÁ‰Íd;$pyÒsAf”iãdyl¹èì0¹"<ù€9âBpؘÿûTÄ H‹�æmJ2<öP&Ü|a–Z,?EÒš/?÷å/b¦æ’¸ÚL€‡¤‚!@íéÀ�øz4tGy‚ë¿�·7# á® &…lE• X M�U'@©c<(KR ¡OK“zë%‰ÀLÉŸÙK¸�ÿþŪ§yx†T–ñrc™up¬ô³@?&5ZÛìÝ2_¯ƒCC„1½ï„̴̾J‰†Cèœ~G[ioeoé n»ÿûTÄÅ k�ç°l�<ŒqüöhSQûß&ÿKUSYî•8’@€`x=¦…À'ˆ£éh¬W=rätHÖ�¨9ʲÏBÍ4͙ѱ��ði,#‰ ØM�Ð#ƒaùái NU,Xª¨½ß¿¯îÝôUïí̺xkc$àZÇÁ3F‘¡YáXº²S,˜Ds#w§ù‰ HPõ ‘6æËX°›¯c� ñõ(¾ö)V£mMMÓOÿûTÄÊ€ (w‘æ0aÁG�qüö 8=SÛ\K1šDH^àÑQÁ:ÃC Ó:(êÝ�»^Ò±£…(¢G<ˆô†ÓEIJ 4]âz«‚ÒûÜõK¾âš[ŠPÊîæä`wM·úU›­x†„HÚDr¨%0.fS|I!%9‘в:–Ù¤½X¥Ì2y¸wRˆ‰2˜ Xë’ˬQ(m´ë‹%ž>ƒ/Dm|u™ß×^¹¹É§‰–bÿûTÄÎ ÜY‰Ç°aÁU1¼Æ xº”GA|\4’" ú¤–ø€¥Q]BÓ¶0DÝq'áPpL\ x‹�¸ª‹><…bÐêa—±oŸBš[Ð,˜ôVw9ö¨³ÿú¼™¸—fJš@"ÌbØL�åYÔ�=Õ”^D³¢D&4¨bRhéèöŠ ¸|ذæ½Ó¶¦Eеæ ùBÐñÅ„’[Œ¨² Ù+bÿ[i}(þ̾_úê«©¬wTWcl€ÀÌè r(Tz~"q˜™„ÂÅ fXÀƒ‚ æ !Zd(� ¶8L¬ÐÔ‹ÊFXx„ %‡¹£jc'[_÷9íë½×ßïU\ÜÔú8ãI¢ÑÌ(#)'�r Þp„á\¬œé‹@)ÿûTÄÖ Y‹ælÁMˆqx¶ 8M >ÿUªxDŒäƒ�:q�"v| ÀG8ƒì½é¸ƒÍC)´œm¥¨]»þbÊ«ÚxvtO©@Œ8 ,Brħ2*ó�ÐX�’„©ªênb,GÌ·ÇF :`ÎØ¦#¼ÞRÉDQT ¾tU"%³Cƒ†]§›©«0—lyŸ|ÒÆ!*yõi¼uÝULº±§H‚Qí¤—4šÅÞ-vä‡�)„ÈR§‡$‰ÓÇHÆÿûTÄÙ€ @=�ǼÁA11¼Ã ˜DoX«/^®ÜA P`p94y‚§ÓÃdHÀg˜.ÃÁd�j•ø½讽ˆá·®ÄÕ˜i·sC/¥€Q àè\ÉØ8 ‹z,>TÏ¥‚ÌAWØàÏèÁ‚�a*Jr‘:\K´´8aBÃRæ9h]ã�@ œh»l5”´ýè¸J SI0ƒÓa ’“Ý!;³S.®‘¦’ Áù †@Øu  ÌÇò22ÙåÿûTÄ〠‰�æ$jA/бü¶ 8 q)O§`0±d¤�‚‹Á…%OŠ­ qd-&.ÜFÒ¬^ïªsõÿ·Z©˜—htK¡YU¼KœÇyÌMš`AÉ  ‰é N OmŒó»ºsfš ‹¡a@è,CÂy@ËÜð’CcÝ4›whk÷Y-[TúLÓ[ŠÎq‹ H�eLT˳¡üÊ, K@€Ä€€aÜž9 Ås¿³Çè?¬¿xÚ�ÞúÿûTÄê€ T—‰Ç¤j�R ñ¼ó ��2E¤ÁYàA`и©âÌ#2xÛ\–Á‚îS­ZÌbÏQZQzlM-‚Ó÷ìªÀ5,ŽÉUɹ‰˜d/ꀒâ©8ÑÖl3¢xü QQ™\˜rs#ª±l[›HÞèL.}«†Ü°91@pî1U,Á*\—jǵö-¥Òýž¥—UÐŒ’jííáÝ Ä‹‚lNFÂ~+i¥ä,žœ¬Ì«r^<^ hÿûTÄè |ƒ‡Ç°aÁ#1üÆ 0 É�A:ì%: œ#Ú6^Eš'ΜÏ>`È�³Lm›yCµ4búŸEksDÌ;Ò´'a‘¹…‡†gveI#�¤Ĉ„—ÄZ\MÍ[Ç‚¹™ÿ-]KÏ@$‹]�Î…:¨¦òƒQ"&à¢I&N±ëD L•À( cµñ¨èõDÓ»³2T€ O^(щÃÁ!ÇM�d¤§G�lQ¹EŽÄhÄW"ÿûTÄë 4Y‡Ç¤ÈÁb 18ÀŽ@ó÷¢ÝÍ™UT†ƒ… œ e˜Ób¹[Ĭ…€Ž}ÛT ¬]Ÿ-K ¨‰y¥¦U±×ª™Š¨‡d8ÛH€ â…¡¦‹X[�$t\]Ξ!Y90²Z´DŒ�[†K3÷¢�²±�O¼ûat´8piæˆÃQçå÷�Þ¼´�ÝVA=R5t]ÔÌÌ;�´I ò( ¨„¤GD"9T>“ Æ_HÜÿûTÄç ÈU‹Ç°eAa±|ö fÌí¾%˜ê àðé‹4%*¡)¢ ¸¨()\“èzÄO6uñ•¯›^úü¿§ïÿä—¾—‹f–U7D�cË«€`3<#2Z>(* “˜‚“2Ü£áYˆâÆ Ç–û˜fÜ©~ЍVC½Gœ6Ìÿñ÷39¼ËæEub *E͉±…—>œ�*,¡‚Üv”¾ Û™)Io4æ„_Ò4%�pà>¦âJœˆ1uÿûTÄå dc�ç°cÑtðøôŒà[fD‰g =8uhÎÁâF¦šY†B‚éò76ÃÊŽ&ð“ ܽ|ïÆ�¨zɻϴ"1ޝU˺əwmc­Få‘çÈ´« 44å;Æ‹ð=u˵%É›eÞH$Á g�“³—$gÖó(ôõˆ¡† …J…ܲ%Š6Ç©‹»²¿ÿÿ¥ ±�552ôê‹tȆ�Ô8J³À ‡„ƒBY¡�ÉIW×Ö#uö[ÿûTÄæ ¤¥‹ç°gJ‹1¼ö x·»×uDì™E¯FÌ—'…þ´¯yŒ�±s¡¢+—(d†,nûN…ªöM)N¼·ªÉö�¹õªuªªx–EKµÁq˜v˜)I‘Øö˜„Id*l÷u£G !zË3aÉçJ¡º®qƒý¥Dì*’ÕÞÖñºœÐpõŒ¯u“µÕžê½õ;Ö¿¨È§vRú¡Ä¡hÛ7Q¶k+È''€™L¾©Œ$–1çÿûTÄç€ üÙ‡æmAA 18Ä�õÒ¬Ý ÄæŒ˜~15È–äRã97 ¦Ñhà�JiIÅñ­ZòŽ’rïÙ½Ïy¶Huâµ°¤`º¬©˜Šv[,m qÅ�¶â<¬¼@<*—Lœ0+R«–·gÔØÕ-T‹rÊ�0tðé Xýàfc€ÀqrdÝMkm,b˼²ëëÑJ;=U.ïƃL€„¦:ÍÖCÜÝN¡Aú°´°<<_K-€Å°…½%ÿûTÄä€ Ì™‘ç¤iq“ñ8ö ¸"¹�¶+v‡Q Ì„d  8s¶�;Qr»Lw¾‹+¿~¾ç‘ÚFéÔŽ…¥ÑQj\v<Hæ‹ÖY–ºm5 ­ã)»»ºº¦d�´�((æŠMÁ¹›Ç„‹$æ�@%SSÇk²NI9C$ŸÍ}ƒù˜œ(ÀØ(x€Yï* ÖÛ*RLc�½CëJ©�h"¯ûÚô*næ#m²@/é^ð|"‘÷O(˜Óc‡ÿûTÄä€ ðw‰Æ$lAd�ñ9– è(RS¶<Ó¯¸½ ÈW[Ré³1ŽDw1.Ð@*ÐÁh¶ˆ³‰²âäµO5iÿížOõUººx—vXäMã”Ê2Q‚TTs¥ý0°ð³Ñ¢…ÛJqX�VY[ ôS8FÊœ®á�oLh£Ê� X@Š ‡VÔ¹ÆÐýßîwOm?뙉ªWrFUD0à† ƒtü#)Ž‘�“®5$€’Ói‚ŠÎfJÿûTÄå€ c�ç°cÁޤ°¸ñŠ0ë¸M”ÛË0Y#ššÌ²Ecþ‘d…güš ‘íM«(ã–¤éÕY ´Ç›Ybg  ÍŽõµ'³îJ›º�ˆb_ú�CŒ†!ëXE!©Á°µ@ØÐPÔ\oŒbG0ÌiHH —Ç,¦)€cDëÖŠ†à1Â×<€è0i“$Xç^ÚÕÛôÿú™îMÎÿTÙ$òˆFâA‘¡®=Bk{ލ¨:U`û—j{©XµS°×ÅníÿkñÛ}xñ«ýô¨¥Å ¡Ø•q‘®5¨&ÿûTÄä€  {�ç°eAr–0øÃ ÐâæT·ø¡Ä5„¶š>¬Q µô6)tË/ÌŒ¿¾`ÓÏmr#88y#Ãï*'ebè.•ãf×>3¡6ýÿújÚ»›vd8šH€ #y Öš'Œ\u=WPëêD¨ÒbI}óÞ“÷:§9Êðè{B�@'áä“"‡•I!bôJ}=rX¨Þ�¿o}¢ª%â]Ôú”V�`Í@D Á¡©jÅå¢ ŽZZW�£¸‰ÿûTÄå Te�Ǥj�€šðøô�P*æ RµsË0¥íGØË78¾“ý¦§S%?(ow"”ºÔ�s&>e*0‘•Lˆ Ì…c€q]ËSж‡*Þ««§†mdŽ4˜ fÂ1±0�â1ŒeE–û/…k*dC>� �£ ?(¯ÝÃEå|Í;þ¬ìÛÓ?a÷ÎÉØñßî¹î�Þÿ­»W“.ì²H𠂍F�%`Å!(i; ÛI Ë*ÿûTÄá ,]‹ç°cÁO–ñ¸ö °:ÞRSÞÊcõ‰“«“D­ aXé• ‹Œ,ÂcÀnW?cTßßwÿöþýu™ŠˆxS(™$iÀˆ„#‰á}qBlQRyá8žãVêPŠóíæLÉ‘~^îÛØPwǵÎÏÛ8̯"C�òúŽßŸ�×ÿüœ-kÍÚ<¿7¯½z+ùÛm;^Þ¯æ?Ù«š›–uG#I({ŽDêÒó¤ŠC,/ˆG(®‚–ÜpÿûTÄ〠ø…‹ç°c�r°øö 8J ´ãNy:(…±ÁÂ0‹Ê.öI »"yzÔ%VÊËѱ[z:¿Ç¡ÿéúÕÊ�ˆwt7$€¨—'(/È�uÔú5[výÐKƒ,ãW‡² L›¨UËü$Qá‘&€è !arÁtZ)´¼(#Äé6 …Ž‚Î,ö,Qö·ÍKu À‘D»JEµº× RbfiÖÜiŽ`*ÔÓ9Pý<À�,A2ÍÿûTĆÜK“æ0aÉ*±üÄ�P’2 *ø2t,ÔÐÊZ ߤtX ƒN (&.“ŒdÃQ~<¯™ÜÅhýt»Gm­GÌéû*ºš·†g[D€p¨q KãèÁqäxÑÌOlrE‘@,z¡Þ,‰"Ð9 •ÞÞô‰+1BK‚@H6C�šèjl‡¥ÛŸ{£tw(åj¾‹om=kbzê¦naMF’ P !ëC�LÔ  '*¸¨…¬¦}Ì+dÿûTÄë ‡æOI1 ±¼ö àÞhO¥ C‹ô„¤@WcCÕ¾ö`‚Ä‚­žñq8aÃÚ<úÚ}ŽSY´Q,!¥WØÓWŠ}n“-(±øÚ«™ºˆTY�O5yØ6Ëb²ÐÜé1˜€‘bê|†B•Éåc›ŸÊ­µLüéÒ>VÌñÌåÒæ.|\ áVŸp¹ ¯Æ&ôûYwû¿ºÕ0mÌÔÌÙØÑ$€)3¯ˆqÃ’@±`' .Nå�åŒÿûTÄê X[‡ì<ÁA=Œq|ô�XÄ­v [ì`ÁV¦&Æ€‚ë‘C�Œhç†HÉÏpd:€;c\¬ ~^é¾ÄoWW×ÿGM¦©ŠwE.¥€IÚÕåÌÐ=ŒCƒ*tr=Š›`a™; #:›‘г›Õ~`�¹‘1ß-ŒVæù'ÚdfD06*‘ÀºsŽ:I©…ÁÌx«-]ÐÎê:(IP¨óJ lÔA*ˬº™šu–6Ñ Á6Lå(Æ/ÇëaœŸF¡ñ“ç3*�ÿûTÄæ ¨q‹æmAqñ<Æ xÿ$�û‰“$ Ë,.!õU¡•bN–×¥)]%—Š À˜xABQÚ}îzµq<öÏJõ*ÊÙ»—¦Ydq”ea¡(@>ƒ¬cáÂ%(M6è„õŸ~…)ïTÆV²/ØDPÁJOis²µÕÍùµŒHád©¬v]¢s6¿w}S>Úk®nbØÌ¦•ò ƒìV”„PéÀ¹±r´fæK\¸ÝÎ*3`òIÿûTĆԑ�ç°cA< ñ|ÄŒàtÏ•—³$K{ºe€(Í£5@‹�›b$·;¿Jæïz<1/͆ý_ýwÿéw¿^׿Ìv긚š†U>º�:RjsÜÎW²‹¼ø¨INKIÁh¬NÏ À3âTŸ ¢†­‡!e5’²à,x„ê­ñIM‡ Ö&ÚåT¦Qݧc_oB6!š)œÎ–P̉ÂÁÒ€dDXQ¸r�Ð$¾·\GGLPª`ÆáYÑ©ÿûTÄé Ð¥‡Ç˜nAJ”qüó È”8^UŠ=M‘¦QÅÕ‡ˆˆ�Hòà‰‘ÍX«Î�$ �íeí`P¸²³É$äÖæI,Y ’}¹¨›¶eISH€ I�¹®S‹ÎPÄbÁ$=B„ÁbņVu˜\4ÞaB6|‰©‘f×ʆö|,°4E!ðÀ½€!£CEŽÐÑU®®ÿ­hù[]ýFïjjÕVÈÚD`÷Ô=”“ŸçAË ¢ ޹WZl&ÿûTÄå€ ¸¡‘æ Sr °øö ¡�Ø„ÕPP4q4ˆ‚Aô VcšÈ«@ë’ V,÷ý5ôÿúéöô*¸ˆÉwc;U@™úÄa ê(œ%#«\€vx²§o¯Ç+é’Ú‚X06 «:2@L\ã¢EÅØzpD±a�!)ÜU©>›6EHcŠyR—Y®æ´²@©USS’Îì©ý*ÉETˆ'æˆ ‹ˆzddC-cH»ÿûTÄå€ ˆ3�ǰÆ�|‘pù† 8“…s}&´à– '`qìůH²¦æ¹ÃQ½çÇ=R�ZP/”§GÓ¯ýÍîUxxi”F)Ð àtø¾#�ãá�4Bò]œ�9G4#6rö¥œ1F¯Ò ĠȤP&|; *AH;Á ¸³�y±¡Ô8Údáë¬'2÷²ÑN·½§ŒARñÔË4qËxˆ†4#éP 0DH„P ô¢Fs�­í 6,EÿûTÄå ¨ƒ‹ç°e�+ˆ1üô� hA¢Èàl %° ˜ŸØ  Ä% K0âMŠ&DmM}ĈάþׯÀŠ?cµL^¶jZ•¹™¶–‡ZÛI#š 2d�Õ™($8B¬Ê˜y±�¿ÞŒ/+» ˆ§µ©¦AâüŒۈ†R*U@‡ÈdãPå<�êÎÆi’)“IÕ„Šó£Ê­³“Ñ%­qlŠRÀ-Ã{⣾Àƒè>k~²ˆCUmOªÙeô{ð�wëüÉ¿?õ}ö_à{žãÞm÷ÍÿÛæÜío°ðïÌËi�Bò‘2eµ#vÈu¤‘ÿûTÄå€ @3�ç¤Êƒ�0¸Æ 1ž]R"…“šž’§ZZXþDh«–TÉ*¾ò3=W&8Då#À� !\’«êó‹s]Mª©†vuc8$Á5.¬íæZeYc °zµôÆ«“¤9Y¬Æí��FÎ_>¡_‚”< ‹ Ó£˜äßl\di²A0À™pµöúö‘>¡YʆI¿™(w—•pꎸÚ$I„ÊT,˜)Œ„�£+€(ÊŠôÿûTÄå€ ¸G�æ$j�SŠðøó!PYÂ7*ÎvðØ…ÈEEÓ2LÈ¡®†Ea"g…˜Rõ2ª ö±­¯T�£¦—¨xgC>¥C�Äž�̈‚AI(H½¡Ñ(u[ ;†ƒªx¢�ºQݪ·@Er/†>‘Plà8À0,}®@P¦ŠÅœ545-AdgyÑTŹ |,üß•¢âòZ”Ûq¢? S¾ë Rt‰K„¶ÕŠtõo,ŽÿûTÄé€ ìK‡Ìât¦e9϶Tc��T­:1�¼è"@fLÑîÄr�ñ3bd4€ä °Ðä€Z=DÞZãU#]±ˆ¿u©ÿý²œÊªxuDQ¤�­a5ô*Ä‚5äñ\daù…�±ìGgÃËÿûTÄé€ x‰‡Æ QAa1|ö è-§L@¢qê4t•?Zƒ”p¸”ð�&K^,L° °hJàüðÓ€aȵÿ_u2Ü¢Ú…zõ©óUÚ¼¨¨eY�”!¨Òr�%€p4H2 < W”1ªÑT &1A€¹'’<™3arà ʢèÇ·oëÿ^ªxzxe2õqG–âòOÌ£åʾ“ Ÿ 2páda]�ìTÑäAJæ&,N*±±ÿûTÄå 4e‹æ0ÃAl•±|ô�0שWJ÷ÌÿžÊúš«Í³Š“ÿlZ¿úçg˻ǿÎMÌŸæ$nmS¯o~1�@“™é–Ò™‡yxDJ¥b # Ð?Ð!bÓÈÀ@�LXFýh&�B�Jïî–om$!Wr”Ä`4(¹e&k,0�Á±{jEhE-MÎlqlêMQ*¸ØòOd�êEQ3U0ˆ’4Ñ‹ð‚€8�ÀtÐÌi„f]XGBõv—ÿûTÄä �a�ç˜j�k�q|ö °OdÏg!-pZ"[ å.o™åi�`E`3c �©ðm3ÕE2vþÏíÿÿ¦Û*ЉˆwE&Y. ¶aI8ÔÇ[2€…&puL„Ë,ÊŽUj‘IçrØè �68]‡Ÿ¨ÄPȈ.$‹ ¨NqË?á׿(…¢aŽ+1f÷Ù‹{ò¨±EœaÅæ^ªbJ&�¨xˆ.Ë Ì€€ôYàè´dã Íj¸MZÿûTÄå€Ð7‘ç¤ÆÁ„Ž0¸ô�Q*•#œ—ÉtëØcw›\aM/ø‹ë߯íý1J—ç�}hÇÿßX3}ÏÎÌ^º¹Å™Ê™–dG$� õ!V�ÒèÐu¨jÁî˜I‘¶Gµ”-*¸Úg�¿c<8ˆX± »N*‚…Ø^«lµ CGz§9¡ÒŸÅÿÿ•È©º¶vi#m€ïi‚ô°*³U8 x «k•WÿûTÄä€ ™‰Å°a�m‰p¸Ã ‰aØAØÐÛ†kç†E…È AÀ“Z…B C‚Š+y‡µÏŠÏÛÐ}}ŸÙ虙Șc'R$€Lõ ;ÑÆBÁ4X¸I_uDÃ�Õ%Ü÷A²É·ÇBRêé°É“�4ž ’kÅPm '2<ðÀëÉæ…^Úû.W¹5MºSßìÓGž‰™˜wT?é9 A¹éV$ƒ7Hã`ìžX K`êŠ*¢fðÆÿûTÄ〠ÈO‹æ$ÈA} 0¸ó ™ŽaPƆ¢˜‚Á—z\T\Ù×�Aƒ†‚ (p}Só9¥WKH½ˆµg��Pªå¿gyTˆ»›–U;éB H·Šù#'%ÄzÏô„Göp9LÅÚî{Þî ]ÒÐÔ48˜!g”¿ˆ­>t l $.Õcáæ GSа‚O®>ºìÅaj¿‹^ãé¾Ç!ͼ-ÖŽ†±´I$CÃÂx £ƒ$€6&îšII:ÌÇxÿûTÄâ e‹ç¤lA< ±üô�%dN´i¶ãÖYÅ5`ÆAÊ DdÏžHâuŽayz c6œejÔ�ž¡ä»>ø¦Žìe©šˆ…E)D��zÙ8 ‡r@¢Qxä~v¦Ág¤60KâÊq·˜O¥+özU¨ˆ†wS)P%ÄÔÔ€»Pˆd•Â%ÈL©eq–ˆ&UP®OÓr„%\ÄáÎÄ1?«nÆloço¹ðýÛÝíocûÞìJ§‘?«~µ??ëø–þîµÁím-7W�2ªQ¤Pã@[ÙÄ„Â'%ܘÁN«ã±ŸöÈ{ܺJÿûTÄè <‹‰Ç˜l�? ±<à `²´ÓPÑŽš¨×ÑÙ2'çž ÛÞ‹Òd@|D$—Ì©þ$Öö^{eÞó:hFG²AäÖj1Ü»­›f[q¢È? óÕ ö5 wˆY=E ægŠh ‰y ²‰±fªj™h™á’w—ëãïãû›îUê}÷äqÌAàÛÖ)K&�á%sˆù£¥Õ©Î�¿Ðó5s5U Á6º;‰S’ ½–Søª@3Ÿ¹JÿûTÄè€ `ƒ‰ç°c�) r|ö 0V‚öŽ�Dè[b(—P ¢zûÛ f(Œ_ü¼Ì(mŒíÐÜW_#B„ùê¡]ÏÖŸŒÖ¾¿ÞòÏf¹¢¡ðâkâÙÿ?Þ×®­â±çqZ[@.$A¡0JQ¿„ŒË¬J£¯}ÞuÄ›ÿý*[#�„$ØÈÈÉä¡(Tr$“OhÒåÌSÁYQ,Pw‚§~X9AR ­a¿Pwò*¿õ�òÁÚ�|YÜíOÿûTÄë ¼[…ǰaÉ_Žñ<ô��• VtK®LAME3.100ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûTÄå€ œ¥�ôô&ñ¿𪪪ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûTÄËƒÈø-5œÁ4€ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªbeetbox-beets-00724b7/test/rsrc/image-2x3.jpg0000664000175000017500000000116415253035401020203 0ustar pieterpieterÿØÿàJFIFHHÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÄ ÿĵ}!1AQa"q2�‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2�B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?’€?ÿÙbeetbox-beets-00724b7/test/rsrc/image-2x3.png0000664000175000017500000000023315253035401020203 0ustar pieterpieter‰PNG  IHDR6ˆIÖ pHYs  šœtIMEÞ  J™tEXtCommentCreated with GIMPW�IDAT×cüÿÿ?‚9Ñ…'IEND®B`‚beetbox-beets-00724b7/test/rsrc/empty.aiff0000664000175000017500000025427615253035401020010 0ustar pieterpieterFORMX¶AIFFCOMM¬D@¬DSSNDX�ÿÿÿþÿþÿþÿÿÿþÿþÿýÿüÿþÿÿÿýÿþÿÿÿÿÿÿÿýÿûÿýÿþÿüÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿþÿþÿþÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿþÿþÿüÿýÿþÿþÿýÿýÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿûÿþÿÿÿýÿþÿÿÿüÿþÿþÿýÿüÿÿÿýÿýÿýÿÿÿþÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿúÿüÿÿÿÿÿýÿûÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿþÿÿÿÿÿÿÿýÿýÿþÿýÿþÿþÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿûÿúÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿþÿýÿþÿûÿýÿÿÿÿÿþÿþÿýÿÿÿýÿýÿýÿÿÿþÿýÿþÿÿÿþÿüÿýÿÿÿþÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿþÿûÿüÿÿÿÿÿþÿüÿûÿþÿÿÿÿÿýÿûÿþÿþÿþÿûÿûÿÿÿþÿüÿýÿþÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿþÿþÿþÿÿÿýÿûÿýÿýÿüÿýÿþÿþÿþÿÿÿÿÿþÿÿÿþÿþÿÿÿýÿüÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿþÿþÿýÿÿÿþÿÿÿýÿýÿþÿþÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿÿÿþÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿþÿýÿýÿýÿþÿÿÿþÿýÿüÿûÿûÿýÿþÿÿÿþÿýÿüÿýÿþÿýÿþÿýÿýÿûÿüÿþÿýÿûÿüÿüÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿüÿýÿÿÿÿÿüÿþÿÿÿÿÿÿÿýÿþÿþÿýÿÿÿýÿýÿüÿýÿþÿþÿÿÿþÿüÿüÿþÿþÿÿÿüÿûÿüÿûÿýÿÿÿÿÿþÿûÿüÿþÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿüÿÿÿÿÿÿÿþÿýÿþÿýÿüÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿüÿûÿýÿÿÿþÿÿÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿþÿþÿüÿûÿûÿüÿþÿÿÿþÿþÿÿÿÿÿýÿýÿþÿþÿûÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿûÿýÿýÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿýÿÿÿþÿþÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿÿÿþÿþÿýÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿþÿÿÿþÿýÿýÿýÿüÿÿÿýÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿÿÿÿÿÿÿþÿüÿþÿýÿûÿüÿþÿýÿþÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿüÿüÿüÿÿÿþÿüÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿüÿþÿþÿÿÿýÿþÿþÿÿÿþÿþÿüÿÿÿþÿÿÿþÿûÿúÿýÿÿÿþÿÿÿÿÿÿÿýÿþÿýÿýÿþÿþÿþÿþÿÿÿþÿþÿýÿüÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿþÿþÿÿÿþÿýÿýÿüÿýÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿþÿÿÿþÿýÿþÿýÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿþÿþÿýÿþÿýÿþÿþÿýÿüÿüÿþÿÿÿÿÿþÿýÿþÿþÿþÿþÿÿÿÿÿüÿüÿýÿþÿþÿþÿÿÿýÿùÿûÿýÿþÿþÿþÿÿÿÿÿüÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿþÿüÿþÿÿÿþÿûÿýÿýÿýÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿüÿüÿýÿýÿûÿÿÿýÿýÿþÿýÿÿÿÿÿûÿýÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿÿÿüÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿþÿýÿüÿüÿþÿþÿþÿþÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿþÿýÿþÿýÿýÿüÿþÿÿÿüÿüÿüÿýÿýÿüÿüÿþÿÿÿýÿûÿûÿüÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿþÿþÿÿÿþÿþÿþÿþÿúÿûÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿþÿÿÿþÿþÿÿÿýÿþÿüÿüÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿûÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿþÿüÿüÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿýÿýÿþÿüÿûÿýÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿþÿýÿüÿýÿþÿþÿÿÿþÿüÿûÿûÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿüÿÿÿýÿüÿþÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿþÿÿÿÿÿþÿÿÿþÿþÿÿÿüÿüÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿüÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿûÿþÿÿÿþÿýÿüÿýÿþÿþÿþÿÿÿýÿûÿûÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿüÿþÿþÿýÿþÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿüÿýÿýÿþÿûÿüÿýÿÿÿÿÿýÿÿÿÿÿýÿþÿþÿüÿýÿýÿýÿýÿþÿþÿÿÿþÿÿÿÿÿýÿûÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿûÿüÿþÿÿÿüÿüÿÿÿÿÿþÿþÿÿÿýÿýÿþÿþÿýÿýÿýÿþÿÿÿþÿýÿþÿüÿüÿþÿûÿþÿýÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿýÿýÿÿÿÿÿþÿþÿüÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿýÿüÿÿÿÿÿþÿþÿþÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿýÿûÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿÿÿþÿýÿÿÿþÿýÿýÿþÿûÿûÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿüÿüÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿÿÿÿÿýÿýÿüÿýÿþÿþÿýÿþÿÿÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿþÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿýÿþÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿüÿüÿüÿüÿýÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿþÿþÿÿÿýÿüÿþÿûÿüÿþÿþÿþÿÿÿÿÿÿÿüÿüÿýÿþÿþÿþÿÿÿþÿþÿýÿúÿýÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿýÿýÿþÿÿÿþÿþÿþÿÿÿýÿýÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿýÿþÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿþÿýÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿýÿþÿýÿþÿÿÿýÿþÿþÿüÿüÿþÿþÿüÿýÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿûÿûÿþÿþÿüÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿþÿÿÿýÿþÿýÿüÿüÿüÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿÿÿþÿþÿÿÿýÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿýÿþÿþÿÿÿþÿþÿÿÿûÿüÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿýÿûÿýÿþÿþÿýÿüÿþÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿýÿþÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿüÿýÿþÿüÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿüÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿþÿÿÿüÿüÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿþÿþÿýÿýÿÿÿüÿüÿþÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿüÿýÿþÿÿÿþÿüÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿýÿþÿþÿþÿýÿþÿÿÿýÿüÿþÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿüÿûÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿüÿþÿýÿûÿúÿüÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿýÿúÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿüÿýÿþÿüÿýÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿúÿýÿÿÿýÿþÿÿÿÿÿþÿûÿùÿýÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿýÿýÿûÿûÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿýÿüÿýÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿþÿýÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿÿÿýÿûÿûÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿüÿúÿÿÿþÿûÿûÿúÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿþÿÿÿþÿÿÿþÿþÿÿÿüÿýÿÿÿüÿüÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿÿÿýÿüÿýÿüÿÿÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿþÿþÿÿÿüÿÿÿÿÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿþÿüÿüÿýÿÿÿÿÿþÿýÿþÿþÿÿÿýÿûÿüÿÿÿýÿþÿýÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿüÿýÿþÿÿÿÿÿþÿÿÿþÿüÿýÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿþÿÿÿýÿüÿþÿÿÿýÿþÿÿÿÿÿýÿûÿþÿüÿýÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿýÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿýÿûÿÿÿÿÿÿÿÿÿÿÿþÿûÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿüÿýÿþÿýÿüÿþÿÿÿýÿûÿüÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿüÿüÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿþÿýÿüÿýÿýÿýÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿýÿÿÿþÿþÿüÿþÿþÿÿÿýÿýÿýÿýÿþÿüÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿþÿýÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿþÿþÿûÿüÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿüÿýÿÿÿÿÿÿÿÿÿÿÿüÿýÿýÿüÿþÿÿÿÿÿþÿþÿýÿþÿýÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿýÿÿÿþÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿýÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿüÿÿÿÿÿüÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿýÿûÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿýÿÿÿþÿÿÿûÿùÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿþÿüÿýÿüÿýÿþÿÿÿÿÿüÿÿÿÿÿüÿÿÿÿÿûÿúÿûÿÿÿÿÿþÿþÿÿÿþÿýÿüÿþÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿýÿþÿþÿýÿüÿýÿÿÿýÿþÿþÿüÿüÿþÿþÿýÿÿÿþÿüÿþÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿþÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿýÿýÿýÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿþÿÿÿþÿþÿþÿýÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿþÿýÿþÿÿÿýÿÿÿþÿÿÿýÿüÿÿÿÿÿûÿûÿýÿÿÿÿÿýÿýÿýÿÿÿýÿýÿüÿþÿýÿûÿýÿÿÿýÿùÿúÿüÿÿÿþÿþÿÿÿüÿþÿÿÿÿÿþÿþÿþÿýÿüÿÿÿþÿüÿýÿÿÿþÿÿÿþÿÿÿþÿýÿüÿýÿýÿýÿÿÿþÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿýÿýÿÿÿþÿÿÿÿÿþÿýÿþÿýÿþÿûÿüÿþÿþÿþÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿýÿþÿýÿûÿûÿÿÿÿÿýÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿýÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿýÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿúÿûÿýÿÿÿÿÿþÿüÿýÿþÿþÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿþÿýÿÿÿþÿýÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿüÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿÿÿþÿüÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿþÿþÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿýÿýÿþÿÿÿþÿüÿýÿýÿþÿþÿýÿûÿýÿÿÿþÿüÿûÿýÿýÿÿÿþÿýÿÿÿþÿÿÿüÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿþÿÿÿþÿýÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿÿÿýÿüÿýÿýÿþÿýÿýÿÿÿýÿýÿþÿÿÿÿÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿþÿÿÿþÿþÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿûÿþÿÿÿýÿýÿÿÿÿÿýÿþÿþÿûÿûÿýÿÿÿþÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿûÿýÿûÿüÿþÿýÿþÿþÿûÿüÿÿÿýÿýÿýÿýÿÿÿüÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿþÿýÿþÿþÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿúÿýÿÿÿÿÿýÿüÿüÿþÿþÿÿÿüÿþÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿþÿþÿÿÿüÿýÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿþÿýÿýÿÿÿüÿýÿÿÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿþÿþÿûÿùÿûÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿÿÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿùÿúÿþÿÿÿþÿýÿýÿþÿþÿÿÿÿÿþÿýÿþÿýÿýÿþÿüÿüÿþÿþÿÿÿýÿüÿÿÿÿÿýÿüÿüÿþÿþÿþÿþÿþÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿýÿüÿûÿþÿÿÿýÿþÿþÿÿÿÿÿýÿüÿþÿþÿýÿýÿþÿÿÿþÿÿÿÿÿþÿûÿýÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿüÿÿÿÿÿüÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿüÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿûÿúÿýÿÿÿþÿýÿüÿüÿþÿýÿÿÿÿÿýÿþÿÿÿþÿýÿüÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿýÿþÿÿÿþÿÿÿÿÿüÿûÿýÿÿÿþÿþÿþÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿúÿüÿÿÿÿÿÿÿþÿýÿÿÿýÿûÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿýÿþÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿüÿúÿûÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿüÿÿÿÿÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿýÿûÿýÿþÿþÿÿÿþÿþÿÿÿÿÿüÿüÿýÿþÿÿÿýÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿþÿüÿÿÿþÿÿÿþÿýÿýÿÿÿþÿüÿúÿúÿûÿÿÿþÿÿÿþÿüÿûÿûÿýÿþÿýÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿýÿÿÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿþÿýÿüÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿúÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿüÿýÿýÿüÿüÿüÿþÿÿÿÿÿÿÿýÿüÿÿÿþÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿüÿüÿûÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿýÿÿÿÿÿþÿþÿúÿþÿÿÿúÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿýÿþÿþÿýÿÿÿþÿþÿþÿþÿÿÿÿÿþÿüÿüÿýÿþÿüÿüÿÿÿÿÿûÿûÿüÿþÿüÿüÿþÿþÿÿÿþÿþÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿýÿþÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿýÿýÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿýÿüÿýÿÿÿþÿþÿüÿýÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿþÿþÿþÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿüÿüÿüÿþÿÿÿýÿüÿþÿýÿþÿþÿýÿýÿþÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿúÿþÿÿÿüÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿÿÿýÿýÿÿÿþÿþÿüÿýÿýÿûÿüÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿþÿþÿüÿýÿÿÿþÿþÿÿÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿýÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿüÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿüÿüÿûÿýÿþÿýÿýÿýÿûÿýÿýÿýÿýÿþÿûÿþÿÿÿþÿÿÿÿÿþÿÿÿüÿûÿýÿÿÿþÿüÿýÿÿÿýÿýÿýÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿýÿýÿýÿýÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿýÿûÿýÿÿÿÿÿÿÿýÿýÿÿÿÿÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿþÿûÿùÿúÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿýÿýÿþÿÿÿþÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿÿÿþÿüÿûÿþÿýÿÿÿþÿþÿýÿýÿýÿýÿûÿüÿþÿÿÿþÿþÿýÿúÿúÿúÿûÿÿÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿüÿþÿýÿüÿýÿþÿÿÿÿÿüÿûÿþÿüÿýÿýÿþÿýÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿþÿþÿÿÿýÿþÿÿÿýÿþÿþÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿÿÿüÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿýÿýÿüÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿüÿüÿüÿýÿþÿýÿýÿÿÿÿÿþÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿÿÿûÿûÿûÿûÿýÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿüÿþÿþÿþÿýÿÿÿþÿýÿýÿþÿýÿþÿþÿüÿþÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿüÿüÿüÿüÿüÿüÿýÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿüÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿþÿþÿþÿÿÿüÿûÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿûÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿûÿüÿÿÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿüÿþÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿþÿþÿþÿüÿÿÿÿÿÿÿýÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿÿÿþÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿþÿþÿÿÿþÿÿÿÿÿüÿüÿÿÿþÿþÿþÿýÿþÿÿÿÿÿýÿÿÿþÿýÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿúÿùÿüÿþÿýÿýÿÿÿþÿýÿÿÿþÿüÿýÿÿÿýÿúÿýÿýÿûÿûÿÿÿþÿýÿûÿüÿþÿþÿÿÿýÿüÿþÿÿÿþÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿýÿÿÿþÿýÿüÿÿÿÿÿþÿþÿþÿþÿþÿýÿüÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿüÿûÿýÿþÿþÿþÿþÿþÿþÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿýÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿþÿýÿýÿþÿþÿûÿùÿúÿýÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿýÿûÿúÿüÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿüÿýÿÿÿþÿúÿùÿþÿÿÿÿÿÿÿþÿýÿþÿýÿþÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿýÿÿÿÿÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿüÿùÿüÿÿÿýÿÿÿÿÿþÿýÿÿÿüÿýÿþÿþÿýÿýÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿüÿþÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿúÿûÿÿÿÿÿüÿýÿþÿýÿþÿüÿýÿÿÿþÿüÿûÿýÿýÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿýÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿýÿýÿþÿÿÿýÿÿÿýÿþÿÿÿÿÿþÿüÿýÿÿÿþÿýÿüÿþÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿüÿýÿþÿýÿÿÿÿÿþÿýÿþÿýÿþÿÿÿþÿüÿþÿýÿÿÿÿÿþÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿþÿýÿþÿÿÿþÿÿÿþÿþÿûÿýÿÿÿÿÿþÿýÿýÿüÿûÿþÿÿÿþÿþÿÿÿÿÿüÿûÿÿÿþÿþÿþÿÿÿþÿúÿþÿþÿÿÿÿÿþÿþÿýÿþÿþÿýÿÿÿÿÿþÿûÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿûÿýÿÿÿüÿþÿþÿÿÿüÿÿÿÿÿþÿüÿûÿúÿüÿÿÿüÿúÿþÿþÿÿÿÿÿþÿýÿýÿþÿüÿûÿýÿÿÿþÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿúÿùÿýÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿüÿüÿüÿýÿÿÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿüÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿüÿþÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿüÿÿÿþÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿÿÿþÿýÿþÿþÿüÿüÿýÿþÿüÿûÿþÿÿÿÿÿýÿüÿýÿýÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿþÿþÿýÿýÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿÿÿýÿþÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿþÿþÿþÿþÿüÿüÿýÿýÿþÿþÿÿÿþÿüÿüÿýÿÿÿýÿûÿûÿÿÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿýÿüÿüÿüÿÿÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿþÿüÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿýÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿûÿýÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿüÿýÿýÿýÿÿÿþÿþÿÿÿÿÿýÿüÿýÿüÿýÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿüÿþÿÿÿþÿüÿþÿÿÿÿÿüÿýÿÿÿþÿýÿýÿþÿýÿûÿüÿýÿýÿþÿÿÿÿÿÿÿüÿúÿýÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿüÿýÿþÿýÿÿÿÿÿÿÿýÿüÿþÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿþÿþÿþÿüÿüÿþÿüÿÿÿþÿþÿýÿÿÿÿÿþÿýÿþÿýÿþÿüÿýÿýÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿûÿüÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿþÿþÿþÿþÿýÿþÿÿÿýÿýÿÿÿýÿýÿüÿþÿûÿýÿþÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿþÿûÿùÿúÿýÿþÿþÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿüÿýÿþÿþÿýÿýÿýÿýÿýÿýÿþÿýÿþÿüÿþÿþÿþÿÿÿÿÿÿÿýÿüÿüÿýÿÿÿþÿüÿüÿÿÿþÿúÿúÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿýÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿûÿþÿÿÿÿÿýÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿýÿüÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿþÿÿÿþÿþÿüÿùÿùÿýÿþÿÿÿþÿÿÿÿÿÿÿüÿûÿüÿÿÿÿÿþÿýÿÿÿþÿýÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿýÿýÿÿÿýÿüÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿýÿüÿýÿÿÿÿÿÿÿüÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿýÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿýÿüÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿýÿþÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿýÿþÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿþÿûÿûÿþÿÿÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿÿÿþÿýÿþÿüÿüÿþÿÿÿÿÿÿÿüÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿüÿýÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿþÿþÿÿÿþÿýÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿþÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿþÿÿÿþÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿýÿþÿþÿþÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿýÿþÿûÿüÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿýÿýÿýÿýÿþÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿüÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿþÿýÿüÿýÿþÿÿÿýÿÿÿþÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿýÿýÿüÿþÿüÿúÿüÿþÿýÿþÿüÿüÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿýÿþÿýÿýÿýÿûÿüÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿýÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿýÿþÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿýÿÿÿþÿûÿýÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿÿÿÿÿÿÿÿÿþÿýÿüÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿýÿýÿþÿþÿüÿûÿýÿýÿýÿýÿþÿÿÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿýÿþÿûÿþÿÿÿÿÿÿÿþÿýÿÿÿýÿúÿþÿÿÿüÿþÿÿÿþÿÿÿÿÿþÿþÿþÿþÿÿÿýÿüÿÿÿÿÿüÿÿÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿüÿýÿþÿþÿýÿýÿûÿÿÿÿÿüÿÿÿÿÿþÿÿÿýÿÿÿþÿûÿüÿýÿÿÿþÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿþÿýÿüÿýÿÿÿýÿüÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿÿÿÿÿýÿûÿýÿþÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿüÿýÿÿÿþÿþÿýÿþÿÿÿþÿÿÿþÿþÿûÿýÿÿÿÿÿýÿþÿýÿýÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿÿÿþÿüÿÿÿÿÿüÿýÿûÿýÿýÿüÿýÿüÿüÿÿÿýÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿýÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿþÿüÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿýÿþÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿýÿýÿýÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿüÿûÿüÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿüÿþÿþÿýÿýÿþÿÿÿÿÿüÿýÿþÿÿÿþÿÿÿûÿûÿþÿüÿûÿÿÿÿÿÿÿþÿþÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿüÿÿÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿüÿýÿþÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿÿÿÿÿýÿüÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿþÿþÿýÿþÿýÿþÿþÿþÿþÿýÿüÿÿÿþÿüÿûÿûÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿþÿúÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿÿÿÿÿÿÿýÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿüÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿýÿþÿÿÿýÿÿÿÿÿÿÿÿÿüÿûÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿýÿþÿþÿþÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿýÿýÿýÿûÿûÿüÿþÿýÿýÿþÿþÿþÿýÿþÿýÿþÿÿÿþÿýÿüÿþÿýÿüÿþÿÿÿÿÿþÿþÿþÿþÿþÿüÿüÿþÿýÿýÿÿÿÿÿÿÿüÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿüÿþÿÿÿÿÿüÿýÿýÿþÿýÿþÿÿÿÿÿÿÿþÿýÿýÿüÿÿÿÿÿÿÿýÿþÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿúÿüÿýÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿýÿÿÿÿÿþÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿýÿüÿûÿþÿÿÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿûÿþÿþÿüÿþÿýÿüÿþÿþÿþÿþÿüÿýÿÿÿÿÿþÿþÿÿÿþÿþÿýÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿþÿÿÿÿÿýÿüÿûÿúÿúÿýÿÿÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿÿÿýÿÿÿþÿüÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿÿÿþÿþÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿÿÿýÿüÿüÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿþÿýÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿýÿÿÿüÿûÿþÿýÿÿÿÿÿÿÿþÿÿÿýÿûÿûÿúÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿûÿþÿÿÿÿÿÿÿþÿýÿüÿýÿþÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿýÿüÿÿÿþÿýÿÿÿýÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿýÿûÿûÿþÿÿÿÿÿÿÿûÿûÿþÿýÿþÿýÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿûÿüÿþÿÿÿþÿýÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿüÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿÿÿüÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿýÿýÿÿÿÿÿýÿüÿþÿÿÿþÿûÿýÿþÿþÿÿÿþÿþÿþÿýÿÿÿýÿÿÿÿÿþÿýÿÿÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿûÿûÿþÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿÿÿþÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿýÿûÿýÿÿÿþÿþÿÿÿÿÿþÿþÿüÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿüÿûÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿþÿûÿûÿþÿÿÿÿÿþÿýÿûÿÿÿÿÿÿÿÿÿþÿýÿýÿüÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿýÿþÿýÿÿÿÿÿüÿüÿýÿÿÿþÿÿÿÿÿýÿÿÿþÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿüÿúÿûÿýÿÿÿþÿýÿÿÿýÿýÿÿÿÿÿýÿþÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿüÿýÿÿÿýÿýÿûÿúÿüÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿüÿùÿûÿþÿÿÿÿÿÿÿÿÿþÿýÿüÿþÿÿÿÿÿþÿÿÿþÿþÿýÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿýÿýÿýÿýÿýÿýÿþÿÿÿÿÿýÿþÿýÿûÿþÿÿÿýÿþÿüÿýÿÿÿÿÿþÿþÿÿÿýÿúÿüÿÿÿþÿþÿýÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿþÿüÿýÿüÿúÿûÿýÿÿÿþÿýÿÿÿþÿþÿüÿýÿÿÿþÿýÿþÿýÿÿÿþÿþÿÿÿþÿþÿþÿþÿûÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿþÿýÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿüÿýÿýÿþÿÿÿýÿýÿÿÿýÿÿÿÿÿþÿÿÿþÿýÿþÿþÿþÿþÿüÿûÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿÿÿÿÿþÿþÿþÿþÿÿÿþÿýÿýÿÿÿüÿüÿþÿÿÿüÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿûÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿýÿþÿýÿþÿþÿýÿþÿÿÿÿÿþÿýÿÿÿþÿüÿýÿýÿýÿþÿûÿûÿûÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿýÿþÿýÿýÿýÿþÿÿÿýÿüÿÿÿÿÿÿÿÿÿýÿüÿüÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿþÿýÿþÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿþÿýÿþÿýÿýÿÿÿýÿþÿþÿýÿÿÿþÿÿÿþÿûÿûÿþÿýÿýÿÿÿÿÿýÿþÿÿÿýÿüÿýÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿþÿüÿüÿúÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿüÿÿÿþÿþÿþÿþÿûÿýÿÿÿÿÿþÿûÿüÿýÿþÿþÿÿÿþÿþÿþÿýÿýÿþÿýÿÿÿÿÿÿÿþÿþÿýÿýÿþÿýÿýÿýÿÿÿþÿþÿýÿÿÿýÿþÿýÿÿÿÿÿþÿüÿýÿüÿýÿÿÿüÿùÿúÿþÿÿÿþÿüÿüÿÿÿÿÿþÿÿÿÿÿÿÿÿÿüÿüÿüÿýÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿúÿûÿþÿÿÿÿÿüÿýÿÿÿþÿüÿýÿÿÿþÿþÿÿÿþÿþÿþÿýÿÿÿþÿþÿþÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿýÿýÿþÿýÿûÿýÿþÿÿÿþÿþÿÿÿýÿýÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿýÿúÿýÿþÿþÿÿÿÿÿÿÿÿÿûÿúÿýÿýÿûÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿüÿýÿÿÿþÿûÿûÿýÿüÿýÿÿÿÿÿÿÿÿÿýÿýÿûÿýÿûÿþÿÿÿüÿþÿÿÿýÿûÿûÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿýÿüÿýÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿûÿûÿüÿþÿÿÿüÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿÿÿýÿÿÿýÿþÿþÿýÿþÿýÿüÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿüÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿüÿþÿÿÿýÿüÿþÿÿÿþÿÿÿþÿÿÿüÿüÿýÿþÿþÿýÿýÿýÿÿÿþÿÿÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿÿÿüÿýÿýÿûÿûÿûÿûÿýÿþÿþÿýÿÿÿþÿüÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿüÿýÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿüÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿÿÿþÿýÿýÿþÿþÿÿÿüÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿþÿþÿüÿþÿÿÿþÿþÿüÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿþÿýÿýÿþÿýÿüÿÿÿþÿÿÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿýÿûÿúÿþÿþÿÿÿþÿÿÿýÿüÿþÿþÿÿÿüÿþÿþÿÿÿýÿýÿþÿÿÿþÿüÿüÿûÿýÿÿÿÿÿÿÿýÿÿÿþÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿýÿÿÿÿÿÿÿþÿýÿüÿýÿÿÿÿÿþÿýÿýÿüÿüÿýÿÿÿþÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿþÿýÿûÿùÿûÿýÿÿÿþÿþÿÿÿþÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿüÿüÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿýÿýÿýÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿýÿÿÿÿÿþÿþÿýÿüÿþÿÿÿýÿÿÿýÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿþÿþÿþÿþÿÿÿÿÿüÿüÿÿÿÿÿýÿüÿþÿÿÿþÿÿÿÿÿýÿüÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿýÿþÿýÿþÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿüÿüÿýÿÿÿþÿÿÿÿÿÿÿýÿüÿýÿþÿüÿÿÿÿÿÿÿýÿýÿþÿþÿþÿÿÿÿÿþÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿýÿýÿüÿûÿûÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿÿÿþÿþÿþÿýÿÿÿÿÿûÿþÿÿÿÿÿýÿýÿþÿÿÿþÿýÿÿÿýÿüÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿüÿþÿüÿýÿÿÿÿÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿýÿÿÿþÿýÿþÿüÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿýÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿýÿúÿûÿüÿÿÿþÿþÿþÿÿÿÿÿýÿüÿüÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿþÿþÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿþÿþÿþÿýÿþÿýÿþÿýÿÿÿþÿþÿþÿþÿüÿýÿÿÿÿÿÿÿÿÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿÿÿýÿþÿýÿüÿÿÿÿÿüÿþÿÿÿþÿþÿþÿûÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿüÿüÿÿÿýÿýÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿúÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿýÿýÿýÿýÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿýÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿýÿüÿýÿÿÿÿÿÿÿþÿýÿþÿýÿýÿýÿþÿÿÿþÿþÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿüÿúÿüÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿûÿûÿüÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿüÿþÿÿÿÿÿþÿÿÿýÿÿÿþÿþÿüÿüÿÿÿÿÿýÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿûÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿüÿûÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿýÿþÿþÿþÿþÿþÿþÿÿÿýÿýÿÿÿÿÿüÿÿÿÿÿþÿýÿüÿþÿþÿþÿÿÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿÿÿþÿÿÿþÿþÿÿÿþÿüÿýÿþÿþÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿÿÿýÿýÿüÿûÿýÿÿÿþÿþÿþÿþÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿþÿýÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿýÿýÿþÿûÿýÿÿÿÿÿÿÿþÿûÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿüÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿýÿýÿýÿûÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿüÿýÿûÿýÿÿÿÿÿþÿþÿÿÿþÿýÿþÿþÿýÿÿÿÿÿüÿúÿûÿÿÿþÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿûÿúÿÿÿÿÿýÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿüÿûÿÿÿÿÿÿÿýÿýÿþÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿýÿüÿþÿþÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿþÿýÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿþÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿÿÿþÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿýÿüÿýÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿþÿÿÿýÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿþÿþÿýÿüÿýÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿýÿýÿþÿÿÿÿÿýÿûÿýÿþÿÿÿþÿýÿÿÿþÿþÿþÿÿÿýÿüÿþÿýÿüÿýÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿýÿýÿýÿûÿýÿþÿþÿýÿüÿýÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿþÿüÿúÿûÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÿüÿþÿýÿúÿúÿûÿýÿÿÿþÿüÿûÿýÿýÿÿÿýÿþÿýÿýÿþÿþÿûÿüÿýÿüÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿûÿþÿþÿÿÿÿÿýÿþÿüÿýÿýÿþÿÿÿÿÿÿÿÿÿûÿýÿýÿüÿýÿþÿýÿþÿÿÿýÿþÿÿÿýÿüÿþÿýÿüÿÿÿþÿÿÿÿÿÿÿûÿüÿÿÿÿÿþÿþÿÿÿýÿüÿþÿÿÿþÿþÿþÿýÿýÿþÿÿÿýÿüÿþÿÿÿýÿüÿýÿýÿýÿýÿÿÿÿÿüÿüÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿÿÿýÿúÿúÿýÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿýÿþÿþÿþÿýÿþÿþÿýÿüÿýÿþÿþÿÿÿþÿýÿÿÿþÿüÿüÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿýÿýÿûÿýÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿýÿûÿûÿüÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿýÿüÿþÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿýÿÿÿýÿýÿþÿüÿûÿýÿÿÿþÿþÿÿÿÿÿþÿþÿýÿüÿþÿþÿþÿÿÿþÿýÿÿÿþÿÿÿûÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿúÿúÿþÿÿÿýÿÿÿÿÿÿÿýÿüÿýÿýÿþÿþÿþÿÿÿÿÿþÿÿÿþÿüÿÿÿþÿþÿþÿÿÿýÿúÿûÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿûÿüÿþÿþÿüÿüÿþÿþÿÿÿÿÿýÿüÿüÿþÿþÿþÿþÿýÿüÿüÿþÿýÿüÿýÿþÿþÿÿÿÿÿýÿýÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿüÿüÿüÿüÿÿÿýÿþÿÿÿÿÿÿÿþÿûÿûÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿýÿÿÿÿÿþÿýÿüÿýÿþÿÿÿþÿûÿûÿÿÿÿÿÿÿþÿýÿýÿþÿþÿþÿÿÿýÿýÿþÿÿÿþÿýÿþÿþÿýÿýÿþÿþÿÿÿÿÿüÿÿÿÿÿþÿýÿþÿüÿüÿþÿÿÿþÿþÿþÿþÿþÿüÿúÿüÿÿÿüÿýÿÿÿþÿýÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿþÿýÿûÿýÿÿÿþÿýÿþÿþÿýÿýÿýÿýÿþÿÿÿýÿÿÿÿÿýÿþÿÿÿþÿýÿýÿÿÿÿÿýÿûÿýÿûÿûÿýÿýÿýÿýÿýÿÿÿþÿþÿýÿüÿýÿþÿÿÿþÿüÿýÿÿÿþÿÿÿþÿüÿþÿÿÿûÿýÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿüÿÿÿÿÿÿÿþÿÿÿüÿûÿþÿþÿýÿÿÿþÿýÿÿÿýÿýÿþÿýÿýÿýÿÿÿÿÿþÿüÿüÿÿÿýÿûÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿûÿüÿþÿþÿþÿÿÿþÿþÿþÿüÿýÿþÿýÿûÿüÿþÿÿÿÿÿüÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿûÿýÿÿÿÿÿþÿýÿþÿþÿÿÿýÿüÿýÿýÿüÿÿÿþÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿýÿüÿüÿþÿýÿþÿþÿýÿüÿþÿÿÿýÿýÿûÿþÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿüÿþÿÿÿüÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿýÿüÿÿÿÿÿýÿüÿþÿÿÿýÿüÿÿÿýÿÿÿüÿûÿþÿÿÿÿÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿüÿûÿýÿþÿþÿþÿþÿþÿþÿýÿüÿÿÿþÿûÿþÿþÿþÿýÿÿÿÿÿüÿÿÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿýÿüÿûÿûÿýÿÿÿÿÿþÿýÿýÿüÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿýÿýÿþÿýÿüÿþÿÿÿÿÿýÿýÿþÿÿÿüÿýÿÿÿýÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿüÿüÿÿÿÿÿûÿüÿýÿþÿþÿýÿÿÿþÿÿÿýÿþÿÿÿÿÿýÿýÿýÿüÿýÿþÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿýÿýÿÿÿüÿýÿþÿýÿýÿýÿýÿÿÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿûÿùÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿþÿÿÿÿÿÿÿþÿýÿþÿüÿýÿþÿþÿÿÿþÿþÿüÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿþÿþÿüÿþÿþÿüÿüÿþÿþÿþÿýÿÿÿÿÿýÿÿÿÿÿüÿýÿþÿÿÿþÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿþÿüÿýÿþÿÿÿþÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿûÿûÿþÿÿÿýÿþÿþÿþÿþÿýÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿüÿúÿûÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿýÿýÿþÿÿÿÿÿÿÿþÿýÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿûÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿüÿÿÿþÿÿÿÿÿþÿþÿýÿüÿüÿþÿýÿüÿþÿýÿþÿûÿþÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿúÿýÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿýÿüÿýÿþÿýÿþÿýÿÿÿþÿüÿýÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿüÿýÿûÿüÿýÿÿÿÿÿþÿÿÿÿÿüÿþÿÿÿüÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿÿÿþÿýÿÿÿþÿþÿýÿþÿþÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿýÿýÿüÿþÿÿÿþÿýÿüÿþÿþÿýÿüÿüÿÿÿÿÿÿÿýÿþÿûÿûÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿûÿþÿþÿþÿþÿýÿüÿüÿÿÿþÿþÿÿÿþÿÿÿþÿüÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿþÿþÿþÿûÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿÿÿþÿþÿþÿûÿúÿüÿþÿýÿûÿûÿýÿþÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿýÿþÿÿÿþÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿûÿýÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿüÿýÿþÿýÿþÿÿÿÿÿÿÿþÿþÿüÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿþÿýÿþÿüÿþÿþÿþÿÿÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿþÿýÿüÿþÿýÿýÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÿÿÿþÿþÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿüÿüÿÿÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿýÿýÿýÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿýÿýÿýÿÿÿýÿüÿýÿþÿþÿþÿýÿüÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿÿÿýÿýÿþÿÿÿÿÿþÿýÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿýÿüÿüÿüÿÿÿÿÿüÿþÿýÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿûÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿýÿýÿýÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿþÿýÿþÿÿÿýÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿþÿþÿÿÿþÿþÿüÿüÿÿÿþÿþÿÿÿÿÿÿÿþÿüÿþÿþÿþÿýÿýÿþÿýÿþÿþÿÿÿÿÿÿÿýÿüÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿûÿüÿþÿÿÿþÿÿÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿýÿüÿþÿüÿüÿûÿýÿýÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿüÿüÿÿÿÿÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿûÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿýÿýÿþÿÿÿÿÿþÿûÿýÿÿÿþÿþÿÿÿÿÿþÿüÿþÿÿÿýÿþÿþÿþÿÿÿÿÿüÿúÿüÿýÿüÿþÿÿÿþÿüÿùÿûÿþÿÿÿþÿÿÿÿÿýÿýÿÿÿþÿûÿþÿÿÿþÿþÿÿÿþÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿþÿþÿýÿüÿüÿþÿÿÿÿÿüÿýÿþÿÿÿûÿþÿÿÿýÿýÿþÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿüÿùÿüÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿýÿüÿýÿÿÿþÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿýÿüÿÿÿÿÿÿÿþÿÿÿÿÿüÿûÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿþÿþÿýÿýÿÿÿþÿüÿþÿþÿýÿýÿþÿÿÿÿÿþÿûÿýÿþÿþÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿüÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿüÿüÿþÿþÿýÿûÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿüÿûÿþÿüÿüÿÿÿÿÿþÿýÿÿÿÿÿýÿþÿþÿÿÿþÿÿÿÿÿýÿþÿþÿýÿþÿÿÿüÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿýÿþÿüÿýÿüÿüÿþÿþÿüÿüÿûÿüÿÿÿÿÿýÿûÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿúÿûÿþÿýÿÿÿÿÿþÿþÿýÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿþÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿþÿþÿýÿüÿÿÿÿÿüÿýÿÿÿÿÿÿÿýÿýÿýÿþÿýÿÿÿýÿýÿþÿÿÿÿÿýÿÿÿýÿÿÿÿÿþÿýÿýÿýÿþÿþÿýÿþÿÿÿýÿþÿþÿþÿÿÿþÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿþÿþÿþÿÿÿþÿÿÿþÿþÿþÿüÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿýÿýÿýÿþÿþÿÿÿüÿýÿþÿýÿþÿÿÿÿÿþÿýÿþÿüÿÿÿÿÿýÿüÿûÿýÿþÿÿÿþÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿûÿûÿþÿüÿýÿýÿþÿþÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿýÿÿÿþÿýÿüÿýÿÿÿüÿýÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿüÿýÿýÿþÿÿÿÿÿÿÿýÿþÿýÿýÿþÿÿÿþÿýÿüÿüÿÿÿÿÿüÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿüÿýÿýÿýÿþÿúÿüÿþÿþÿÿÿþÿþÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿþÿþÿüÿýÿÿÿþÿüÿýÿýÿþÿþÿÿÿÿÿþÿýÿÿÿÿÿüÿþÿþÿýÿüÿþÿþÿÿÿüÿþÿþÿýÿüÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿþÿÿÿÿÿúÿüÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿüÿþÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿüÿÿÿýÿûÿþÿûÿýÿÿÿÿÿþÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿÿÿþÿýÿþÿþÿýÿþÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿýÿüÿÿÿþÿþÿþÿÿÿýÿýÿþÿÿÿýÿûÿþÿÿÿüÿüÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿýÿÿÿÿÿüÿüÿþÿÿÿþÿüÿýÿÿÿþÿýÿýÿþÿÿÿþÿÿÿÿÿýÿýÿþÿýÿûÿüÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿýÿþÿÿÿýÿþÿüÿþÿýÿûÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿþÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿüÿüÿýÿýÿÿÿüÿýÿýÿûÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿÿÿýÿþÿÿÿþÿþÿýÿúÿûÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿüÿþÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿýÿþÿþÿýÿüÿÿÿÿÿþÿýÿýÿÿÿþÿþÿþÿþÿþÿýÿýÿþÿþÿüÿýÿÿÿþÿüÿýÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿýÿüÿýÿþÿþÿþÿþÿþÿþÿÿÿÿÿüÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿýÿýÿýÿþÿÿÿýÿÿÿþÿþÿþÿþÿüÿþÿÿÿÿÿþÿÿÿÿÿûÿúÿýÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿÿÿýÿùÿúÿüÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿüÿÿÿÿÿüÿþÿüÿüÿÿÿþÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿÿÿþÿÿÿþÿýÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿûÿûÿûÿúÿüÿþÿýÿüÿþÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿýÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿþÿÿÿýÿûÿûÿüÿýÿþÿþÿûÿúÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿýÿýÿýÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿýÿüÿþÿÿÿýÿüÿÿÿÿÿýÿþÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿüÿüÿüÿüÿÿÿÿÿýÿÿÿÿÿþÿþÿþÿýÿûÿþÿÿÿþÿÿÿþÿýÿþÿýÿÿÿþÿÿÿÿÿýÿüÿüÿþÿÿÿýÿýÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿýÿüÿþÿÿÿÿÿýÿüÿûÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿüÿþÿþÿüÿüÿÿÿÿÿþÿþÿþÿÿÿþÿýÿüÿýÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿüÿûÿúÿûÿýÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿýÿýÿþÿþÿÿÿþÿþÿþÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿûÿùÿúÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿüÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿüÿþÿÿÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿýÿÿÿÿÿÿÿýÿüÿÿÿÿÿýÿÿÿþÿþÿþÿÿÿþÿüÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿüÿýÿþÿÿÿÿÿýÿýÿýÿýÿýÿýÿüÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿýÿþÿýÿÿÿÿÿþÿÿÿþÿüÿûÿýÿþÿþÿþÿþÿýÿýÿýÿýÿÿÿÿÿþÿþÿÿÿýÿþÿýÿûÿüÿÿÿþÿýÿþÿÿÿþÿýÿþÿþÿüÿþÿýÿÿÿÿÿþÿÿÿþÿÿÿýÿüÿýÿþÿþÿüÿþÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿûÿùÿûÿÿÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿüÿüÿüÿüÿüÿýÿýÿûÿüÿþÿýÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿþÿþÿþÿýÿüÿýÿüÿûÿþÿýÿÿÿþÿþÿþÿýÿüÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿýÿþÿþÿÿÿþÿÿÿüÿýÿýÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿþÿÿÿþÿþÿþÿÿÿüÿüÿÿÿþÿÿÿÿÿþÿþÿþÿýÿýÿþÿþÿÿÿþÿýÿüÿüÿûÿýÿþÿþÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿüÿüÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿþÿýÿþÿÿÿþÿþÿüÿþÿþÿÿÿÿÿýÿÿÿÿÿüÿýÿÿÿþÿþÿýÿýÿüÿýÿÿÿþÿýÿþÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿüÿûÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿûÿüÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿüÿÿÿþÿÿÿýÿÿÿÿÿÿÿþÿüÿüÿüÿþÿýÿþÿýÿüÿüÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿþÿûÿüÿÿÿÿÿýÿÿÿýÿþÿÿÿÿÿýÿþÿýÿþÿÿÿþÿþÿþÿýÿûÿýÿÿÿþÿÿÿÿÿýÿýÿþÿýÿÿÿþÿüÿýÿÿÿþÿüÿýÿÿÿÿÿÿÿýÿüÿþÿþÿþÿþÿþÿýÿúÿýÿÿÿÿÿþÿÿÿÿÿüÿüÿþÿýÿýÿÿÿÿÿýÿÿÿþÿþÿþÿþÿþÿýÿûÿúÿüÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿüÿýÿþÿüÿýÿþÿþÿþÿþÿþÿÿÿüÿüÿÿÿýÿýÿÿÿÿÿþÿüÿûÿûÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿýÿÿÿþÿüÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿýÿýÿþÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿüÿþÿÿÿþÿþÿþÿþÿýÿþÿþÿþÿüÿýÿÿÿþÿÿÿþÿþÿþÿþÿýÿýÿþÿÿÿþÿþÿþÿþÿÿÿýÿýÿýÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿþÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿýÿüÿÿÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿþÿþÿÿÿýÿüÿþÿþÿþÿÿÿÿÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿûÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿÿÿýÿýÿÿÿþÿýÿþÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿüÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿýÿüÿþÿÿÿýÿþÿÿÿýÿýÿüÿûÿþÿÿÿýÿýÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿüÿúÿýÿÿÿýÿüÿþÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿþÿþÿþÿýÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿÿÿÿÿýÿÿÿÿÿÿÿýÿýÿýÿÿÿþÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿýÿþÿüÿúÿýÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿüÿýÿÿÿþÿýÿÿÿüÿûÿþÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿÿÿþÿþÿýÿþÿÿÿýÿüÿÿÿþÿúÿûÿÿÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿþÿýÿþÿþÿüÿýÿýÿüÿþÿÿÿÿÿûÿýÿþÿþÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿüÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿýÿÿÿÿÿüÿûÿþÿÿÿÿÿþÿýÿÿÿýÿÿÿÿÿýÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿüÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿûÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿúÿüÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿþÿýÿÿÿÿÿüÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿÿÿýÿýÿÿÿþÿÿÿÿÿýÿÿÿþÿýÿþÿþÿþÿüÿþÿþÿýÿýÿýÿÿÿýÿýÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿýÿüÿüÿüÿýÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿýÿýÿýÿþÿÿÿÿÿýÿþÿýÿÿÿýÿýÿþÿÿÿýÿþÿÿÿÿÿþÿþÿýÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿýÿüÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿýÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿþÿþÿýÿüÿýÿÿÿþÿýÿüÿüÿýÿüÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿüÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿþÿþÿýÿþÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿÿÿüÿüÿüÿûÿûÿþÿÿÿÿÿÿÿüÿûÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿýÿþÿþÿÿÿýÿüÿþÿþÿÿÿþÿýÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿüÿüÿþÿÿÿþÿüÿûÿýÿÿÿýÿýÿýÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿþÿþÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿÿÿÿÿûÿýÿÿÿþÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿýÿÿÿÿÿþÿýÿüÿûÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿýÿüÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿüÿüÿýÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿüÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿüÿüÿüÿÿÿþÿüÿýÿþÿüÿùÿøÿûÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿûÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿûÿþÿýÿÿÿÿÿüÿûÿýÿÿÿÿÿþÿþÿýÿÿÿþÿýÿýÿþÿûÿüÿÿÿýÿþÿÿÿÿÿÿÿüÿüÿÿÿÿÿÿÿýÿûÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿþÿýÿüÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿþÿüÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿýÿþÿûÿüÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿüÿûÿýÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿúÿûÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿþÿÿÿþÿÿÿÿÿþÿýÿüÿýÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿýÿÿÿþÿüÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿüÿÿÿÿÿüÿüÿüÿþÿüÿþÿþÿýÿúÿüÿÿÿüÿûÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿüÿüÿÿÿýÿûÿûÿüÿýÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿÿÿþÿÿÿþÿÿÿþÿüÿþÿþÿüÿüÿüÿýÿýÿþÿþÿþÿþÿþÿýÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿýÿþÿýÿÿÿþÿþÿþÿüÿþÿþÿþÿýÿüÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿüÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿýÿþÿýÿüÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿúÿûÿþÿÿÿþÿüÿÿÿÿÿýÿüÿýÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿüÿüÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿýÿÿÿýÿþÿþÿÿÿþÿýÿþÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿýÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿýÿþÿÿÿýÿýÿüÿþÿÿÿÿÿüÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿÿbeetbox-beets-00724b7/test/rsrc/partial.mp30000664000175000017500000003102415253035401020060 0ustar pieterpieterID34COMengiTunPGAP0TENiTunes v7.6.2COMhengiTunNORM 80000000 00000000 00000000 00000000 00000224 00000000 00000008 00000000 000003AC 00000000COM‚engiTunSMPB 00000000 00000210 00000A2C 000000000000AC44 00000000 000021AC 00000000 00000000 00000000 00000000 00000000 00000000TP1 the artistTAL the albumTRK2TPA4TT2 partialÿû`À F=íÉ‘A#ô‰¹ÿÿÿÿF0ÃßÿC ÿ_ùïÿÿÿÿóÏ£)çÚa”2ùŠz<‚žyõ=xù=O `ÐÊÇ�  ¥à�Æyé>`øÜá ÐÀXè" z)ãBœ"À$)‚ �A„ ÿÿÿÿÿøÿ×?ÿûÿÿÿÿþ¾Ývb£×B�¬¦ ³4Àã°²+¸µÂ¤Ír¹Á�ÔR°Ä%;�îR£Q[ÿÿÿïÖÜîÿ³¾Ú7UW6dTUT!ub8´Çø çèx?ñ.Ì€ˆˆˆˆ�ÿÚÚ¢³<ŒaeŸDY/ÿÿÿ½ÿPœ¼·$D¬(躡ïPŒi§ÿû`À€Š9à… éâH#4•¸‹RÒAbÉuÏ&Ž ü:=ÄÝL´2!Ô¶#9îŽÔ#"5¿ÿÿÿú­ÿfE$ìȉ,ª1HËez²1’ª!ĨR ˜‰Ì§)¢((â¢,Êc°š)ÄÜX¢¬,qE„T9N@øˆtÿÿÒþ÷ÿ?ÿû`À ò= mÁ¸È#t�¸¿ÿÿóËäܯðÉ÷IN¡æiÞÿ{ÞžYg§S—ÜëdE/'ÿÿÿÿÿÿÿçþ§Ì¸g Wëï&%ÍirÄDuñ6.ÝítÜ‘mtP&ê,Ž�«¢’Duhâb¨D›ÀN±ÿÿÿÿÿý`Zÿý{ÿÿÿÿÿçÌímÞó¥/Þj¾GH„<&ñÎC¥ÿü„žl÷ÿÿÿÿÿÿÿýþÿçJÎÉP��1•¥I’òÔä»ò9£3³ZHFÊ;ŽÔr/viƒÃ�1  Ü‰…£2‡ ìÁ�ÿÿÿÿÿÖõÿþyÿ?ÿÿùz\¨Û+dDΪ�1ˆÆckTIw˜ÿûbÀ æ% „MɬH#t‰¸™¨…¶R²¶Í´öÿÿÿÿdÝꓳÐ÷1êr© ÊϳîÒ»³lÖ• lΆmC‘Uê÷c,ì$(tÈ4BKÿÿÿÿÿëåý²ëZSÿÿÿÿü¹QRÅ­ÝŒ‡>³Ìl®®è§1Œ¨ˆËf:V¨m&¾åDGB;?ÿÿÿÿÿù­RÌé+ƒ9‡}•+ϳ+±ÍUÐèÊbPSú;1Œ%Ü; Š…R•Ìwt”€Î9Bÿÿÿÿþ¶ƒÿëÿ•ÿÿÿÿäìúRwó5�lª„s>ʸõ#ÌäºuFlëÐêɕћÿÿÿÚÿ³«ÔªFJȪyŒEus–ÿû`À" ? „­Á¬Æ#t•¹a2ft*3άVwVl̸â•êc�@@Ç‚o2ÇåQÇ;> ¢£€?ÿÿõ�sÿÿÿÿÿü»µ®å:=¨îïv:ºº•VB/Îlêèö-ÊZ$Û™5OÿÿÿþÍ'*MD£�'» È.–z¹›S«”ÌêW!„Ça溡Z!3#NǞ#!ƒ¢âcH5VA¸ò¨`†`±�óõùþ¿ÿÿÿÿ®•g;RWT�ÙUÕ½ÔÝQeÑÑTľÎB%OÿÿÿõùÑgêÕ9F F‘�T‡j9"Î(cJb#!Ç�xˆÕ3³ ªEÿû`À, Ú= „­É¯È#4‰¸vcœqL8áaàÊPq¢�Ñ2$48ÿÿÿÿþÖ¯uÿºÿÿÿÿÿ?£‘Ý”„5›Rl›ogGÐŒªöi7ºÕŽ·ìKwÿÿÿÿÿÚÒ"1Ý_™Ü§8¤T„Dg�ä;YƒœFä%PìÆ \ÈäRŠF €‚äS3: ÁÈQBªà•Ü(ÿÿÿÿþÍ�—ÿ/ü¡ßŸõÿÿÿo‘œíbnYØz(‰‘ëu×J:ä·Id£ïZÐÔÙÿÿÿÿÿþŸJ'»Jƒ Ff®ï©Ne+ È 8ä*&*†q2 0�Ì AŠAD…0’�Q!2ª”¥A§aQEÿû`À6€ ¶A „­Á¬E£t�¹0ÿÿÿý°/ó׿ü¿ÿÿÿÿò]s¹œÐô… 仪Dþ9FzÓ¦[7‘t¥+M¹2ä³ÿÿÿÿÿÿÿéÿ9æÓ*FE‘D‰»ë2³×r™9“Ò·I­|¼UèÊã±Áz°spÂ+† JÛØ8ÿÿÿÿþ��©ü¼ògRfÒÏåÿÿýþ•$íc1üý§º!Yz:d÷#ê×*º%Pú?{¯ÿÿÿÿÿèɦ·5\ÎR£¾ì‚ŠTv{˜Ä$A™ RkÑi†ˆ!£±ÅÊ�Ö(|¨rˆ˜pðé¢î<ÂÁÀ+)�h0À5�"ü¿ÿÿÿÿÿdîÿûbÀBVA „­ÁÄÇ£4•¹�F±:¼Û>yê­)Ý�ì¬åºQò²+7cfTÿÿÿëÙ[óÉW£•hr¿ÿÿÿÿ�iO‰�&�׊aÒ¶§ö’ѺkL“ÔW0÷?ÜpµpÝÿÿÿÿÿÿÿ1ÿ×ýúÚuz÷¤sò8ë›~9�çˆ^;Ž’˜…ìar:¦hZ—Ro|†AwÚÖìXòo®Ü**>@Ö0ÿÿÿÿÿëËWuûJ�FÑYìîåˆòYÙræ\ˆîjí»*"±Hßÿÿÿÿ~î‰m¨—g*:˜…+"ofi•ÞÂ#E� �¨²)JçWACê,$aqÊÇ)„€p1Œ"Pè‘ÅH‡(Ñ¡`8�ÿûbÀo€5 … ɽH"Ì•¸3èòÿ¯ÿÿÿÖ×Ýzè¼ì×»Èr/È¢ Ê®”d£3Ñ—yN¤qÿÿÿ÷ä{"Zåu#ÌeR ¸ñŽÄsî®e-ESi‘�pÕ( ›0“�„bŽ3‡Àãs�†�yNEr”ÓŠˆ¨€� ŒÀÿÿÿÿÿí�yïÿéßÿÿÿýz.¥1,o5ä+9·Ežuvf±Îõ¹v}ÈÈ–NÿÿÿÿDû}l³µ+3UTŠCo¼¥>%èOyS!�XŒ‡‘Æi;�\ê8#)Ń:‰cÅ•Êt(P‘À?ÿÿÿÒÿùÿóÿÿÿÿù´š÷fÿû`Àx 9 ­Ù¤G£t‰¹b$„vºftgdû©kU-™œèƤÆVäfÛÿÿÿÿìŸêR>Ó­ÕK5(i5; Îñ“•ÑŠwiÇ*¹ˆ¤"âŠ*.*1â¦c´x´çRH@“ˆ#•bÀÿÿÿö@¿ÿ-»<ŽÄjµ=]ÖÓTª¤®Æ96Kä<îäsn³¼ó—ÿÿÿýv"Ñõ{Ñ]LëgR�g©ªF5ŽFuõZÇQ3�QÓ ‡Ç°›”a‡¨Ô ˜µÌ.tP‰GQCå<ÊÿÿÿÿÖþ]ÿþ«¯ÿÿÿþÞˆy‘žr3ÚÛg§Ÿ¤m4U++!d“Ö¶_J´Í{ÿû`Àƒ nA „­ÁªG£4¹ÿÿÿÿÿÿÿÿöù7ÈqyiHsC0¤Er_?* –gÐNP�‰îF¸v#UCªˆ9ŽB!* jè�A‡1Y(0ÿÿÿÿý`_óòþ_ÿÿÿÿüßíÑžïzJ_¹K&´išôE3Šeu!&>ˆˆþFÿÿÿÿéÌý<ˆs±Q#•ÞcÚï39’Àœ“Ùœ[%ÜÑÝÄÇ8s¸Îd†; áXä …C0­ƒÿùZõº�Výi ­b¹*ªOf3U§,ÍD=®E%^ÝËÿÿÿÿóHêí³=Uή¯­]�™žØâ®ª9ÕŒfd#9ÿû`À� òA „mÁžÈ#t‰¸Ñ�Ô�¤C»Tˆpø…Å”HƒbÈ s‘� E,*Qÿÿÿÿÿý`9oËêkÿýýÿÿÿÎë"åE§KQîÖÝ�Jî·<†aG TGȪW›F}]iÿÿÿÿêÞªú#f«¢Ì¨ÅUTH̵Eç̪·;f¤€ÜâÀÙÑÕN]Dœr¬¨qNÈaÝ(ÿÿÿþ²ûçþ}~_]ÿÿëïôìÌÇûèw.šQÞrØÌÌäb-lzèÒÒšÿÿÿÿßé­ÝíSUÐæg«DL†îB�ÓœxÝ� ¶QE§™ˆc±îD €Ñ3‡PƒÃ¡ÿûbÀœ 2A €­Á²H#4‰¸$)Ÿ1Qd‚ £ýÿçÿÿÿÿýÖþ—tÍT!˜¦ÈwS5îêëfº�ÐÅ*”�lý؈ŠßÿÿÿÿôºµYÊÊKžÓÊÄB²¢�Ïvj±•QXÌB *”a”£¤q3”Á7 áº¡b±Îƒ!¬k **�6Hÿÿÿÿ¶ü¿¿Ëå_ÿòùß%é,«¿uÜöeæBÊìöJ¹Mwº®í­]Õr«7ÿÿÿû¢Ú®d+Tµ#!•ˆDeœ‡æ)Øì…F•®q`³�QËÊ·K ‡!:ÁÎÂÃ�ur‹C˜®àÿÿÿÿú@¾_âüÿû`À©€ ž; „­ÉÁG#4•¹¯ÿÿÿÿçïÿ%2ó¥xzžõËa©—ÝßÈͶMŸšÃ™);þe­Ûÿÿÿÿÿÿÿÿù~~KrS¬[uvzŸzYq¢ñ òlQ�wÑß#}¨\‰jZ |‹T �¸Ä!ÌéÀÀàÿÿÿÿÿ�Ÿž Øç —Ne9Ÿÿÿç eR!áçÖVê¢õœ}!wÂOí3UUÚZWU>ÑÿÜWÿÿÿÿÿÿÿÿ?íñó÷+kLÖÃùŽ*Øëk‘s*—gJ�4`ž¹EÆÇviF"‡$˜z©†9‚XõÂa�Ë”9pèP·XT]Çÿÿÿÿÿc`qîyÿû`À²€ .A „MÁ­G£t�¹‰#±’¿%¾§ÿþY¸tûîú㙬ꙉy¥˜†ýwŠõÚ©¦÷ÞÒ¥©S»éºæÿÿÿÿÿÿÿþÿ¿ÿû¿Ž¹šk¯«YO›­²<6<’±…&TÉ눢Æ!wB±E2ˆ ¸ö³J‡4\V…K1`°’ކ6Ëq1Š@ÿÿÿÿý±ƒÍ#˜Wå¿Ì«ÿÿÿý:*\Ȫuo™��H(έb+JB{1¨¦î·±•jjÿÿÿþ�7¥®·tT2+9#ÝÖ<–ºœÈ©*­ ayŒQ1§3•Ú&=¥B�:``ë‘‚¢§Š ‰Zpð[JQÿû`ÀÀŠA … ÂÈ"´¡¸ €k?ýþ½ÿÿÿÿÿþÕdR•¨É¿WDJ2oR›±ÎÓêUd©Šf3¦Óo5ŸÿÿÿÿòKk­Ê„y™bêìêt3–S’È5‹Ž «�,† 1 áòŽr�JâŠ0¢„#(@Xêè$,�âŠ�8Š4xD*…„ÿÿÿÿÿ’Ëäû×ÿÿÿÿûνey5v}úº*±K÷U2‘ÖgR™–tK"µoEÿÿÿÿÿéîíLÊŒE:2+Ù’}Hî8†fc ‹³)†ÅÌîìBˆaÇds¸“!…„XPr˜xñÊ,Š($0<*5 †4lüÿû`À³€²A „­ÁÛH"ô•¸Ö|ÿÿÿÿÿÿôM‘Û[VÛ²NI”¬ÚÖçbk3›ß¢ªÕ‘Z~¿ÿÿÿõ¡j‡»µ¶g*•Ø”ssB«¥r”¬QGª‰ ”„)å1˜0‚ädÆw<)]Ì($aE8pj‡ÐhÀ³˜À¢¦‰€ÿÿÿÿþ��ßüÿF—=ÆÚþ¿ÿùå®›±÷õÌk*"§f5§¢*YÕC^bºê§»LÜÕ²ÿÿÿÿÿëî‰wcª¦UÎ<Ê;0Ô=QÖ«žŽ¤�:³ó¿ÿÿÿÏé¹&q…+T©µ'ÙTU•ŒgeR á‡B32)—ýž·D|ïÿÿÿÿÓ]«Mɺ+YŒ[Ö¦0Ò)ÊbŽ¥Ž5EQ„ÄEa!˜\h˜AÂ!ذ ³BÃîg À(ñá‚ÂC &P 8|DV&Qÿÿÿÿÿû`À´€ÂA „­Á×Ç£4•¹ÿéä^¤–ú,‹ÿŸÿÿžÒ÷f»‘×d[Òº½ V¹Lës ws)P§z^¬t252]koÿÿÿï§£÷]»ÍÊS2•gsƙٞDkaœÔ9�Ç#˜Â"%F âƒDL*£¢ (B" ‡XÂŽAìb¼>ÿÿÿÿÿ±…åþY//ÿÿÿüæ©J$î”Y?RºÑôVT}ÞŠrQKjßZmu}vÿÿÿþ«ëzttz%¦TS•1ä#ÌÆ½�j=‘Òª”ªQ!0c ÓH,¢å £ÄÄÊ,¡Ñw‡È 8ç1Ðå†0¸ÐÛ ÃjÐöÿûbÀ¶€A ­ÑÙÈ"ô•¸}s—ÿþ¿ÿÿÄ@÷:XÈ®M*¨Cc¹§r”ü­#çDQz­ªý§µ)ÿÿÿÿýþ–ÑNbç›-LQl„0׳ )�Ük ;˜Â,5ܣŃ‹;"Š 8ЦA¨$ÁÑqÆ�\M…EAB@Áç( *ÿÿÿþ��ÿ-ã4Ñ—pþRÿÿÿ³¢îVlìU·K&öu+<Ï™‡tLììv3¡ŠÔ³I{×ÿÿÿÿúûû•YÑ ¥*«“êçªîR†Ð<Ž=ÇÔLU…aÅqáL (sˆ”ñ¨§D4P€È�‚Ä !˜€8ÿÿÿÿÿû`À·€’A „­ÁñÈ"´•¸ÿìŒ w"šçÏ’–«ÿÿþMÿÇýwóó¯÷Üu]fFÌÕH÷SR‰õô±×K¯×ÿÿÿÿÿÿÿÿÿÏw§qóßLò°»O¥O3r²1GÔ­mÍ»±å;=šSÊ8y£2lÏ#•0ÑÄÃHˆpò �¢¥�% « €ÿÿÿÿÿ²ŸÏ_åËzÿÿÿþþŠŒ÷Z2>ô±• ŒÌ]ªC\�È„VGGuyÕ(Êr¢J´ÿÿÿÿû[BUÝŸaj«ö£[‹Õ™HŠèãLRˆ˜«yŒ‡œ¬C%Üq]Qbì->A!Y�â†`£1\Xâ@`Ò y?ÿû`À·6A „­ÁâÈ"ô¡¸—#ÿÿÿÿÊ­ä&ʪË�ÕèêÊ}V¤1Ö³Fnn¹:û[¯ÿÿÿëmjÌës¡ÒÕF!ŠbŠê®Æ)˜†‹‚*‘LŒcˆ°�j¡¬*‰¢ï0p¥>$av!œXè4DHÁÁ5‡ÅĨU(p@1@ÿÿÿþ­ƒüŒÿ¥ÔËïëÿÿÿ7êˆìµR!Ÿ#£µŠè¨~ܦf5æfb1ÞŽÝS"ÛÿÿÿþßèÍiš£P®vJÖ®d1qèq”2ÚÈ0:Å+‘Tƒ6aÂbEl?2‡DD…‡‡\M"B £¢† ”Ácˆ4\6à ÿû`Àµ€.A „­ÁçÈ"´•¸´ý¹~öÿÿÿþT«Û"£—ÜÇž—ÑsÙÑhê®DÎmYd½îdSnÛÿÿÿÿéí¾­:ª3š§š•c%®5HQU<§!ÅEHcDH@8â(‡E`=‡(¹Ã§qR¸²:$&<(j¹‹ÆŠ¸  ˆhˆØ6­ƒóæ¿ÿÿÿÿ#í%)sMªØí1ærÚì·IUkwG‘rîGtTe÷Ñ—ÿÿÿÿÞÕêÛ++Jζ%ƱÞÈÄÌ<‹;‘XÇ8qˆ‚:‹ Aa6qe- @ÊAA¦`‘Dˆa"ÄÆĘ„@ð™”:?ÿÿÿÿý$ÿû`À·€A „­ÁïÈ"´•¸/þN_¬™ôëÿÿä ÷Gõ>¾J¥Ó:²�—G4¸±Q(„tC\î{+©•®gOÿÿÿÿ쮕½Ôˆ³!O<®ë!¨Žd,ŠæR1>‚%f0°¬@ê>qâ¡ô (¨˜åœ4ÖQ!0ø€ºX‚eQC€ÿÿÿÿÿÒäþgì?ÿÿÿÿÿ-‘œ¦ŽI"*ÌD£™•̧Y§In–jH~­’Vkg»T®Š¬‹ÿÿÿÿ•úÑÌŽäRËÕ®¬–K¦í[ÝF"Ψpá®ås ƒ”<îƒáC‡A r$ò 0ˆ×R‹ŽÌWˆ€ÿÿÿÿÛÿÿûbÀµ^A ­ÁéÇâô•¸½ÿÿß›ÿÿü¿->ùŞó/ß&@ºÒzšºË)¢Ô-^Ÿð¼Ž½Ïmûÿÿÿÿÿÿÿÿå‘ßæe ·îV›E‚˜6��Þõ$4C¹»¼­dPÀŽŠ$B¬ŽAÅ£E "£,†8SW©9 € €`5‘çÿËækúëÿÿòÿZšçTC£ú^5Ýõ‘œ¨bT©‘Üz-®–™=¤½ŸÿÿÿýiCž”èËB)©au”‚o,ÑÈ8‡c‡ ""@”AÐD¥*<:*‡ °x:@ùDEEH8:.Œ…Ї†ÿÿÿÿ¶ü¿ùëïÿÿÿÿ©ÿÿ–ŽÍ­îGH¢’°»NÞ±™ÄW%²zÕóØøDo“eÞÿÿÿÿÿÿÿþ_ü?)¹leyX†¿ç)ΜzR̈Ÿ"]Ë•L´'dxÈÐtS 3j±Û é àÿÿÿÿÿÀ~˜dsÿû`À½€>A … ÂH"´•¸æ½ ÿ#ÿÿÿ˲µÐÕc0‰&V‰ZâBÅrÌdpëFEyFˆm ¥*³¬Î¾ë×ÿÿÿÿÿ¿¿mYÊŠVÊÆ}LêÆ+>j=‚¨,å-*UcÅB²=� QSÎPèÑÎ"ÊY˜H  ÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿ¯ÿý~Æ(`JEª*!ÙÙÊbª”Vs ` �#³±Š©ÿ³”ÁB(ÿû`À³€ n? „mÁÑF¢ô•¹ÿûbÀ»€&@ÞMÀ[Àÿû`Àÿ€ÞÀbeetbox-beets-00724b7/test/rsrc/whitenoise.opus0000664000175000017500000004211215253035401021071 0ustar pieterpieterOggS’”ô'•ÚOpusHead8€»OggS’”ô ìŽ\OpusTags Lavf60.3.100encoder=Lavc60.3.100 libopusDESCRIPTION=Processed by SoXOggS€»’”ô &·Ä2ø®­­­­®­®¯®®°°¯­±°°­®°·µ·´¶²±¯®¯³µ´²±®°®®¯¯°®®®¯¬¬ø|™=êîX=#+Ð)1ãÐGÍ?ò‡„w7•¼´”C 3�¡§TL~wI>¡>!é\ ÅëÇÂͼ˜2ôÚÞżõ œö¢õ¡kæû'ô_y}>�´¡Sm‰º«Ã�Xœ´2ZRžÚ0剖ÕYë�ùÞ¼ÔÇ�;ú¼”ñk©ŒðÜìÙ¾Áë4PÒ=#U¼;¤Åõ; çÑÎŒxÍìо¤À¯“|R/u»O¤EZ ÄË¥\ä²PÐde´X ÂDÅ./Û žÄs=L†]J9fêkm?+?ý$JÄý‚$•æÇqí êQ®ø&ºwPÍMa˜lÐ-ª„Äž¨ÔêõÞˆS}ù¢el n¸Vÿ^J€˜|ú¶¶ËJ _"…`©R¯é&'0�ãüzæäï‚óØ¾Š 5ýŽa™?¬cadFœ[‡×7?Ô�1‰¬Ðu¼;›1€ÙDf&ÏP|l�h{hUï�„Œ(¼ÏÁH…ç-:mÿ9 ½ƒN/„ƒäùa€Š›•ìá0–3 çã.L)�‚Å©dväëø3_2õ~o YÄÜÑ?¸›s°%r�žï÷º›ø+´š8§ÞΘ7e̶l�ן±F„þb©ß°vó÷†¿£!–ØútÕVÞ0�È*‡‘�úh³28þÇ9ŒfꆣðѤ4=Ÿåk²±¶•UûÝ` gç¨Új÷ |ÌÕ¦ÿÇøò)^«�!í‹AÖËï,ïÇQ�,VÛaïd(ë¿QÝ÷À^³K¶µ°Âø+*ÖD|³»´3)*÷4ÃuM„<—ÊJÈÜ ÚS{™�zmç~�¥‚•Þ|­;Æ`2™øÏaÏ�9 D]ØÔÉ›Ø÷ÙLÛ�gÀÂ�\ü3.¡HÉ'$KY“„ìP‹\/� øhõ’pUÙÓDlùÉ_˜ßº\Ügîè-å¤À/Åœ8ÁJ¸6¥¹ë|ˆof»go”�%çØ>@NuëêEsR%³‘ìu_×Lùäø(7 WJÈd0‹\ x¯Þ¨Á)#£ß¼Ó¤žµ, ÊzBhðŒ¨�ئ¬ÃÃý8¹*E/™zGù×Ìswn›(å�&Ür_@šµØ@.*ÛkSŠI™‹k„Ѫ"W3±&Ù +zl‡‰ª/Æç$i¾†£„{•=øŸz#\æÖK¸–º­Î¾Æú´úI†Œñ«æ¬ï,Û¿P8!?…®‚\õˆRÒz{ëø3qLÚôNDþ›Ä˜6…ëÑ~:í©ÈtC)ÃâŸÇíù†ášJ…ªUºDР^šoPë.é¤fˆNNë î:,ŪÚx³"o)¼6(Ž»ŠÃˆÖËi1ÿwu àîî[M÷–;…·&òc<@”äº\ �çDïÆ‡�S¥]õÀ÷¥R¨Ïá”N–A�2®äóOk¤�qÚÆ¬‘í0�^{ô‡È)lø+%Eí,Gr鎎ÎOWö¯$á‘“î9zµíI0íÜ" ë’|PA.)VÍ_ÏÀ—‘‚ï¯9a®Ô6ͦý¶ÓNÄ …ºs³VM½Qâ°­ÝÆŒ|ö)›º U(S¢É¦ÖKœ/BíIè=Y‘æ/.i­É–•Ñ_{¼óï ©Éê>2þŸ/jõz÷¢ÚZµå@þ0»fiÂ-”ºˆ~Àò¹Æ¥$§&>¤?b[®ø3_®ðïÇs^• ME‘¤Ë¦Â~‰òs<q†w³è¶“ôu¤&¯³®` vOÚ¹eA-�}œ–þ§=~z®Õ0<‡«a©T¼�è2ž*hç:uÌšJV%¯ÖŸèP{¢âÚ†e.e�À ¬/|NQ³jMpŒ‚ãË #æ½eÐhèNÇ-¯¿?Û^R © ó3Øt>÷d B‹„ÕÙ`­ŒÁ�§\|G¶V²–Bø ?Z�°/‰fÜaµ:ã&œEß´:áË ‹D½€WZ¹µn+ôê˜~°�(‹ esŠVä˜Ð…Óæ‡q?8^µ³Ÿÿ@¿ô4…ºy·Hàó.,w ñƒãÃj[^Ë0�~Œ®º™‡djŒF~ÚélÏä“÷!Y6ϯ&Ñm|2ã,›©`HüÄ<ô•ìÇ•œÔ¯‰<&¨ºµ'öòX¶áº>$¨Qø¶� ›ŠZ{YnÂN˜\`hÑ„%)asÆ ÁÄgÒØ…pš³çÖ]j´ôÓá5¨ô$€ÇjX¡!"’c5å=€õÚö Ù:Ä IËÕùÐB5WXçÚr�7'ê�0DÉ~‚°ë9ì5Þr=xw pÉ#/¬ÚÏ$l¥}t¬y§Ìñ·*U4“”®S–(ÌËm%•¾u¦d¯pþoø Ä…fdh0U=b™†N;ßúQ,�’;âgguheÜø 'OùtÉD+—ô]¸;ƒÑfšóx·}«Ç8IÞŠð4[<ýDdXd~‚í»«Žl<ø%W½³¢¢[�2m—8Vn¤%ñëçžÿí¨À S—x,·ò¢‘Œuž´Y/ x€?K½‘Võy®\ÌÇÝ­ú÷åRîe´¦¢:?1…»yW8ÂÅa¥O$³\´ƒÁõÅXóøF´åÙøƒÔñ_†ByþWØùPˆš}TUç§Òš3|ÕRúÌ9{´¢¸o·Ý/:œt ¹ì´ý\{å¼øZ]Àñ'‰ñR‘…‹G™¸)ε�ªÕàg Ç€‚}±rò™ÈV÷£³£¾Üi’ ÙÆ3:rúñ׸INÔ0î÷Þ2\ÈyìF‡ã¤õ¶Õž±ÆV^Ä‚›‡úÔêØ“>?‰W z–މ6¡Ô—–¯Òa¾+_ÇrUÝ¥ø5Áb)�OßáeÉG3É÷~Œ’Ed2y�FAksíczõ2A¢·N·IªàñÊdº+¶¿ VÍÒœÞ^¼/‡LÉ‘èÛ›…UªÊʽqœÕèUû½9yé�ÝAÖg¶ßŠý²çQsS Ϭ»ÂNކ¢6ð„Ät�UàŸ¹Cê¥ÖLîV#¦N·Žv¹Hàï`þ`Jq7¨¦ÃnlŠï-ý¿cãpë1Šø2‡ÙR€þ�³0pLBê”[«°ЍÉ=åx 1`´ºb0™Ò©Ñç^T #Âɽï]_¿æ`»ÊK)E¯RL7¢ Iቲ§…ãÜú¥Ÿê\¥ô\‹èätÝ|ÂÙš¨âpÿHõEîÆFбmðY‹“@o=Áé™Ådç$³MÅÝÛÏoK*h¿ãÖÝrR(¦þÄ'æHIdcs7I“´ $&5Èf¨èÅà^JÒ�*ø3^öÒ¯i Å÷µ4sùŒ¥x³{ÍÏ;¢®fƳíñM}u��f+ùFùsaÀ1\ÿhÈL_5œ—òûd£iêyî� ÆJàr>|›d_7±a{têB“ÿÍ\Œ’Þ–§k 6©($Ê,ŒŠšE…ÞÒþY£²ãnâï5¶ vxÞXV•Ì› vl½jú^ˆÞ„gJƒˆáÙ÷‹Ëáw çê;·@Ø|H7÷±ŒœøI‘/0=6Œoð㥠Tã�!ä8¨`@%±½õÓ—d“׃ïeίÞáäÂZ”ñhþŠi›ûÛzó‡Í`¼Ððg;;H’‹8}%û±ƒÖŽ3À—DÜîxi¨3‹îBÏ€Tegó¤C´à¿ÝW‡˜0?,IVµÓ¾—/Ùý_ü ª2щnVw%¨á�9ò•â(” Îç·ëËŸ€\¿==\�)óRšZ½;²ö6ÇÙø4y%¢ùõ,Bl6å!`6áûT(ó –R†Hžˆ»#´P/rçS.…‰‚Ù‰o0ÎÞÿS¬ß8ý@w5³#AdÓ*~þýÈv kæ“iê)Ãd6¨‰?¡Õú¡Ël¢„A¨â†áÂÉ$6‰o_ì÷þ‹Íy«z¸ €wXêÚéäeß ºmb¤Žï�©»ö{«¹8"¯3€°™zlüdŠº¢“&Ów5u{H†Rb;‡õúêxøI‘/0F¯½y3&PÜ3{+?qˆÒÙï{“šÛ˜…œzœãüB0rÄÕéþêêï‚Cͼ±;ë‡üã‹tÛ(,RUw-«I‡Oç!Qð»�¾“(71^ùfã;o~Ûš%?ój@Eý—Év€Ü,Ü7yŸIÊŠd±ê“ø’Éš6¥u?A]áÎ¥ K(‹(áêüM…»³Ô�â©ÄÙ¶U] ºš¬^È=÷utø3 ´}¥G�’zŸÙUº ³/�¨¤LÒ§–m„�EÊu6“ Á'Ñ«ðSù*µ9¹©aŸXšàc1µÜO©ºP“\k<~"ÃHUbtŽË®j’¡“Rø‚Zê†pØQ”~°—!(OÅŠréHÛÒ•o¿C}\ÙnM%'’�©cÓq \RG•·ÒE±qÉRx.UêÁÕ,÷v+Ä$OÖ1T=*°>llKF>TøÁ.¨êÅöe¸!ÕÒ8¶íÄçþž|´ @‘­%‚Õ�²�`]°¬Þ`!ÒNòpçŸe -‡”Ve÷T¬0zðÊÌPÔE¨Ï² « LÛD;ñ6OðPÊ {­Ï)cí\lˆÕþÈåú,W¶K0Sä]êÑäŸ4CCb»d9–t÷1Œù»x�¦?ìFŒðHì™wmpЇUays9(›„L›P©H°›ßÂæå¸q¹�õ—½÷i\øGZãî �¾¶Ì¶ƒÎîóO„àI«V Å ]¢¹l¯½“£ÉÈNørÒ‰k¢Qõö9¢WfùÄWÈ·öJ…q×ü�Ò"+‘D‰0ü5&Ñ�7•\_ʬZçd.³O?Ó)é aÑÙs/íêõ‘¶9{±ÂÒ TO'®±å›‰`emÿƒ6DÎH½Õù�8ିæð…P©_gpGR¨ÔµúƛѦ<;Ì7»ã½Ü[é‘AÅß³�Dø(ï�*!í ÎãÍ,ç§~î¶E³ ‡…›Rd “S�GªÜÅ|Ö=èåPŸG©PŒ'ÀiޣŠ‚ JÿÅ+£�`W‰_ÕØß§Í•g�NåøÉ_CÚ«¢²�S2nÑë¸eïü8àÉß$âßðÉ †ø°ÖVNïÆÛPƒoRÉelkKö$›¦§ÿIÈiVòç¼—â�1¬P"Y!@3–š%yv…aá-¿Wø áQ³s I N†)·íoB‡“xió@É~ôÒÏéí‘[c¸“øÏ†ù2àZ% ˜q° ˜Ô,!<�W>½ K‰ú­˜ÆA~^…¦§Pa`ý˜Édž¹tB=Ó)bÍŸ^KòY'L„Š´ 7"Ó>1Dj—6uoðÛ †S±ü†íõ%¤ˆ*üf}E>¶þvŽÝHVYÅ=úå3“S–‘p›Â5QjYC{r9øXþ-~в!ñÖ“Úekø3 ­E$.¡Î¡ò%Øš<@ZœÁ�î+QGšîÁn�n-°qø^îÉÔJkEp»Œט§?¿)eö³‘U-ÙÏ\µ2„oÙÝgê?:ìq@?ÚÔÁ®ÅêŒ÷Ñ$;å¦Oá@(uÃÑ©”©YB6ð‹Wq0¿ê!V�±2ÄÔ@ ö€Í/U¿ÕÿQõÓwEßDþÖó…Žk-W½¾S¨ñÛ]àƒÆ)XMñòÑÍžÀXœø+KlZ ¨’«¶¯s%�>WrÍ^jº]1Ðp2ÉÚeç%ÞW±Nt8.5#¯±TNüX•Ð31á{û¡Aò�ºTÚäW”Ë‹[™Îu+Œ¿,.ëU„_lóŸD­€S6ß#ã %'Ù¨äRE>\­å6rkÕ“Ú~˜x7â°§bYIæfÜ¿‚ˆÏ…Y2Ë‚¾ä¯ètëÞØ–š¥4[Ýb h”ô†„}fØÃÒúsø+ š9.o» `çÎJ�2§‹<��°(´éä^RÛætp­ï´]ÂØ $� uŒqÈÌȨ³Ö`�{ˆ~¬² J Í—Ry·oÇj<”©%CFxc·­¦{ Ð,£Ãi¸pþ`¨?ÙAò2Ê,Êþ˜"þ,»ôžd¬ÆËß¿¥˜dÆ]yQÖGÐŽÚ¨Ó=>¶øDTz,Ç�çœÏ(ÙÄÏæÔ‘í‹Ô=wôø3 ×àE+ª.Å0áü¢±ñk!㈽©óËeäٵͮ{ÇvO¨ˆtÉkO2Žºè�í¶úNWõê�Ð#tY›úD¼=€Âi¹—Àú8 °{‹¤¶§ÿºŒ«=¦¾Ê¼/áüó&Ï]ÿ¡•ûé")‹ÿ¨´ÒB�%1yjèaŒ�øÕÓë{tˆi9.Ʊ{2²ä")&#µzeRêè_àŸ¤m‡í]irãø x¯ª/b°¸—ƒ>Îi_à&¸ÜÛþF¥ÕüÌ`IÛ=àšŠ,�SÈ*{£Á— O‹´³íAQiþ«kÚ:/2àiwe‚ªÐ˜i‘'ÿ «åˆAùô'\“·™-‹#"éÐòß~¢§&È•kó,¥çïæØv=ð¶MÓK+½7þf7訳ho0²òÚ&Þ²ã½&�º µF¾Ç<ÕeìÕ†�3m…0¯ž½D,¢²rÝø+XÞ¬ÔzÃÝ«û¯±cµ²eßCÂÇY†…e,¦ZºkvuÈk1þ �êÄ%?gIá1™]µó,ÞÄ'?ûáï­ÞM¾à„Åj–¢GµŸ¦Ÿ²E75Ê lÑ‚¶ ø­sœ�(°`Í,‹!Ù†À²Ï§žÅíàÉ�_`T`?ž¨ïëÀZR=—Ôñ}©ÞâóÔ·Xê¿pðDÛ­2—ö4žŽÂ6¥&à$^{ý¢jÊ1A¦Yövø+—À Y‘4â\ ÙƒÖ+b¦$øû羌™‘Vv‹›^�$ƒÂ…çÖeQFô\Œ1QbËæ~<ôöý¿vùr{S¤r ty˜ f}z.•©×ûYêŠØ©ï“șޢ¼¤Hu¥·}¸²cœ›Á¦Ä2Rƒ³¶‹Ùn¼ÊêLÂÂVůû{\šg¹’KEgÇu;g·,› ˜�6,+k(ó“‚ß!ªÝ“ñ±ëãŽ4›øv:6'Øií´,ý{€Ïc/6ÿ§÷^«¦§j\d ›O.KìÝèA—�€mƒOTî—.œûa‡bƒàç,PMö“›W-½IÅò½•ÀR”p”u•n}˜>_nÀz<+ñ¶wÅ~ÜãEkFhXj˜Ü†¨mçwÜè±£n:ÎW™ðO¢À„…o:d¥†G]ƒ"Ã.Ý�0ö,Æò‰¶–:ïl<ÚÑë¬ÅáÅøF´æSDÏ2‹5]кÿîz¬ŸI`¾’Þ÷:ë�·¶í¸g Ð\�\œôs‡ÉlámW Ð¥ÖTzúöi$}òÚá¤ÙÝo ª5£±H÷ƒq/˜Ç`k…yUèr¥$�ÃÔù–kc×xûM¨­È®Àÿ˺cŒ,w]ôSíÌלôYŽS�è{Ÿ>ç¼ý‰ÆÚÉÄYV xü6m¼Ïù"/r<Ò»äÄØÖoþ³àø(‚ŠL¥­†±CZË•ü“9*-uFåÂÎV*Ó|òº6Ôç¥Äpwf pèŒ�±èš›öuik »$.LþR©ò#9¾ad˜PÐ èÖ�ãJ—�âÆ.¸0[ÜÍžºo¥PÕRHp±î§¯ÝÂÔ ^úòúç�¬uɱN«ÈKsµC*¼Üc[LìD„Z2<‚‚0ÛÑÊòS°2*åm¼¿�Lÿºu¨d+¬eôø+ïÓ?}#é!¹¨Bc]¼¦Àißq+IÇ‚bmkˆK àM­ºJhÍ€´±g4|¶ª$H)•Ã`ÀU¿Ó¡\ÐUW ÉXER8�ÕóuCjÀ¶ÁM¥úf’ðÛßàÒìe-?æ°¶P‘aß~Slà颸C•$/~q^MšB–3Èl¹XU@ðsÄ>ÜGŸ6ʰyG‘­7þlr'{ µ�v�®ŒP¸ºlk2Á;èø Õ‡Q/Ây.>Âøyô€ùlL{÷�x½ë6Ë»xU^mÇéîx´š¬ 0cY+J‚köåZ7ÎQÓü­VjÌMkYCL¬Žm3B•¿}OgÅÀ‹6̸¸Ë‰mô(‹Äðfw¶Í†3±ÙVjz/ Ìµ”!QXREºZMÊÁ«ŽIÀPÁê„keã’q‰ ­ÀÊ=ECCƒ•~ófT’Š-.¹+„Hz7%+ÆÑ\uhÈ$>\[ø+JYÇd®¶Ùjsöd²n4±É ë4jú…EÍŸÊ;[]Õ¿NÁ‡T ¦~KÕÜP½ÊÄ’I�Œ…2R0Ðèßy„WVmY•”‹nˆ‡£Éâ”å»$IýŒ$nþ©¼*®àT¥�š…aå ZZÝ /º|J%Ï[›4þj‰�‚!Ó8ôBì¶ò>&Y0í™ò5vK½H?§*^:í 0Kb}dgvP`ø+%G&cO§ümˆmÇ¥¾»´E³¡náÉ�K^1þÓψ;ÇT<ó]ÿÚº‚v/c_Ïü´pþe‘•ÌŒ ¤§)ðw~¢?â¥A¿¬ÇL¼Œ%ߤ¶;ѱÿ#• �1�j¸çØW{&¼cY["¶y¬W¡Ìf'ý�—ô&Ÿw°2à˜dÍý´ ÓzC’7¦<¦tµ N…çd\GOE§»„Úôg@7óÒ9ø(:yãódc8<È`[hb [»Ùđh‘ ´žcÇ™ðº©ÔÉ¿/¤3¥(-w ­žôÆ- %-¹Še†“H,�D’50åÊ«„4H&˜W9P&µps�08õÎÁBl垃ۙ¾² ˜xÁIFÒÐÞRó¹ú“Hq*1 e¬^ ¶B:Q°^ !OfŒ{°²;£ÂÊ�°–©™çmÉ®þ5‚HÔvõø+%Ãî�רb½&@‚Ô¾ëé¤a}#Á¢D¾Hà��N¯U]``ŸÎ±sþSzU³¥.‚älb�ʺhuI&[çLý+Ïñ[/ô`A*)~Wýo+Mãz1×øÄAN_ýòj£I®Ð„¾>R²ñQ{ôdn¬’)Œk ãFì¼e�Ëð§Ä/ê«ä°ô†¼ý�ÛL¬ÓVE‰ö+A·³Ö£m_ñ9vø1ôØ-¨ë\3•Rìëì3Ú[úñe¡dÇë⯥ƒKdüis—Ä{ ‘FV¦ñJÇÁÇÝ!å³ÁMy'Þþ‘.‹ÅÓ-“.¶ÅÁ>è '1�ïj{Ç�v¤êü<èÂ&¼•²IœN‚J±HAÙ+ë¯üˆÁÁË„äï»O3Æhß6>Ú†tø_©¶ÝZXéѳÑùôï—¡�Âêü´‰T{t‰ûø(CF­4gåO^L¡&�¨öÅÁ-15oëêuCÛ"3aÅŽCë=½eù$Q68Oh¦Þ¦ÑA²)Z�ü †j¡teŠ5Nq#ƒeã]‡F³ÒˆÒŠÃ7•ïEnºè¨µ­msÈšuMû\²fìn’} ó¼Oµ³$yâMŒŸ êz¡ZºÈï·Ê7zùJœÌ¯Q(ª§V–Çh߈Ð$éP)جõp¿ª¾sLJTOµø2ãž/—ùÉû½âNc;n»ÌÚ`yY ˪�¤.xô7[Õ—²°uø¹û·æxº€²IûL[îKªzÔâ÷ævìý@"·›_Çáµz,ÅçÚäÒÃç™ï½°Y蜾l'&¬ÉŒñV&®«<ï–ö#ä!ô¦ZÛnƒ&-Ð[g¨ß±Å7ë�µf7.x/Ú€á¤Àû¼´cãõ»üø,Bð«º,ȇRWáÃw,[ƒVÓOˆM…:.¾-Ihµ„ý«w¾u6­ƒ©"Q…Ž;«a`±Ïnòkåwèº�âb]lX«C(3Ï_2�e bß% Ìç‘êï.W– 0Ê<Eß5+• @¹Ïk3*í¸´+ñï‡vZNÖ+3WžUš­!8‰ßÄmëº^SÚÁu#¥ Ã(Þ[3™›“�><(ž@|?8Ïb»øGï}Éú…ŠhcÒBŒ'·©ÿ7‘4M‘Qô2ŠI˜©Uá˱¥òNΪßÓ_<¶ê Áªy�¶Ã_](ÁT³(‹W´˜~ÒêÜI}ísV�¢œoH‹Å¤Îk�Î_vÕÇkô0,z•¿ ¬:Í››qã?‹Õ7__‰mIe åÐö“{Iuue�9Z²ï᪇QYáU0çt}I~1é²Èžü1–ARüuƒcÿQqø'û…Z¾ øÓ�L‰Z#Õ¼9Ó;cs/H»RuÈéÇè¸FGÒÌ:s�sŠÍÆ6¾< ØŽ[K–GwvÍ]‰°Û¹=ö‡¾Ù­Š¾5¤§DóÎg£æc•ᘟò�ŸÓ“p-õH¦~T"4RFÅ'Üf\¤[iÀSz„ÅÁ=í2l‰Ô: ÿ ¡/g20U&ѯiÎþòGâäebátâdCÈ»=û…ø€?ËâÖ&v}³woUáÜ�Yýð"DC¹äk¶p(¦ÔA„NTUcé݈âšWÛÓVº6yi:â¾îó:ciç~»áñ} 6º‰co#Î2Œ�ÞÜŸu—¸aÈÜ8®º²Æ:W¦¬^.ºfì7\:¡¨¡3ðäâ+Y iŽÈk™—ì³´sòe õgHIèå”Â<ÝM4‘ß¶HÿçÞü+|~nƒ°oâ'OggSw’”ôi—Ù\2«¬ª©ª¨©§¥¦££¢£¤¢¢¡£¡Ÿ ŸŸžž��žª¥¡ ž�šœ�œ›œœšš™šš™——øFf´§æ×­’qãl~PóJUû^¿ `é\÷ñiø«‚2níw f~áAg ¶ßï´’‡#D¦º}¤6ûÜ.®‡ �Ç¡–ÉrÒ,Jz€Xà`ÇC.øæ%úˆC…Š~˜›¥3àáb@`uFÇVP.§k¸ä�ô(ë°ÄÌ?i¯€ 4`D(OŸÛ’¹Tò¡ðyRš8sªä.Ùº�Î-L}¼³‹ø”Ý�ø(¡ßš˜â°Û‰Æ�O©ôxcɬŸ ™$N¿ýYàfb¢e¤J9ûâMHܸ_ˆ"whj—IbéÛƒlM?·l‰ñú`åf ¢{š~>¨Y ß))ÅäùHgÛv3�Ãj]€�)?¤èÛÔ3 u<�—ÿ¡çs¦a†&!{�ÕáiUÄæ÷^2~æ’eµÆßtZ–‰'S§Y0q®iÏiÕÀ-ítGGÕ…ŒÓø+W¢r[ÍüšD"°ø�FkÖ©%éøê&aíÈc¡£îM8|Ø( Ö`[Û »ÏLÛz¨º¹Gœ±ej|PYÝ$ÁÌE|ОΔ´‘í;/Ç'¡8wÄ· , û}…ÚÐIýáZ·€�”D˜©¶Š×>#Í̼×3rî‰ÐÕëŒLYi’XÿÿëyÝ È~AïYa”K‹Ù^ðvÅ8/à¤ÔnÍ?ø+$ëŽGà™Qð…Ñæˆ–ta÷ ´'Z)Ð^]ô~À/´@~S_�ÇžR­Ö“yâ6•…Ë‹Q¥{|]¶Çôœ&Ì@M?»ç$骛å2„©¾!ØŒ×ÖÏ’¡¯¼„•ìÒmX4qõÕ8jD\æÔ†­ ˜…!i¡£Q«ÛÇÇ�š *ÙYëduÏÏd2kžt¤nî8oV�)¨Îk¶î$|4§ïäM&üø(–L=L÷9ÇÀ€SœÑ0$+±qwñÓ‹ËQÚ2{Häâ+Þ’ ñδ€ÐK±bó³*p`kp (Æ,n÷âàw D¢ÀgÛ•<²߇®Àœ1Í96råÆJG*²ù1S¶¼ö[Iôä¢ðç¶¡×Èm}dÚŸ�!$âͪ —öÊ1ˆÃÖu¡Iu9?d²*i« U�>þaMÔv>oR<¶DÚ¸½ýø+JYÆÁt˜²ÂïråSÁíÿ¸0cæJ� Ìi�õ“8Cp€¹TîÂö´—‘¢1êß‹v×/y*žIN*•¾à™æÎe1ãôÒ'Õ'ÑcL¶©iÎ#æxŸ“¹oÒº°×g{²¯t5îëÉ 7»ÍØr€çõvƒ±·YÒ˜˜uÖ–cÌ‘&c(-;™ùiØ:B®˜»¯*nø7òBl¨v»†jªø(s—�˜MÏë3±Ý3Â÷³=æšúùìÕ%‘X¹RóH²ÅÌöU͆X82WGÁæñº ÔàB6 ~çRj¸Ë9`ðÁ�ÊþÙYTè;+UíœûßÝËLïYa«ÌOùMÀëÈD‰ô»~ä*¡س`79e¥L “žj¶õÇÖú ,ÿ+soí7V_TOæÓ­ú|šlÆ´§ “²ù:uŠÖ6{µø3_ß–~EE¡û4-cÇÕRlÿ‘[„p”±å�ŒÐf ¢•¶NBøR¬r’DO?aÏú£CZ†ñ?vNqXzE0édìÀYcF%yi£°°wàöª­ÁµŠþ˜³·ËŸ‹;ûM\(¥±—ôòëæ-0ýã„¡ç&Å ¡Ñr~Ä1DÁ)*u]Ïžc[J²UX±'°i&ຫDµÉz„Žø&@ M‚+´·?êUxÌ EZò¸Ë]š�Í#Þö¼÷v¿¢?™)ª ­L”S3‚2' (�¬KCÞß >:F:‹ö²UÁ¢W\šr7ð‚%ÒAlï2„x™{:Þ˜4ñúh«i7ì¿ ¤û“fB"éøâ®êÂn;-fl7WzpÒKÂjëh­+JQ×§’K H�^ˆcÅ í”4ùøWõ*Þø4gåÀnzìÖâÙÛbÛ>lë¹T¼&c'êuB€€7½×òÇF†]—‡H; ƒË’9ɰ)óJ)>g¦¢#tÑ“NE¢K#…6—ˆ_Ëålu,èW »½„Ài¸ƒ&-ò¢‡ÌnpœY„ÒžüÍwç|øÿ¼b€2ç0Î_îYÀ S°~¸’OÁC†×'CSæDZ„”½zz=Ë �·”ãÏ�2¢…˜Èø ØÑDâ!t^c"Ù?5#ÈzÃ~Î"ÈiŠ�4³íȶ9ÛýÊ2µIèe!'üû˜åjÕ?ÐÕé@ 4é{„¹ÿAuˆMü_gžC&�n+¡ÄJ%ǵˆæˆ¯œ$®Á¿ ¤•ð�楯©Sëž$§ø++šƒ¢�Bϱã‡ëx‰üEìc=CyQ/ëíÁwõ?ŽW¬í,¿gÍ¡huÇ §z�z ßШ«Ñ~¢a~Ë‘3X‘bJðø—ˆ!åÂë‹ Éã¹ t·¦Âô5’`ôÁ/;KLB�%¦Ø/¾-d=€'¹2ìG�Úà÷ÐmSQCïHMf@#ÙØœO�®dí1À 2‘Ù_.ª%mÞGoø(ÆVõ¥þ�ÄAc6‹Ù²ÉmóA¶ëBÚÐÔ^¸Ö’k•ΡUj½ÄîdŽ/pÙ¯ ¶G$˜# Ô�Þ¥·véQ£(>[ö*)¶M�çóiÃsõâ­áª›çÉh…Šã ”i °Û�¦N* ¼¶’À·*³�`VMö¡Âøº6O_}áä ÏrnÆ•§­ÞúB$%6Ö8®Ø¹kü ^ø+&’õÀ7òä+hËÂçßLkæõ´ÅJ 0‰Ùû@׬ޭ½$¤?_ÂÆ,¨y:&ë³9ƒ‘¨YšÜ÷=ýõ,3_ÃauG"97‚[†3 Ð,»ÂîÕ’)¤?4LV|­"†z¥D§§iùo:2Ø/C`ݽxnoæÛˆÂ§ÞJæü/?d;ÞtæÐ9ؘ¤i‡0Z�;ÅRØ‹¦¬V»Y¤÷ zø+XKiš(‘Ñ3 Íw”“>2X̪Yaˆ‘Jçä!“ -,€¿xÐR|ÁÕ¦ê¬Áì�p›c 7ì­á}éj@”~˜[—@×*)]“˜N!žÌƒo¾/ÑD#ÂÈÞø(­”Rì }êO'1è ¾`G?jÀ²BìÕlº«êQ¼›“š±ÅnAã\‰×]�‰¯9 uä!˜*o¯(‹2ÑæéM(ø3f2wG´H:ù~z[L~è©Å¸ÀŒq/Až8‚‘gŸ�SMéåupyt]¢ÑÙhk$‘+É™œ¥jxž™ ÅðÒ-ç¦C<…ùU•¤ñ‹¼ÁR0ù†\-UÝE‘,Îcš ½<¢‰¬"ö¥"é¡áçˆ EžÜŒ›£ø+<à [áö”â~™ì[€ß«”ÞÚíc(4PHñzw ë­‹ib½[lævaá|ˆäç�¨ð+%+”ñÅš±�ìjZ;"”+„@9¥•2#½€·ÚÛ¢_Ÿ8ôná(gõ:~B{P%"‡CDk”9o/½O¼’ i)O¸@)ìÓ¬l¢?ÈìD7e2ëŸÙX¢ãH9ûûK¥ È5öŒ=óvÆge³ø XÜÌëÝï  n°Ô]! |àï×6}NåJηT°©([Y…× +S×þ•þ~×ôê«¿ÿÐèΛˆßæó/�ù�Z§[ÉÉ_�œ|=ñ /£�ßRN­W+äÔ\o%öÑCdÞ­À¦PÌ!>ºÐ¿ç¤ü£Çêq›öZ€·e]‰ÃÒöïÛª¦@åcœyë„ÿm`“¥¿w`S§ˆøù&wøJÛÌö–ÌÉqXiËB¨ ¼±*ƒ€K›7B}*Ó8;˜e�U2[¿¿ÕdiÈÆŠÕF1.œ¦.­Š/7;wpðbW¹2`~(NpAÄj:†¯ÊdrÍ3û÷°“_¼åe¬¬~�;™C<²®éF ¼¨Õ B+¶ú“®&!wŸß7bòùù¦ê�ý�4ìÙO� ú^Ü-ZCø ²€¸ø+U¶h^ªÌÕ*¢¢o¤E¦özOCgØ��a�·î�¬¿«[—]³ÈÅ¡ÞNê§°qa/“£-�\Óí8¿·J(5è|£ù¤8g–Dut“%Ùà Kà¾SAÅ]G8Kí�˜£ PÃeÜ%yâCNàw /c0›.‹íeký«­Ë< �lübŽ ïS'‰§áPy¾�6±Úü[¼øGØnOÜöúÆçÈÓ‡/@¡é‚ÏÜ"¼ZøäMNypËz€+ ¼‰YÁ(¸ƒå,Ù²íølñœx§ìräkúVºEZòçÞN±€h^YàƒûÆvÛ— ¢ì¢Áꎯ¾Gu<¢•ÏŽG„§q°È¸/·hrÃ�îg�ÛØË�½�_L„÷DZ�j›ù³„=:Nc#®ÁHÕ�Z6,‰ˆø+RÍEJd�#�†*�4 2¾M;‰íÖ¿-wsÄ—0WVžæšƒ²±r—©¶Óý'H€ÆA‰Á'"•; •ÄÊñ’û°ÑC4h²Bä4ò�}ÿ:#ñò³ÊQ.³»Q’}«Ø§ 賺ƹn‹³áTëi ¥À©Õ˜{½ðc‚­´® Jò°µ¿2pÞäè[&/¤„ŒÅ^�.Zï5ƒø3¢rÈÛ®íÇqÌuö7 %¯(TvbZ—=˘¹Å^-°¾�á8òzk�Ü–�m1ÕmRc…Š…jï~Ô*Œ‹˜Ï-�”›»(ø2pZü@'¸>,ü� T»+—,øØaˆƒÁ(x‰¨þ câ}_Ö6F¼†¡Ìé}lõa“=v»Ñ~RÜÊ©qÓ©NŠÑÍîUTùÇo¨ø+W£Ù½Èº—Ô¿¢Á:Ê·yo½ ê— šÎÿ˜‹$Í¦éø½ jJ?é`:îXâ @ëBÉòVté"ØçègõÇ'y#ÁziEz³!ƒ-ûêš`P2@Z¡õïÈm†Pàj¸ˆ\sƒ†?q�®šÛ™H1pÎ�ðhHêG¿9Ü3%�´ÊeqX„ÂŽ:ftfY¶û_A"5ø ÞÔ"ÃOQ2Ó~\'÷㪩lñWÜLkÅVÞä6;ºÞC˜Í�5N�Èü'Ï®e¬£:» â[�’-Ùvcˆžx–¸ö`B溛Ïȉ0¢âõ¿;«'Êнüγ�´H%cÀ1¨Hm¡&*5µvñ0(ù7‰…ª§†Þñ€‘ØHȱAà·›‹í§9Ùà‡73ë$u»—ø( Uh'ñôaðÖ¥ ŽÕ¿$@›”FH®RfäªËtY'N›Mg·Á 9£ùV¦ÙÈ jžZíFÞÇ£i†wmW^Òì�ªí+çÇÞŸÂ03¸-'¢!EJ¨–è–#<µ Iÿ…!>ù3—RÎÒjÿï¼Õú)´O¯dB  ‘¬´•gaKYÂã(?ˆ?óûÆ7zž6ÚÿŒ¸¾øJÜàÛ,²ÉáS€ð—™¤“ÒmÆqc· Ÿá/jè ôv`ï=›V‹b—æˆÁ‰Fyë…Ú4!BœæRvîジþÍ]HqIí�e\ ÙˆYAA(ê«&þ»J7(;Éq·ß‹�‚+莂GÖ °¤¬XId&ŽMT3l¥€>Š~žáÃ&|m2zëf‰’C&³½ H9±ó[Âøø ØüÏ]Y§ÍS±Å‘'¬—k!x ´ È5d~ÌWNwÂÙòv® ]†½³w®ÑhÄ`ähÔTØ(:É™HÆáÏŒ©4Fבíﱬu²‡DàTæn{²UUÁ3¢,™/´(ܬ,ˆA¢.°^x�~1p8”–©Dùá:6%xctëadGvË£@G…â°Ø!nh´´U·7V}.7â�Rºïø+©¢Mùî›|æªOrÚÅÖöjÄ@ýx0éÚ°ÈÕh_ �îK@šE‹ÒL;ó±%¥ܶ3ÈcVcõµÕr­ÚêùgÉ"Ý·órjÕØaE5ã¾ûç�‘Vq+¤_5<ð¸%SÆp´Š³·DY"VLz%}&�UvìZ¢åÓ`ô"j£´trwî!ÉÖø×Õ× )þ ž?>*“_\­ˆUߩ־ø+W½_–U¤\l$ÇÓ súœ(q¶RþéJ3 ÌÆ°!\É3]ç)ˆÎ²ts7š:¡›óûu1²{Þ°Ê:ô›<³Ø—¤¨<ÛU5 ÆÂä[·(ãÚ˜§wêåKTáÞ3ùùÛ+§ô*Aûbƒ¥6õÀò,®¶l4éZºÝEƒ«´%B O¶úåªäÉ“¬G%~¯Ç3GP‘U�Ù�²|²ø(6vßJŒB¾e¡9÷ÔÕ&?O©$÷¨Ý%±jÌ^!ÿËžÁ¢{M<':pñû ³[E<~Óvª„˜VµƒÞMêÅÒQ�Ò¨� ˆäü³ÞœTUÅ*‰JÑìÿÎ{ƒ.†|Zãl� Ix&Mε· R$¡ËùØ�H8g»”nLìU{ñ�ò™~Ù9RìÐ)žÛ•8/÷Ûþ62(“Öý5ø3 �(Ëafïs!¡? ·a’0BÁ[·ÚéRùJhVKV†mÆŒKIU®@@K£²��^õ´ç¿ÕùɳÏ6¬^¹�‰ÒÂfWØå ¢ïY¥^ L–ãw›gq^x#‹5WCä¸Û¥ªˆ­Yò[6¢…T^6…×¼e,zŒßÖZ&íõ±â‰ùÿ[As0ÄeÍŒ8>4·Ä×Ë#ôŸôlY¯ûáEp›ø+‹’Yš÷Ksø†�¦Y¹.æËFf»Ï¦€6+MšPøé'�°œ H'�u£¾Ý¾¶“Ã]3å|ÐÅ\žWy ¢y"—¸XR«7äÿ‘ÚPÌã¾wù´"uL¢¨a<¾µRFLß‚ÐJžhí׳6øË:Õéb}Ë?‘­øtì,ŒâåN^ AêAÒ&}¤s0\‹•É@›¤c4;D˜Zµ`v7�üø5Ń®¤û€–˜†x¢�Ù:�3¿­«5Þžµ!ʦéë™/<‚3µÂñ&@ʼnCg+&Ò{FÝ`ºb� O?â®Ë ¹Î·GËH†cO—63:¬N¨Ÿ¼0x'W»÷›ìS«F•sèBeÚ`\1ƒˆÝUÔçÇŽ òù‹òã3…T„gÕCbš3Š?Ýßœ÷­_2³«Ó[„ø++™G‹³í™¨%2µüÃ]ºÀ&„Lj9ׯ#šŒ:=i%k#!ãß±CG &p·1À©™×fZZxÐÿÉ~[,Ù§ýÌü¶Ãê®ÿ4¤#Ÿýväd=YþÓ/ åK™yzïÎ1ྠ¿„=Á—± ¤²Å¬)ÿݬ _ëÔΠªˆmq$Þ£ÓU>–‡7(êäN[/“æs^Ñîzœzø+—WHG¸†¥Å„ë]nÃWc¥ï}cZq¡èóeˆè÷žGÔà1z”³>ðƒ{ºMˆ4Ô†*î)tÒ>ͨçš$¹�$1E‘mªb8ÒÒ~aRç €§PsuàŸ±ªç5Ãn$ò/~†à±(q8¬cã<[ÐNUÀÚ…®Kr?ob‚oóÂFÔˆ¢ ù[Ñ)£,·|­¡¦¤–~ø(?*Íñ)Î](‘AÛBN¶Ï¿f¼uL4�%)Òq•–È.F ØM1Þ×*/pÿ“׿ÄÄNé#Ù�¬‡óïX«Á1í%Ø›ÿJ÷䌴ñF>j°Ö&êÔ°‹þw¾q6“…Uß(}hÊ!ÿ~ ´q¹m ëõ[—Õ3Yt~]‹Rð$3¸ÿÔ ÇŸsú7pÿsà·—rg� ,¯ÅlωŸf”k †­yXm‡1ƒ~îeø(çÛ'9¦GófÐm {2Ë$¸I‘A[ÇÛ£Sm}ç‰yˆÓÆâöP2…ƒÈ!ûÇ€±,-rÇ««.z€–•Õ1š4YàÆ\#Ä`/‹—}XýÒ¼Zzk¬c]wS0ØÆÏ¦~§_äΊ%›M S"xÄLCÖ`­[fe5¸s!øl5 yõ<¨šöë¨KÛµ€ sõ6lL9JÑø6ªäÀNn�.Óü—>KTˆUƒµ" æ�˜+Ó©_X�Ue—4–`øŠ¡�v>‘Ùg³.G>Ó›Vn'¶�Äis&.Φ§8GÙaNÙHÌF™_§Ø>1¡êÈ _íû¡ŒÌxWÓï¨NdàÉ—?½ãØr %Ïù‘ëwÔ‡º"Ç-Œ‹œvÃd>2eº&pžØÁFö„H>ÍÊø&çˆ4kb%·ŒJÓéýnvÌOµœV_”`›ññË”LŽ”Y~L¸ìšj;±é×l³5å¶\¬ÌÌG%©éKÏ`nD²¾£ª“ðÌY_iõ;M†•»]½61¡·j=³BÜe³–s¼Ïã6a©RÈhñÒÉó#›FåôciÞ hP'jÊq6é¼­‚gz¹ø2ä´Æ@ÀcOxòò¼ùʃ 4�aÀ›T½ô§¿T�ßñHŸ½Àº ßâ˜ï‡)+ӳײçŸÍ½þuÇÍÕ24½'†a÷:展DÏãvÞV£ÂíØ’µý€ (ˆ©K˜š6—'âÕR¬û`•s®¹kË#©�¥¼¼°™�æ`äÃyw/¯+׈ªnCJXÊ.žñ7H>+�fÁè Óø+±®ò�æ�<¶oiÆW˜c¿v§ÇÇ´‰¦Ó¯ûÀ\¶ Õßóˆ.Ó¼�†«"ñŒ»«L”5ÇÐLXé‹ñ¢Ý÷‡û” d5'b*:�o»¹—ÕG÷S„éc·°·¬„ zÙynà5³™ŠuÑiæøö˜÷mÛÑc†%`­T°q½Æ™ëмb¦ŸGÜËꯎ¯â®dÏ}Þu‰Ãº%†cøG¼Q:k�q6<²šuî«H=»Ç†÷Z]G0®™¡m_%+eˆ×Iç/ßÅ3¤›Sòás�>sJòóÄ«69î­±$V„ÿˆÆçyŠoË—bæš³7ArüÏsx $.W¿®$,ðËU|CEÉsÖúzN�³Œ˜ºÔd»0“™:+9àÞÔ½ËÇÔò2[&Å‹Ssú‹‘Ä~]V¶³ˆø2ãÐÚÎTs“b ›Þåßs@œ0ë!²²ì}Ñ]ž¯aÖµr‚ùMˆÖ=íRI~yD­{^T7¾àF=0K °X {ruwTRwz=CjÙÇÜ*;çbÓшøÂTøÒеٹ«@é®Y0jß^à§ uAÍ»® çT WbˆP„_þŽg¹I¶•«œU¼›p²‚¨5Ýø(¾1Q<~àv­A’&͘ʹ^Åè–Ž&–¼N[÷/Gãàµÿó‹G>×ÇK”ûáó�JUð„‘g,Ì›0fqî™6+é²ÅƒhÐ’m¦�T9Qáôó³â‹‹(þ �çÃÊBã[‚CæÅamß¼A1æ\9¡Š±Çø5š�9�U©(‘‹[} µ¾&&槯�Äó®“·Uø57Ö_wó.T)9Tà�½3F$Âܳö@3|uŽóÒò¿Í$öçˆ[³ïŸþoéǤÐ_ä†ECa<=?0âîØ›Rðñf?­Ê oÄva:Fèì‚ÁŠõ@„Lÿ›qµ³RÕÐ:åö¾-ÿé8¡5]AšŠÊDq ØÖ0«òy"‹¾P—[€Æ*Õ(ÎÚÊŸJ¥ÎgÃø+-œÐ1ò]0¿ùa×lZnHçÆ‘?ŽUØ¢l´j‹çG5 KSÕ¿úÜŸ�ެPÉ;"\t [‹˜H{ì«TGCX(îoúoÅèA|¶bê¥fTÆBóuòD<æ·;@_“¶âEOø°h�‹Á• \WÆ’Ó‚74³U-§ð0iüúÀwÞõ–‰-€QƒÑöàüJOggS8x’”ôï$‚�þøxQ‡„‰" ¿&11AF0eSö"+‘}¨;£tÒ¡\Q ;Uþþ=ÂB˜9&Áp:ÜšJHÿ•ÀÝ«§ev˜Ø%…qõ¿Â¨ ‡ŒÂö.nÓßœ•œ4fJñúÐó½Â3B.¬±°ÝtúOœ�hFŸE,À’eÞ(8d!Ÿhø`0SHöÁœÞäsêLM§eܯK3{ç�!1â¤Ìlé•yMÍË< Ÿ[Š@ mÓrÛ©�ž-�^–¸ÜjWÇ áÒvùšCv9ñêk�wò¦Ö¥b:•Jº*jóRs"â&a‚<ÒöÐ�—.õbeetbox-beets-00724b7/test/rsrc/itunes_library_unix.xml0000664000175000017500000001541415253035401022630 0ustar pieterpieter Major Version1 Minor Version1 Date2015-05-08T14:36:28Z Application Version12.1.2.27 Features5 Show Content Ratings Music Folderfile:////Music/ Library Persistent ID1ABA8417E4946A32 Tracks 634 Track ID634 NameTessellate Artistalt-J Album Artistalt-J AlbumAn Awesome Wave GenreAlternative KindMPEG audio file Size5525212 Total Time182674 Disc Number1 Disc Count1 Track Number3 Track Count13 Year2012 Date Modified2015-02-02T15:23:08Z Date Added2014-04-24T09:28:38Z Bit Rate238 Sample Rate44100 Play Count0 Play Date3513593824 Skip Count3 Skip Date2015-02-05T15:41:04Z Rating80 Album Rating80 Album Rating Computed Artwork Count1 Sort AlbumAwesome Wave Sort Artistalt-J Persistent ID20E89D1580C31363 Track TypeFile Locationfile:///Music/Alt-J/An%20Awesome%20Wave/03%20Tessellate.mp3 File Folder Count4 Library Folder Count2 636 Track ID636 NameBreezeblocks Artistalt-J Album Artistalt-J AlbumAn Awesome Wave GenreAlternative KindMPEG audio file Size6827195 Total Time227082 Disc Number1 Disc Count1 Track Number4 Track Count13 Year2012 Date Modified2015-02-02T15:23:08Z Date Added2014-04-24T09:28:38Z Bit Rate237 Sample Rate44100 Play Count31 Play Date3513594051 Play Date UTC2015-05-04T12:20:51Z Skip Count0 Rating100 Album Rating80 Album Rating Computed Artwork Count1 Sort AlbumAwesome Wave Sort Artistalt-J Persistent IDD7017B127B983D38 Track TypeFile Locationfile://localhost/Music/Alt-J/An%20Awesome%20Wave/04%20Breezeblocks.mp3 File Folder Count4 Library Folder Count2 638 Track ID638 Nameâ�¦ (Ripe & Ruin) Artistalt-J Album Artistalt-J AlbumAn Awesome Wave KindMPEG audio file Size2173293 Total Time72097 Disc Number1 Disc Count1 Track Number2 Track Count13 Year2012 Date Modified2015-05-09T17:04:53Z Date Added2015-02-02T15:28:39Z Bit Rate233 Sample Rate44100 Play Count8 Play Date3514109973 Play Date UTC2015-05-10T11:39:33Z Skip Count1 Skip Date2015-02-02T15:29:10Z Album Rating80 Album Rating Computed Artwork Count1 Sort AlbumAwesome Wave Sort Artistalt-J Persistent ID183699FA0554D0E6 Track TypeFile Locationfile:///Music/Alt-J/An%20Awesome%20Wave/02%20%E2%9D%A6%20(Ripe%20&%20Ruin).mp3 File Folder Count4 Library Folder Count2 Playlists NameLibrary Master Playlist ID11480 Playlist Persistent IDCD6FF684E7A6A166 Visible All Items Playlist Items Track ID634 Track ID636 Track ID638 NameMusic Playlist ID16906 Playlist Persistent ID4FB2E64E0971DD45 Distinguished Kind4 Music All Items Playlist Items Track ID634 Track ID636 Track ID638 beetbox-beets-00724b7/test/rsrc/acousticbrainz/0000775000175000017500000000000015253035401021023 5ustar pieterpieterbeetbox-beets-00724b7/test/rsrc/acousticbrainz/data.json0000664000175000017500000037450215253035401022642 0ustar pieterpieter{ "tonal":{ "thpcp":[ 1, 0.638657510281, 0.293813556433, 0.259863913059, 0.21968896687, 0.218203336, 0.252398610115, 0.22969686985, 0.447383195162, 0.749422073364, 0.580664932728, 0.310822367668, 0.238883554935, 0.178785249591, 0.194924846292, 0.299323320389, 0.282649427652, 0.18946044147, 0.181915551424, 0.231100782752, 0.554247200489, 0.831909179688, 0.589426040649, 0.387799620628, 0.422363936901, 0.429372549057, 0.408978521824, 0.326897829771, 0.266663640738, 0.429461866617, 0.633336126804, 0.477401226759, 0.261826515198, 0.238164439797, 0.287726253271, 0.690547764301 ], "chords_number_rate":0.00194468453992, "chords_scale":"minor", "chords_changes_rate":0.0445116683841, "key_strength":0.636936545372, "tuning_diatonic_strength":0.495492935181, "hpcp_entropy":{ "min":0, "max":4.48086500168, "dvar2":0.867867648602, "median":2.02990412712, "dmean2":1.14721953869, "dmean":0.68769723177, "var":0.635742008686, "dvar":0.33780092001, "mean":2.00384068489 }, "key_scale":"minor", "chords_strength":{ "min":0.24240244925, "max":0.793840110302, "dvar2":9.58399032243e-05, "median":0.586153388023, "dmean2":0.0106231365353, "dmean":0.00929547380656, "var":0.00910324696451, "dvar":6.61800950184e-05, "mean":0.576524615288 }, "key_key":"A", "tuning_nontempered_energy_ratio":0.721719145775, "tuning_equal_tempered_deviation":0.0515233427286, "chords_histogram":[ 56.2445983887, 8.10285186768, 1.79343128204, 0.0864304229617, 0, 0.605012953281, 2.20397591591, 12.1650819778, 0.0216076057404, 0.0216076057404, 0, 0, 0, 0, 0, 0, 2.67934322357, 0.21607606113, 10.8686256409, 0, 2.07433009148, 0.0864304229617, 0.648228168488, 2.1823682785 ], "chords_key":"A", "tuning_frequency":441.272583008, "hpcp":{ "min":[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "max":[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], "dvar2":[ 0.159377709031, 0.118723139167, 0.0969077348709, 0.0841393470764, 0.0857475027442, 0.0681946650147, 0.0922033339739, 0.0763805955648, 0.08953332901, 0.134413808584, 0.117157392204, 0.0784328207374, 0.0576078519225, 0.0540019907057, 0.0537950210273, 0.0788798704743, 0.0758254900575, 0.0659088715911, 0.0595937520266, 0.0897909551859, 0.117696471512, 0.141075149179, 0.116812512279, 0.143778041005, 0.157332316041, 0.206293225288, 0.187901929021, 0.16186593473, 0.119209326804, 0.107413217425, 0.119033068419, 0.101279519498, 0.102868333459, 0.108767814934, 0.105039291084, 0.133028581738 ], "median":[ 0.200053632259, 0.138681918383, 0.0352100357413, 0.0198299698532, 0.0150980614126, 0.0205171480775, 0.026256872341, 0.0286095552146, 0.0424337461591, 0.0602139532566, 0.0744276791811, 0.0494470596313, 0.0350396670401, 0.0212194472551, 0.0196186862886, 0.0201223343611, 0.0170610919595, 0.0120322443545, 0.0105668697506, 0.0191436801106, 0.0846247002482, 0.135070502758, 0.113241240382, 0.0424886606634, 0.0378469713032, 0.02946896106, 0.0286043733358, 0.0198593121022, 0.0253958441317, 0.0672319456935, 0.0957452505827, 0.0639808028936, 0.026175301522, 0.0180807597935, 0.0324410535395, 0.125212281942 ], "dmean2":[ 0.353859990835, 0.294070899487, 0.217189013958, 0.180236533284, 0.162956178188, 0.144071772695, 0.172789543867, 0.171253859997, 0.22391949594, 0.284728109837, 0.274570196867, 0.198656648397, 0.154297873378, 0.124744221568, 0.124510832131, 0.157537952065, 0.158150732517, 0.135058999062, 0.123808719218, 0.177607372403, 0.277576059103, 0.324962347746, 0.298212528229, 0.308668285608, 0.311420857906, 0.344731658697, 0.335885316133, 0.283822774887, 0.227637752891, 0.252195805311, 0.288448363543, 0.249307155609, 0.212308287621, 0.205825775862, 0.223324626684, 0.315198987722 ], "dmean":[ 0.206140458584, 0.16949801147, 0.121237404644, 0.101308584213, 0.0920756608248, 0.0820758640766, 0.0983714461327, 0.0957674309611, 0.130757495761, 0.167563140392, 0.159212738276, 0.113431841135, 0.0875298455358, 0.0698468312621, 0.0709747001529, 0.092557400465, 0.0927894487977, 0.0761438235641, 0.0697580873966, 0.0992580577731, 0.162719354033, 0.194310605526, 0.174188151956, 0.171439617872, 0.174783751369, 0.191449582577, 0.185274213552, 0.155063658953, 0.124152831733, 0.143824338913, 0.167870178819, 0.144021183252, 0.116702638566, 0.112653404474, 0.125104308128, 0.184472203255 ], "var":[ 0.143021538854, 0.0637424811721, 0.0320195667446, 0.037381041795, 0.0286979582161, 0.0301742851734, 0.0303927082568, 0.0223984327167, 0.052778493613, 0.13409627974, 0.0731517747045, 0.0302681028843, 0.0220995694399, 0.0194978509098, 0.0208596177399, 0.0510722063482, 0.0462048053741, 0.0236530210823, 0.0288583170623, 0.0295663233846, 0.0644663274288, 0.119045428932, 0.0609758161008, 0.0493184439838, 0.0607626289129, 0.070556551218, 0.0664848089218, 0.0493576526642, 0.0335861295462, 0.0447917319834, 0.0859667509794, 0.0526875928044, 0.0304508917034, 0.0315008088946, 0.0328483134508, 0.0794815197587 ], "dvar":[ 0.0686646401882, 0.0436623394489, 0.0358338914812, 0.0332863405347, 0.0316647030413, 0.027725789696, 0.0338032282889, 0.0273791830987, 0.0345646068454, 0.0615020208061, 0.0457257218659, 0.0297911148518, 0.0221415478736, 0.0201385207474, 0.0201426595449, 0.033235758543, 0.0318886972964, 0.0243560094386, 0.0229729004204, 0.0327679589391, 0.0460740588605, 0.0626438856125, 0.0435314439237, 0.0521778166294, 0.0578555390239, 0.0772548541427, 0.0728902295232, 0.05926451087, 0.0424739196897, 0.0389089211822, 0.0483759790659, 0.0381603203714, 0.036982499063, 0.0398408733308, 0.0387278683484, 0.0517609193921 ], "mean":[ 0.366864055395, 0.234300479293, 0.107789635658, 0.0953347310424, 0.080595985055, 0.0800509601831, 0.0925959795713, 0.084267526865, 0.164128810167, 0.274936020374, 0.213025093079, 0.114029549062, 0.0876377895474, 0.0655898824334, 0.0715109184384, 0.109810970724, 0.103693917394, 0.0695062279701, 0.0667382776737, 0.0847825706005, 0.203333377838, 0.305197566748, 0.216239228845, 0.142269745469, 0.154950141907, 0.157521352172, 0.15003952384, 0.119927063584, 0.0978293046355, 0.157554119825, 0.232348263264, 0.175141349435, 0.0960547402501, 0.0873739719391, 0.105556420982, 0.253337144852 ] } }, "rhythm":{ "bpm_histogram_second_peak_bpm":{ "min":167, "max":167, "dvar2":0, "median":167, "dmean2":0, "dmean":0, "var":0, "dvar":0, "mean":167 }, "bpm_histogram_second_peak_spread":{ "min":0, "max":0, "dvar2":0, "median":0, "dmean2":0, "dmean":0, "var":0, "dvar":0, "mean":0 }, "beats_count":577, "beats_loudness":{ "min":4.48232695405e-09, "max":0.181520029902, "dvar2":0.00434844521806, "median":0.0302296206355, "dmean2":0.0709233134985, "dmean":0.0362482257187, "var":0.0014705004869, "dvar":0.00124853104353, "mean":0.0407853461802 }, "bpm":162.532119751, "bpm_histogram_first_peak_spread":{ "min":0.164835140109, "max":0.164835140109, "dvar2":0, "median":0.164835140109, "dmean2":0, "dmean":0, "var":0, "dvar":0, "mean":0.164835140109 }, "danceability":1.14192211628, "bpm_histogram_first_peak_bpm":{ "min":161, "max":161, "dvar2":0, "median":161, "dmean2":0, "dmean":0, "var":0, "dvar":0, "mean":161 }, "beats_loudness_band_ratio":{ "min":[ 0.00683269277215, 0.00988945644349, 0.00177479430567, 0.000523661612533, 0.000248342636041, 0.00070228939876 ], "max":[ 0.970164954662, 0.725397408009, 0.739950060844, 0.658194899559, 0.676319360733, 0.622089266777 ], "dvar2":[ 0.0699004009366, 0.0290632098913, 0.035205449909, 0.0226975940168, 0.0168868545443, 0.0086750369519 ], "median":[ 0.619332075119, 0.176913484931, 0.0926762372255, 0.0303400773555, 0.0398489944637, 0.0262520890683 ], "dmean2":[ 0.369491040707, 0.230186283588, 0.192849993706, 0.106605380774, 0.107576675713, 0.0616580061615 ], "dmean":[ 0.207789510489, 0.129003107548, 0.110624760389, 0.0578341074288, 0.0602345280349, 0.035002540797 ], "var":[ 0.0565228238702, 0.0165011454374, 0.0193302389234, 0.0086074648425, 0.00634109321982, 0.00296737346798 ], "dvar":[ 0.0250691790134, 0.00962078291923, 0.0126609709114, 0.00782771967351, 0.00567667419091, 0.00305109703913 ], "mean":[ 0.577607989311, 0.195795580745, 0.138790622354, 0.0610357522964, 0.065284781158, 0.04240244627 ] }, "onset_rate":5.17941665649, "beats_position":[ 0.383129239082, 0.789478421211, 1.16099774837, 1.53251695633, 1.90403628349, 2.27555561066, 2.6470746994, 3.01859402657, 3.39011335373, 3.76163268089, 4.13315200806, 4.5046710968, 4.87619018555, 5.24770975113, 5.60761880875, 5.9675283432, 6.33904743195, 6.71056699753, 7.08208608627, 7.45360517502, 7.81351470947, 8.17342376709, 8.54494285583, 8.91646194458, 9.287981987, 9.64789104462, 10.0194101334, 10.379319191, 10.7508392334, 11.110748291, 11.4822673798, 11.8421764374, 12.2136955261, 12.5852155685, 12.9567346573, 13.3166437149, 13.6765527725, 14.0364627838, 14.3963718414, 14.7678909302, 15.1394100189, 15.5109291077, 15.870839119, 16.2307472229, 16.602268219, 16.9621772766, 17.3220863342, 17.693605423, 18.0535144806, 18.4134235382, 18.7733325958, 19.1332416534, 19.4931507111, 19.853061676, 20.2245807648, 20.5844898224, 20.9560089111, 21.3159179688, 21.6874370575, 22.0473461151, 22.4072551727, 22.7787742615, 23.1386852264, 23.4985942841, 23.8701133728, 24.2416324615, 24.6131515503, 24.984670639, 25.3561897278, 25.7277088165, 26.0992279053, 26.4591369629, 26.830657959, 27.2021770477, 27.5736961365, 27.9452152252, 28.316734314, 28.6766433716, 29.0481624603, 29.4196815491, 29.7912006378, 30.1627197266, 30.5342407227, 30.9057598114, 31.265668869, 31.6255779266, 31.9854869843, 32.3453979492, 32.6704750061, 33.0071640015, 33.3554649353, 33.7153739929, 34.0868911743, 34.4351921082, 34.8067131042, 35.1898422241, 35.5961914062, 35.9793205261, 36.362449646, 36.7339668274, 37.1054878235, 37.4886169434, 37.8601341248, 38.2316551208, 38.6147842407, 38.9863014221, 39.3578224182, 39.7293434143, 40.1124725342, 40.4723815918, 40.8438987732, 41.2154197693, 41.5869369507, 41.9584579468, 42.3299751282, 42.7014961243, 43.0730133057, 43.4445343018, 43.8160552979, 44.1875724792, 44.5590934753, 44.9306106567, 45.3021316528, 45.6736488342, 46.0335578918, 46.3934669495, 46.7533760071, 47.1132888794, 47.4848060608, 47.8563270569, 48.2394561768, 48.6225852966, 48.994102478, 49.3656234741, 49.748752594, 50.1318817139, 50.5033988953, 50.8749198914, 51.2580490112, 51.6411781311, 52.0126991272, 52.3842163086, 52.7557373047, 53.1272544861, 53.4987754822, 53.8702926636, 54.2534217834, 54.6365509033, 55.0080718994, 55.3795890808, 55.7511100769, 56.122631073, 56.4941482544, 56.8656692505, 57.2487983704, 57.6203155518, 58.0034446716, 58.3749656677, 58.7464828491, 59.1180038452, 59.4895210266, 59.8610420227, 60.2325630188, 60.6040802002, 60.9756011963, 61.3471183777, 61.7186393738, 62.0901565552, 62.4616775513, 62.8331947327, 63.2163238525, 63.5994529724, 63.9709739685, 64.3424911499, 64.714012146, 65.0855331421, 65.4570541382, 65.8285675049, 66.200088501, 66.5716094971, 66.9431304932, 67.3146438599, 67.686164856, 68.0344696045, 68.4175949097, 68.8007278442, 69.1722412109, 69.5321502686, 69.8920593262, 70.2635803223, 70.6351013184, 70.995010376, 71.3549194336, 71.7264404297, 72.1095657349, 72.481086731, 72.8642196655, 73.2357330322, 73.6072540283, 73.9787750244, 74.3502960205, 74.7218093872, 75.1049423218, 75.488067627, 75.859588623, 76.2311096191, 76.6026306152, 76.9741516113, 77.345664978, 77.7171859741, 78.1003189087, 78.4834442139, 78.85496521, 79.2264862061, 79.5979995728, 79.9695205688, 80.3410415649, 80.712562561, 81.0840835571, 81.4555969238, 81.8271179199, 82.198638916, 82.5701599121, 82.9416732788, 83.3131942749, 83.684715271, 84.0678405762, 84.4509735107, 84.8224945068, 85.1824035645, 85.5423126221, 85.9138336182, 86.2853469849, 86.656867981, 87.0283889771, 87.3999099731, 87.7714233398, 88.1429443359, 88.514465332, 88.8859863281, 89.2575073242, 89.6290206909, 89.9889297485, 90.3488388062, 90.7203598022, 91.0918807983, 91.451789856, 91.8116989136, 92.1832199097, 92.5547409058, 92.9262542725, 93.2861633301, 93.6460723877, 94.0175933838, 94.3891143799, 94.760635376, 95.1205444336, 95.4804534912, 95.8403625488, 96.2002716064, 96.5717926025, 96.9433059692, 97.3148269653, 97.6863479614, 98.0578689575, 98.4293823242, 98.8009033203, 99.1724243164, 99.532333374, 99.9038543701, 100.263763428, 100.635284424, 101.006797791, 101.378318787, 101.738227844, 102.098136902, 102.469657898, 102.841178894, 103.21269989, 103.584213257, 103.944122314, 104.304031372, 104.675552368, 105.047073364, 105.406982422, 105.766891479, 106.138412476, 106.509933472, 106.881446838, 107.252967834, 107.624488831, 107.984397888, 108.355918884, 108.715827942, 109.087341309, 109.458862305, 109.818771362, 110.17868042, 110.538589478, 110.898498535, 111.270019531, 111.641540527, 112.001449585, 112.361358643, 112.732879639, 113.104400635, 113.464309692, 113.82421875, 114.184127808, 114.544036865, 114.915550232, 115.287071228, 115.658592224, 116.006889343, 116.366798401, 116.726707458, 117.086616516, 117.446525574, 117.794830322, 118.15473938, 118.514648438, 118.886169434, 119.269294739, 119.652427673, 120.035552979, 120.418685913, 120.813423157, 121.2081604, 121.602897644, 121.997642517, 122.380767822, 122.763900757, 123.147026062, 123.530158997, 123.92489624, 124.319633484, 124.69115448, 125.085891724, 125.480628967, 125.863761902, 126.246894836, 126.630020142, 127.013153076, 127.396278381, 127.779411316, 128.17414856, 128.568893433, 128.963623047, 129.346755981, 129.729888916, 130.113006592, 130.496139526, 130.867660522, 131.239181519, 131.610702515, 131.982223511, 132.353744507, 132.725265503, 133.09677124, 133.456680298, 133.816589355, 134.188110352, 134.559631348, 134.931152344, 135.30267334, 135.674194336, 136.045715332, 136.417236328, 136.788757324, 137.160263062, 137.520172119, 137.880081177, 138.251602173, 138.623123169, 138.994644165, 139.366165161, 139.737686157, 140.109207153, 140.480728149, 140.852249146, 141.223754883, 141.595275879, 141.943572998, 142.315093994, 142.675003052, 143.034912109, 143.406433105, 143.777954102, 144.149475098, 144.520996094, 144.89251709, 145.264038086, 145.635559082, 146.007064819, 146.378585815, 146.750106812, 147.121627808, 147.493148804, 147.8646698, 148.236190796, 148.607711792, 148.979232788, 149.362350464, 149.745483398, 150.117004395, 150.488525391, 150.860046387, 151.231567383, 151.603088379, 151.974594116, 152.346115112, 152.717636108, 153.089157104, 153.460678101, 153.832199097, 154.203720093, 154.575241089, 154.946762085, 155.318267822, 155.689788818, 156.061309814, 156.432830811, 156.804351807, 157.175872803, 157.547393799, 157.918914795, 158.290420532, 158.661941528, 159.033462524, 159.404983521, 159.776504517, 160.148025513, 160.519546509, 160.891067505, 161.262588501, 161.634094238, 162.005615234, 162.37713623, 162.737045288, 163.096954346, 163.468475342, 163.839996338, 164.211517334, 164.58303833, 164.954559326, 165.326080322, 165.674377441, 166.045898438, 166.417419434, 166.788925171, 167.160446167, 167.531967163, 167.903488159, 168.275009155, 168.646530151, 169.018051147, 169.389572144, 169.772689819, 170.155822754, 170.52734375, 170.898864746, 171.270385742, 171.641906738, 172.025024414, 172.408157349, 172.779678345, 173.151199341, 173.522720337, 173.894241333, 174.265762329, 174.637283325, 175.032012939, 175.415145874, 175.798278809, 176.169799805, 176.541305542, 176.9012146, 177.272735596, 177.632644653, 178.004165649, 178.375686646, 178.747207642, 179.130340576, 179.513473511, 179.884979248, 180.256500244, 180.62802124, 180.999542236, 181.382675171, 181.754196167, 182.137313843, 182.508834839, 182.880355835, 183.251876831, 183.623397827, 183.994918823, 184.378051758, 184.761169434, 185.13269043, 185.504211426, 185.875732422, 186.247253418, 186.618774414, 186.99029541, 187.361816406, 187.733337402, 188.10484314, 188.476364136, 188.847885132, 189.219406128, 189.590927124, 189.96244812, 190.345581055, 190.72869873, 191.100219727, 191.471740723, 191.843261719, 192.214782715, 192.597915649, 192.981033325, 193.352554321, 193.724075317, 194.095596313, 194.478729248, 194.861862183, 195.23336792, 195.604888916, 195.976409912, 196.347930908, 196.719451904, 197.0909729, 197.474105835, 197.857223511, 198.228744507, 198.600265503, 198.971786499, 199.343307495, 199.714828491, 200.086349487, 200.457870483, 200.829391479, 201.200897217, 201.572418213, 201.943939209, 202.303848267, 202.663757324, 203.03527832, 203.406799316, 203.778320312, 204.149841309, 204.521362305, 204.892883301, 205.264389038, 205.647521973, 206.030654907, 206.402175903, 206.773696899, 207.145217896, 207.516723633, 207.888244629, 208.259765625, 208.631286621, 209.002807617, 209.385940552, 209.757461548, 210.128982544, 210.500488281, 210.883621216, 211.255142212, 211.626663208, 212.009796143, 212.392913818, 212.776046753, 213.170791626, 213.565536499, 213.971878052, 214.378234863 ], "bpm_histogram_second_peak_weight":{ "min":0.163194447756, "max":0.163194447756, "dvar2":0, "median":0.163194447756, "dmean2":0, "dmean":0, "var":0, "dvar":0, "mean":0.163194447756 }, "bpm_histogram_first_peak_weight":{ "min":0.659722208977, "max":0.659722208977, "dvar2":0, "median":0.659722208977, "dmean2":0, "dmean":0, "var":0, "dvar":0, "mean":0.659722208977 } }, "lowlevel":{ "spectral_complexity":{ "min":0, "max":51, "dvar2":34.109500885, "median":15, "dmean2":5.03252983093, "dmean":3.31208133698, "var":108.135475159, "dvar":16.1623840332, "mean":15.1260938644 }, "silence_rate_20dB":{ "min":1, "max":1, "dvar2":0, "median":1, "dmean2":0, "dmean":0, "var":0, "dvar":0, "mean":1 }, "average_loudness":0.815025985241, "erbbands_spread":{ "min":0.907018482685, "max":163.113571167, "dvar2":511.106719971, "median":34.9861183167, "dmean2":17.4016342163, "dmean":11.4227361679, "var":572.351501465, "dvar":220.769592285, "mean":39.7502365112 }, "spectral_kurtosis":{ "min":-1.22816824913, "max":77.2247085571, "dvar2":28.6044521332, "median":4.62249898911, "dmean2":4.51546525955, "dmean":2.82785224915, "var":33.1767959595, "dvar":13.1654214859, "mean":6.00768327713 }, "barkbands_kurtosis":{ "min":-1.96124887466, "max":732.31427002, "dvar2":588.577392578, "median":2.02856016159, "dmean2":8.05669307709, "dmean":5.11299228668, "var":374.321380615, "dvar":247.842544556, "mean":7.06718301773 }, "spectral_strongpeak":{ "min":1.71490974199e-10, "max":16.1200447083, "dvar2":3.3518705368, "median":0.39955753088, "dmean2":0.941311240196, "dmean":0.545010268688, "var":2.96148967743, "dvar":1.33243703842, "mean":0.93408870697 }, "spectral_spread":{ "min":1388334.875, "max":41575076, "dvar2":1619247235070.0, "median":3420763.25, "dmean2":983456.875, "dmean":732694.4375, "var":4945877663740.0, "dvar":854983901184, "mean":4104934.25 }, "spectral_rms":{ "min":3.15950651059e-12, "max":0.0132316453382, "dvar2":3.71212809114e-06, "median":0.00425734650344, "dmean2":0.0013317943085, "dmean":0.000880118692294, "var":5.96411746301e-06, "dvar":1.66359927789e-06, "mean":0.0039903158322 }, "erbbands":{ "min":[ 1.77816177391e-22, 1.16505097519e-21, 1.25622764484e-20, 2.42817334007e-20, 1.54258117469e-20, 1.0398112018e-19, 1.45132858053e-19, 2.45289269564e-19, 4.01068342766e-19, 8.21050273636e-19, 3.81530310848e-19, 8.81511903137e-19, 1.07499647945e-18, 8.4783438187e-19, 1.00474413342e-18, 2.63416224414e-18, 2.7020495774e-18, 3.62243276547e-18, 3.19863277569e-18, 3.43176763428e-18, 6.46998299903e-18, 5.15079866686e-18, 8.52004633608e-18, 1.02257547977e-17, 1.00997123247e-17, 1.05472856921e-17, 1.00685656659e-17, 1.10003920706e-17, 1.51110777052e-17, 1.5046216819e-17, 1.31580720189e-17, 1.30844504628e-17, 1.13508668418e-17, 1.02681982621e-17, 8.04728449187e-18, 4.73097927698e-18, 2.75997186582e-18, 1.08864568334e-18, 2.8601904839e-19, 3.5584382605e-20 ], "max":[ 2.05614852905, 10.580906868, 60.5060195923, 152.843505859, 450.042755127, 175.338409424, 237.807418823, 238.884460449, 443.897521973, 525.930541992, 518.611022949, 1031.67468262, 954.232910156, 1123.45935059, 556.857299805, 356.125640869, 342.635467529, 1293.60327148, 1103.80981445, 1287.36242676, 2169.76928711, 1266.18579102, 601.754516602, 1258.96850586, 444.097320557, 240.62600708, 303.504180908, 56.5521354675, 72.2374343872, 85.4121780396, 25.407957077, 19.8146400452, 46.2547264099, 16.3226490021, 16.8903636932, 5.15064907074, 0.893250703812, 0.284754753113, 0.106889992952, 0.00452945847064 ], "dvar2":[ 0.0137821119279, 4.26913785934, 97.7259292603, 622.611999512, 3656.42504883, 376.053527832, 307.56942749, 320.293243408, 2445.90405273, 1300.15063477, 729.621582031, 2693.6159668, 2013.25512695, 3353.13598633, 573.952941895, 269.22253418, 457.528259277, 1406.78710938, 1557.82128906, 793.165527344, 5019.24316406, 4039.60839844, 970.312316895, 1538.21313477, 721.875244141, 195.41003418, 88.4793777466, 31.4306335449, 42.7237434387, 32.8801956177, 6.04226541519, 1.52690029144, 1.47338938713, 0.542356073856, 0.211627364159, 0.0269440039992, 0.00465576630086, 0.000269315525657, 1.98406451091e-05, 4.38383267465e-08 ], "median":[ 0.00466703856364, 0.101253904402, 1.64267027378, 5.13034963608, 6.49109458923, 4.258228302, 3.18711066246, 4.03815889359, 7.81102657318, 7.54452610016, 5.75877952576, 8.21393203735, 11.6316785812, 9.69087696075, 4.23464298248, 1.69191777706, 2.67072510719, 4.43968248367, 4.24516201019, 7.75287914276, 16.0199928284, 12.5332527161, 9.28721427917, 9.18504428864, 6.87661838531, 4.15781497955, 3.11850094795, 0.707400023937, 0.422007799149, 0.326348185539, 0.171605303884, 0.0764799118042, 0.0530340671539, 0.0369812250137, 0.0170799326152, 0.00388540537097, 0.000607917027082, 0.000106923354906, 2.54503829638e-05, 2.41674279096e-05 ], "dmean2":[ 0.0468679144979, 1.00080478191, 4.60071754456, 11.530172348, 27.0302009583, 10.1726131439, 8.18716049194, 9.02602672577, 21.6493034363, 17.5054721832, 11.9851293564, 23.2072429657, 23.1678962708, 24.8249855042, 9.62737751007, 5.9968290329, 8.08820819855, 12.5483970642, 11.0777654648, 12.6770420074, 31.1724281311, 22.2209968567, 15.6441850662, 17.6994724274, 11.4936075211, 6.59135293961, 5.08022689819, 2.30506944656, 2.95904040337, 2.46585559845, 1.15297198296, 0.531184136868, 0.382049500942, 0.275081396103, 0.141834661365, 0.0498343594372, 0.0225136969239, 0.00503297196701, 0.000977287418209, 5.82068387303e-05 ], "dmean":[ 0.0350424982607, 0.580041825771, 2.61035442352, 6.80757236481, 16.318693161, 6.28967905045, 5.23286628723, 5.70099258423, 13.4230766296, 10.8768568039, 7.74926900864, 15.0034389496, 15.0271100998, 16.6018199921, 6.02632713318, 3.79855132103, 5.38237333298, 8.43670463562, 7.43314123154, 8.2191324234, 20.6921386719, 13.7538080215, 9.77100944519, 11.3139772415, 7.25735664368, 4.1218457222, 3.17433810234, 1.45581579208, 1.87883663177, 1.61556243896, 0.779599308968, 0.371349811554, 0.264476120472, 0.193502560258, 0.100708886981, 0.0353026203811, 0.0144239943475, 0.00325388251804, 0.000670222449116, 3.95594870497e-05 ], "var":[ 0.0116662262008, 1.27503490448, 25.6204109192, 206.069885254, 1430.30371094, 234.442382812, 206.473526001, 288.805267334, 1444.05480957, 817.272949219, 625.690795898, 2697.92749023, 2397.11669922, 7130.13330078, 515.86315918, 346.633789062, 809.448486328, 2584.76660156, 2616.26757812, 3138.03320312, 20583.1132812, 3381.78515625, 1288.27880859, 2477.11401367, 682.099060059, 216.604751587, 97.8326339722, 13.7823019028, 19.9818115234, 16.6690158844, 4.43811273575, 1.2346996069, 1.27807950974, 0.517578363419, 0.177246898413, 0.0190207827836, 0.00211605615914, 0.000168058744748, 1.65621640917e-05, 3.32350325039e-08 ], "dvar":[ 0.00734147289768, 1.59334981441, 34.9658050537, 236.386993408, 1519.1640625, 157.498901367, 126.366111755, 127.708183289, 921.020629883, 497.140319824, 303.813903809, 1122.60107422, 868.916992188, 1545.74194336, 241.721923828, 118.562904358, 218.458129883, 734.227844238, 762.639587402, 405.900024414, 2714.4777832, 1520.69287109, 428.032836914, 696.146972656, 272.255096436, 80.3479690552, 38.2512245178, 12.4188299179, 17.8483753204, 13.7868928909, 2.77658462524, 0.731714189053, 0.67433899641, 0.263227701187, 0.108624838293, 0.0132785160094, 0.00197272375226, 0.000125091624795, 1.03948887045e-05, 2.18264126772e-08 ], "mean":[ 0.0470404699445, 0.51214581728, 2.94917726517, 8.56711673737, 16.8939933777, 9.74743175507, 8.58794498444, 10.7102499008, 23.4056625366, 18.6381034851, 13.9866991043, 27.1086997986, 28.1797733307, 34.376159668, 10.7114057541, 6.6013917923, 10.7804918289, 16.5257949829, 15.1251926422, 19.3569641113, 49.2880210876, 27.8654499054, 20.180316925, 22.9017887115, 15.1088733673, 8.45034122467, 5.79618597031, 1.91187810898, 2.04077577591, 1.82269322872, 0.964613378048, 0.475511223078, 0.359998822212, 0.270887732506, 0.138232842088, 0.0431671403348, 0.0138024548069, 0.00314460648224, 0.000714557303581, 5.64505244256e-05 ] }, "zerocrossingrate":{ "min":0.00244140625, "max":0.525390625, "dvar2":0.000216632659431, "median":0.04736328125, "dmean2":0.0121012274176, "dmean":0.0100563038141, "var":0.00131242838688, "dvar":0.000186675912119, "mean":0.0536084286869 }, "spectral_contrast_coeffs":{ "min":[ -0.981265366077, -0.957678437233, -0.97364538908, -0.967074155807, -0.96257597208, -0.963937044144 ], "max":[ -0.232828617096, -0.450794398785, -0.464783608913, -0.367899239063, -0.556100070477, -0.624147236347 ], "dvar2":[ 0.0063711241819, 0.00358002260327, 0.00270585925318, 0.0017158848932, 0.00113679806236, 0.00189194327686 ], "median":[ -0.592801511288, -0.736532092094, -0.745844006538, -0.781389117241, -0.797656714916, -0.772757589817 ], "dmean2":[ 0.0916584655643, 0.074229337275, 0.0648957416415, 0.0500396862626, 0.0380141288042, 0.0374387130141 ], "dmean":[ 0.0592447705567, 0.0465519614518, 0.0414465926588, 0.0322540737689, 0.024834824726, 0.0243127625436 ], "var":[ 0.00911337323487, 0.00655136583373, 0.00618056347594, 0.00577284349129, 0.00380114861764, 0.00231571029872 ], "dvar":[ 0.00270068016835, 0.00148758781143, 0.00118501938414, 0.000784370582551, 0.000524090020917, 0.000761664705351 ], "mean":[ -0.594863533974, -0.735448241234, -0.745020091534, -0.775078713894, -0.790849328041, -0.779701292515 ] }, "dissonance":{ "min":0.155567497015, "max":0.500000119209, "dvar2":0.0011708199745, "median":0.469446510077, "dmean2":0.0329371914268, "dmean":0.0200165640563, "var":0.00120261416305, "dvar":0.000480501999846, "mean":0.460001558065 }, "spectral_energyband_high":{ "min":7.11060368084e-21, "max":0.00607443926856, "dvar2":2.99654345781e-07, "median":0.000152749445988, "dmean2":0.000292699754937, "dmean":0.000196773456992, "var":2.3810963512e-07, "dvar":1.35860290129e-07, "mean":0.000318794423947 }, "gfcc":{ "mean":[ -75.1009368896, 108.134063721, -114.922393799, 35.9068107605, -53.9456176758, -7.74362421036, -37.9716300964, 9.9239988327, -24.244802475, -10.4905223846, -23.3989257812, -9.61326217651, -9.66184806824 ], "icov":[ [ 8.00217167125e-05, -0.00014524954895, 0.000159682429512, -0.000167002261151, 9.01917956071e-05, -0.000181695446372, 0.000171542298631, -0.000129780688439, 0.000197500339709, -0.000278050283669, 0.000315256824251, -0.000206819575396, 0.000114160277008 ], [ -0.00014524954895, 0.00178359099664, -0.000247094896622, 0.00111800106242, -0.000636783661321, 0.000774645654019, -0.000396145915147, 0.000103466474684, -0.00112135277595, 0.00229536322877, -0.00234188255854, 0.00232740258798, -0.00131408020388 ], [ 0.000159682429512, -0.000247094896622, 0.00116660131607, -0.000234406528762, 0.000154832057888, -0.00112980930135, 0.000650760543067, -5.60496459912e-07, 0.000167754784343, -0.000856044876855, 0.0014209097717, -0.00128671491984, 0.00078388658585 ], [ -0.000167002261151, 0.00111800106242, -0.000234406528762, 0.00312983314507, -0.000794405816123, -0.00058439996792, 2.24104460358e-05, 0.000424961413955, -0.00152624503244, 0.00239069177769, -0.00202889670618, 0.00110484787729, -0.00148455286399 ], [ 9.01917956071e-05, -0.000636783661321, 0.000154832057888, -0.000794405816123, 0.00397709663957, -0.000828172138426, -0.000291677570203, -0.000975954462774, 0.00101370830089, -0.00107421039138, -0.000894718454219, 0.00066822959343, -0.000943991879467 ], [ -0.000181695446372, 0.000774645654019, -0.00112980930135, -0.00058439996792, -0.000828172138426, 0.00597975216806, -0.00177403702401, -0.000384801533073, 0.00153620564379, -0.00195281521883, 0.00158954621293, 0.000321330269799, 0.000257747073192 ], [ 0.000171542298631, -0.000396145915147, 0.000650760543067, 2.24104460358e-05, -0.000291677570203, -0.00177403702401, 0.0080866701901, -0.00180288043339, 7.330061635e-05, 0.00111615261994, -0.0011511715129, -0.000984402606264, 0.000181279159733 ], [ -0.000129780688439, 0.000103466474684, -5.60496459912e-07, 0.000424961413955, -0.000975954462774, -0.000384801533073, -0.00180288043339, 0.00851836241782, -0.00320849893615, 0.00141180318315, -0.00124999764375, 0.000833041733131, -0.00159861764405 ], [ 0.000197500339709, -0.00112135277595, 0.000167754784343, -0.00152624503244, 0.00101370830089, 0.00153620564379, 7.330061635e-05, -0.00320849893615, 0.0134673845023, -0.00816399604082, 0.00590222747996, -0.00234723254107, -0.000930359237827 ], [ -0.000278050283669, 0.00229536322877, -0.000856044876855, 0.00239069177769, -0.00107421039138, -0.00195281521883, 0.00111615261994, 0.00141180318315, -0.00816399604082, 0.0195522867143, -0.0122134555131, 0.00327054248191, 0.000577625120059 ], [ 0.000315256824251, -0.00234188255854, 0.0014209097717, -0.00202889670618, -0.000894718454219, 0.00158954621293, -0.0011511715129, -0.00124999764375, 0.00590222747996, -0.0122134555131, 0.021111080423, -0.00721056666225, 0.00365835893899 ], [ -0.000206819575396, 0.00232740258798, -0.00128671491984, 0.00110484787729, 0.00066822959343, 0.000321330269799, -0.000984402606264, 0.000833041733131, -0.00234723254107, 0.00327054248191, -0.00721056666225, 0.015932681039, -0.00565396249294 ], [ 0.000114160277008, -0.00131408020388, 0.00078388658585, -0.00148455286399, -0.000943991879467, 0.000257747073192, 0.000181279159733, -0.00159861764405, -0.000930359237827, 0.000577625120059, 0.00365835893899, -0.00565396249294, 0.0153731228784 ] ], "cov":[ [ 21821.4921875, 1302.12060547, -2790.62133789, 583.293151855, 63.9840736389, 26.9333572388, -119.419998169, 277.984161377, -110.454193115, -76.0569458008, -16.7917041779, -162.89515686, 121.933448792 ], [ 1302.12060547, 1445.02355957, -661.351135254, -311.094665527, 156.139587402, -306.730987549, 60.9609375, 92.3673324585, 3.47471880913, -108.692207336, 66.6088409424, -147.776809692, 75.2410125732 ], [ -2790.62133789, -661.351135254, 1889.47399902, 92.8338088989, -92.8102874756, 368.803192139, -78.5678482056, -95.1785125732, 24.1375102997, 86.254699707, -94.2749252319, 117.902046204, -80.0259933472 ], [ 583.293151855, -311.094665527, 92.8338088989, 515.187255859, 60.5850448608, 128.642654419, -2.62003684044, 6.46807575226, 13.7108755112, -3.07335114479, -7.74705600739, 28.8581352234, 29.7626171112 ], [ 63.9840736389, 156.139587402, -92.8102874756, 60.5850448608, 339.564758301, 28.9691524506, 45.5025405884, 54.3213920593, -9.63641166687, 12.0036411285, 43.2324829102, -22.4280166626, 29.361246109 ], [ 26.9333572388, -306.730987549, 368.803192139, 128.642654419, 28.9691524506, 324.149993896, 20.1203899384, -3.79410982132, -15.0688257217, 43.0340042114, -26.3511829376, 28.6324996948, -22.8170604706 ], [ -119.419998169, 60.9609375, -78.5678482056, -2.62003684044, 45.5025405884, 20.1203899384, 155.001724243, 42.1054992676, -1.47882866859, -8.76181983948, 19.2513332367, 2.83816099167, 11.5606393814 ], [ 277.984161377, 92.3673324585, -95.1785125732, 6.46807575226, 54.3213920593, -3.79410982132, 42.1054992676, 155.586120605, 33.8702697754, -2.8296790123, 9.17068958282, -6.04741716385, 28.1404056549 ], [ -110.454193115, 3.47471880913, 24.1375102997, 13.7108755112, -9.63641166687, -15.0688257217, -1.47882866859, 33.8702697754, 114.661575317, 34.3392486572, -7.06085252762, 10.0253458023, 15.4272651672 ], [ -76.0569458008, -108.692207336, 86.254699707, -3.07335114479, 12.0036411285, 43.0340042114, -8.76181983948, -2.8296790123, 34.3392486572, 112.38079071, 43.6220817566, 14.6831378937, -20.7214431763 ], [ -16.7917041779, 66.6088409424, -94.2749252319, -7.74705600739, 43.2324829102, -26.3511829376, 19.2513332367, 9.17068958282, -7.06085252762, 43.6220817566, 99.527053833, 15.1529960632, -6.4773888588 ], [ -162.89515686, -147.776809692, 117.902046204, 28.8581352234, -22.4280166626, 28.6324996948, 2.83816099167, -6.04741716385, 10.0253458023, 14.6831378937, 15.1529960632, 101.876480103, 16.7505264282 ], [ 121.933448792, 75.2410125732, -80.0259933472, 29.7626171112, 29.361246109, -22.8170604706, 11.5606393814, 28.1404056549, 15.4272651672, -20.7214431763, -6.4773888588, 16.7505264282, 91.9189758301 ] ] }, "spectral_flux":{ "min":6.40516528705e-11, "max":0.355690479279, "dvar2":0.00278266565874, "median":0.0625253766775, "dmean2":0.0423415489495, "dmean":0.0282820314169, "var":0.00376007612795, "dvar":0.00135926820803, "mean":0.0749769806862 }, "silence_rate_30dB":{ "min":0, "max":1, "dvar2":0.0354892387986, "median":1, "dmean2":0.0246406570077, "dmean":0.0123189976439, "var":0.00654759025201, "dvar":0.0121672395617, "mean":0.993408977985 }, "spectral_energyband_middle_high":{ "min":1.27805372214e-21, "max":0.0389622859657, "dvar2":9.42645056057e-06, "median":0.00293085677549, "dmean2":0.00200005969964, "dmean":0.00133119279053, "var":2.5883437047e-05, "dvar":4.14980877395e-06, "mean":0.00445337453857 }, "barkbands_spread":{ "min":0.167884364724, "max":139.821090698, "dvar2":253.175750732, "median":18.0125980377, "dmean2":10.9470348358, "dmean":6.75650119781, "var":180.234161377, "dvar":101.147232056, "mean":20.320306778 }, "spectral_centroid":{ "min":111.030769348, "max":11065.2148438, "dvar2":701335.5625, "median":1143.22497559, "dmean2":567.022827148, "dmean":354.07824707, "var":626410.0625, "dvar":292997.4375, "mean":1266.39624023 }, "pitch_salience":{ "min":0.103756688535, "max":0.928133249283, "dvar2":0.013650230132, "median":0.569122076035, "dmean2":0.124187774956, "dmean":0.0767409279943, "var":0.0128469280899, "dvar":0.00529233785346, "mean":0.566493272781 }, "erbbands_skewness":{ "min":-8.09688186646, "max":6.17588758469, "dvar2":1.00871086121, "median":0.283587485552, "dmean2":0.786845207214, "dmean":0.512230575085, "var":1.42545306683, "dvar":0.427418738604, "mean":0.235957682133 }, "erbbands_crest":{ "min":2.31988024712, "max":34.2482185364, "dvar2":16.2832355499, "median":8.70411396027, "dmean2":4.28936433792, "dmean":2.70263242722, "var":24.3617858887, "dvar":6.85065603256, "mean":9.92293930054 }, "melbands":{ "min":[ 1.7312522864e-24, 4.69779527492e-24, 4.46513652814e-24, 3.32025441336e-24, 6.6967940523e-24, 5.54350662457e-24, 5.62380004294e-24, 7.24197266845e-24, 4.37425935743e-24, 6.31036856572e-24, 4.53679113075e-24, 3.08454218323e-24, 4.01757944901e-24, 5.05271286808e-24, 5.25895581858e-24, 3.18568913964e-24, 7.13208118891e-24, 4.5636159514e-24, 5.04583400098e-24, 6.17228950832e-24, 6.96855978959e-24, 4.44096109684e-24, 6.9472211021e-24, 7.30462636813e-24, 7.82425851273e-24, 7.32260214157e-24, 5.87433201125e-24, 6.79884662102e-24, 6.23345462746e-24, 6.36714722381e-24, 5.56132344254e-24, 7.90887173342e-24, 7.08392990812e-24, 8.85545433259e-24, 6.01856418372e-24, 6.31963413149e-24, 6.85279050744e-24, 7.75657976909e-24, 8.50479856047e-24, 7.94873918585e-24 ], "max":[ 0.0150078302249, 0.0248268786818, 0.0372853949666, 0.0202775932848, 0.00924268271774, 0.00459495186806, 0.00642714649439, 0.00673051225021, 0.00483322422951, 0.0058145863004, 0.00487699825317, 0.00474451202899, 0.00216139364056, 0.00089383253362, 0.000890302297194, 0.00114067236427, 0.00265396363102, 0.00179244857281, 0.00171541213058, 0.00327429641038, 0.00261263479479, 0.00140622933395, 0.000604341796134, 0.000546872266568, 0.00119282689411, 0.000385722087231, 0.000307112553855, 0.000185638607945, 0.000196822540602, 7.07383733243e-05, 3.59257646778e-05, 4.41324045823e-05, 5.90648887737e-05, 5.03649462189e-05, 1.98958878173e-05, 1.04367582026e-05, 1.49458364831e-05, 3.54613039235e-05, 2.11343995034e-05, 1.33671064759e-05 ], "dvar2":[ 1.97027497961e-06, 1.79839098564e-05, 3.41721388395e-05, 6.39068775854e-06, 4.12703258235e-07, 1.60991760367e-07, 5.84672534387e-07, 1.35801229817e-07, 5.67447884237e-08, 9.04100758703e-08, 5.12682660769e-08, 6.00754361813e-08, 8.33282598478e-09, 2.19900075926e-09, 2.22529794591e-09, 2.68628164157e-09, 6.38194253e-09, 4.48827552901e-09, 1.61791646747e-09, 5.6524527281e-09, 7.00124225261e-09, 5.1307971205e-09, 1.8114484357e-09, 6.22804863237e-10, 1.41800715614e-09, 5.03870334345e-10, 3.42071621029e-10, 8.80266623482e-11, 5.10801435871e-11, 1.6358601973e-11, 1.09966497713e-11, 1.34551406475e-11, 2.12651927317e-11, 8.70376774126e-12, 2.70498077062e-12, 8.23377390574e-13, 6.18267915163e-13, 8.94622212682e-13, 5.74140724113e-13, 4.04918747187e-13 ], "median":[ 6.78846045048e-05, 0.000686653598677, 0.00100371893495, 0.000425793463364, 0.000121567500173, 8.67325506988e-05, 0.000119830452604, 7.64572032494e-05, 4.73126528959e-05, 4.95156273246e-05, 5.10508471052e-05, 3.72932154278e-05, 1.39631702041e-05, 4.18296076532e-06, 3.36458288075e-06, 5.95153596805e-06, 7.06666241967e-06, 5.36886500413e-06, 6.55584017295e-06, 1.27752928165e-05, 1.80421066034e-05, 1.10708388092e-05, 9.13756139198e-06, 6.40786538497e-06, 6.87108331476e-06, 5.39385519005e-06, 3.31015212396e-06, 2.2452804842e-06, 2.11795463656e-06, 8.45357135404e-07, 1.55302529947e-07, 2.16630468231e-07, 2.0936421663e-07, 1.59076819273e-07, 1.03014848207e-07, 5.60769883862e-08, 4.16746956944e-08, 3.91173387015e-08, 3.08294119122e-08, 2.99958919925e-08 ], "dmean2":[ 0.000655197829474, 0.00202016695403, 0.00265697692521, 0.00127012608573, 0.000302697066218, 0.000204388590646, 0.000336306344252, 0.000177521447768, 0.000107648374978, 0.000137986353366, 0.000116639275802, 0.000105825478386, 3.63973231288e-05, 1.78256286745e-05, 1.63039130712e-05, 1.98472516786e-05, 2.55192408076e-05, 1.86820070667e-05, 1.45677859109e-05, 2.93159864668e-05, 3.81224999728e-05, 2.55198028754e-05, 1.86311717698e-05, 1.29478112285e-05, 1.63034928846e-05, 1.03988468254e-05, 6.90801107339e-06, 4.38494134869e-06, 3.91557023249e-06, 1.95062216335e-06, 1.26417035062e-06, 1.61554555689e-06, 1.957419272e-06, 1.21927041619e-06, 7.50478704958e-07, 4.08925643569e-07, 3.15493565495e-07, 2.87596407134e-07, 2.50877462804e-07, 2.38469112901e-07 ], "dmean":[ 0.000433199049439, 0.00115317711607, 0.00158822687808, 0.000778516754508, 0.000194163410924, 0.000129944470245, 0.00020776965539, 0.000110655011667, 7.02645556885e-05, 8.88201902853e-05, 7.56665394874e-05, 7.11579850758e-05, 2.26343472605e-05, 1.1214566257e-05, 1.06519555629e-05, 1.3082231817e-05, 1.72533091245e-05, 1.2507844076e-05, 9.44854855334e-06, 1.93181331269e-05, 2.54146216321e-05, 1.58707625815e-05, 1.14972417578e-05, 8.10282745078e-06, 1.0418824786e-05, 6.57239706925e-06, 4.29072770203e-06, 2.71895851256e-06, 2.42956934926e-06, 1.20713775686e-06, 7.98163171112e-07, 1.02098283605e-06, 1.22477297282e-06, 8.0222929455e-07, 4.99395412135e-07, 2.76074587191e-07, 2.18049038381e-07, 1.94722304059e-07, 1.73989079144e-07, 1.64999249819e-07 ], "var":[ 1.04273829038e-06, 4.88182786285e-06, 1.22067667689e-05, 3.09852111968e-06, 2.95254579896e-07, 1.60118688086e-07, 3.36397903311e-07, 9.02441499306e-08, 5.12204714198e-08, 8.87765096991e-08, 6.13447141973e-08, 1.30928043518e-07, 7.16093628839e-09, 2.90166846106e-09, 3.30743610277e-09, 3.75769282357e-09, 1.11862910046e-08, 7.38158290048e-09, 3.41670158832e-09, 2.24571348184e-08, 3.01072198283e-08, 4.89972462603e-09, 1.57648072374e-09, 7.79673825502e-10, 2.14637396745e-09, 5.14293607701e-10, 2.73522648975e-10, 8.45902653479e-11, 5.53298171169e-11, 1.09233455614e-11, 4.45680905375e-12, 6.09628753728e-12, 8.53084356628e-12, 4.52617804347e-12, 1.82034248786e-12, 6.15677430912e-13, 4.4449592119e-13, 6.71954570979e-13, 5.48820374997e-13, 3.48484424911e-13 ], "dvar":[ 8.33708043046e-07, 6.49838420941e-06, 1.36113221743e-05, 2.76258151644e-06, 1.75387782519e-07, 6.53309797372e-08, 2.18858644985e-07, 5.17116269805e-08, 2.40723956324e-08, 3.69722101823e-08, 2.22425278196e-08, 2.84932291095e-08, 3.64641872252e-09, 9.5759922214e-10, 9.86244308443e-10, 1.3016818734e-09, 3.31316440949e-09, 2.19745110996e-09, 7.73902275597e-10, 3.32642535739e-09, 3.88597554135e-09, 1.99106442444e-09, 7.00074609394e-10, 2.79730322239e-10, 6.32938867984e-10, 2.10190226335e-10, 1.22236526456e-10, 3.66416376407e-11, 2.22450686344e-11, 6.52528248449e-12, 4.34595848892e-12, 5.58480735616e-12, 8.46765019213e-12, 3.64534357561e-12, 1.20417478072e-12, 3.81005014864e-13, 2.8428255301e-13, 3.87186458025e-13, 2.78560404994e-13, 1.87431545436e-13 ], "mean":[ 0.00047609579633, 0.00126094208099, 0.00185862951912, 0.000971358967945, 0.000324478023686, 0.000246531388257, 0.000361267186236, 0.000190427192138, 0.000126440427266, 0.000159403600264, 0.000136641858262, 0.000143978060805, 3.71072310372e-05, 1.87067053048e-05, 1.93349878828e-05, 2.34964645642e-05, 3.1896517612e-05, 2.36660616793e-05, 1.83704396477e-05, 4.34660541941e-05, 5.81043132115e-05, 2.89009076369e-05, 2.15983145608e-05, 1.50616651808e-05, 1.95628890651e-05, 1.24749267343e-05, 8.04845058155e-06, 4.90500542583e-06, 4.20188916905e-06, 1.82525320724e-06, 8.70177814249e-07, 1.09259167402e-06, 1.25471365209e-06, 9.23780646644e-07, 6.02008753958e-07, 3.45971272964e-07, 2.69976595746e-07, 2.55056221476e-07, 2.36791535713e-07, 2.26877631349e-07 ] }, "spectral_entropy":{ "min":4.61501169205, "max":9.81467628479, "dvar2":0.184129029512, "median":7.38190746307, "dmean2":0.352754920721, "dmean":0.243219792843, "var":0.300432950258, "dvar":0.0902535244823, "mean":7.3010840416 }, "spectral_rolloff":{ "min":64.599609375, "max":21037.9394531, "dvar2":3396222, "median":861.328125, "dmean2":1057.10974121, "dmean":604.693481445, "var":2179523.25, "dvar":1425528, "mean":1383.6763916 }, "barkbands":{ "min":[ 6.93473619499e-25, 5.19568601854e-24, 1.02416202049e-23, 4.28463410897e-24, 3.04471689542e-23, 2.72335547301e-23, 3.08580014027e-23, 1.15517745957e-23, 5.01556722243e-23, 3.01743335215e-23, 3.20834273992e-23, 6.39242832255e-23, 4.96037188707e-23, 6.11980114915e-23, 7.73605723709e-23, 1.27850093686e-22, 8.33913319498e-23, 1.55698133196e-22, 1.80609161514e-22, 2.27535985033e-22, 3.03975723224e-22, 3.99622470031e-22, 4.5185483121e-22, 7.15649816942e-22, 1.01532623561e-21, 1.53862207745e-21, 2.31706194078e-21 ], "max":[ 0.00229191919789, 0.047907166183, 0.0691591277719, 0.0995827168226, 0.0820566862822, 0.0232072826475, 0.0308443717659, 0.0302771702409, 0.0344947054982, 0.0269099473953, 0.0134304724634, 0.00715320091695, 0.00838674418628, 0.0218261200935, 0.019664183259, 0.0362881943583, 0.0182446800172, 0.0173479039222, 0.0146563379094, 0.00540218688548, 0.00442544184625, 0.00217473763041, 0.0013186649885, 0.00208773952909, 0.00195873784833, 0.000584891589824, 0.00050722778542 ], "dvar2":[ 2.09710808718e-08, 5.00840687891e-05, 9.50076937443e-05, 0.000209878431633, 8.73877215781e-05, 3.97830672227e-06, 1.24859725474e-05, 1.86764350474e-06, 3.62891637451e-06, 3.01378167933e-06, 5.96735674208e-07, 1.57074438789e-07, 2.46402947823e-07, 4.87388831516e-07, 4.96838595154e-07, 1.52867119141e-06, 1.2727361991e-06, 3.34951494096e-07, 4.58745859078e-07, 1.02385989464e-07, 2.90899002664e-08, 3.47254207611e-08, 1.03255741735e-08, 3.98843491567e-09, 4.08773503935e-09, 1.11437570283e-09, 4.70612881998e-10 ], "median":[ 1.01329169411e-06, 0.000326245411998, 0.00187892094254, 0.00155476410873, 0.0016892075073, 0.000451811589301, 0.000548189680558, 0.000192572828382, 0.000307663634885, 0.000414336362155, 9.44759449339e-05, 2.73611021839e-05, 5.38471249456e-05, 6.47374472464e-05, 8.72917589732e-05, 0.000232024758589, 0.000200124268304, 0.000144036966958, 0.000164192693774, 8.08068361948e-05, 4.40170915681e-05, 1.11471890705e-05, 6.5616086431e-06, 3.2568784718e-06, 2.92447043648e-06, 4.78593108255e-07, 7.76246977807e-08 ], "dmean2":[ 5.63530775253e-05, 0.00340586039238, 0.00441808719188, 0.00632638018578, 0.0048057041131, 0.00103038607631, 0.00156902591698, 0.000596007099375, 0.000905426510144, 0.000906587869395, 0.000307931040879, 0.000146102538565, 0.000193360538105, 0.000240257213591, 0.000224526840611, 0.00052686111303, 0.000436997273937, 0.000281702930806, 0.000314143690048, 0.000150212654262, 8.88355425559e-05, 8.39097774588e-05, 4.62743046228e-05, 2.28419812629e-05, 2.21090576815e-05, 1.11555727926e-05, 5.03497130921e-06 ], "dmean":[ 4.36054288002e-05, 0.00207182555459, 0.00250360206701, 0.00372918182984, 0.0029777479358, 0.00065627245931, 0.000966914638411, 0.000378262484446, 0.000581912638154, 0.000613346113823, 0.000192098785192, 9.08574875211e-05, 0.000126861719764, 0.000160341092851, 0.000145415237057, 0.00034682394471, 0.000273586803814, 0.000176411645953, 0.000198787456611, 9.40177123994e-05, 5.56063205295e-05, 5.36341467523e-05, 3.11664407491e-05, 1.60014496942e-05, 1.57560625667e-05, 7.42050679037e-06, 3.44123100149e-06 ], "var":[ 1.73105885182e-08, 1.84976615856e-05, 2.50716802839e-05, 7.04820486135e-05, 4.76136665384e-05, 3.67056259165e-06, 6.74153125146e-06, 1.57238355314e-06, 3.58573174708e-06, 5.54312009626e-06, 5.51931407244e-07, 1.78970466891e-07, 4.17550438669e-07, 9.57703605309e-07, 8.59389047037e-07, 6.6176985456e-06, 1.22271069358e-06, 4.2584204607e-07, 5.58315321086e-07, 9.85875061588e-08, 2.47446703128e-08, 1.64356386279e-08, 7.04793423623e-09, 3.46884565516e-09, 3.82823417411e-09, 6.34027108593e-10, 3.8906944333e-10 ], "dvar":[ 1.15370024645e-08, 1.92330826394e-05, 3.36813718604e-05, 8.24065355118e-05, 3.870560613e-05, 1.55360748977e-06, 4.66681467515e-06, 7.47769490772e-07, 1.50442451741e-06, 1.46062268414e-06, 2.81505151634e-07, 6.65834889446e-08, 1.17960382795e-07, 2.50351632758e-07, 2.41593681949e-07, 8.20324487449e-07, 5.11046778229e-07, 1.56924727435e-07, 1.97066171381e-07, 4.1844121057e-08, 1.20861924913e-08, 1.45208129965e-08, 4.66174743252e-09, 1.88047488692e-09, 2.07477035552e-09, 5.05100294923e-10, 2.44846420916e-10 ], "mean":[ 5.19759996678e-05, 0.00199001817964, 0.00309076649137, 0.00392009504139, 0.0039071268402, 0.00123883492779, 0.00161516538355, 0.000634168100078, 0.00102682900615, 0.00122780457605, 0.000289549614536, 0.000142228382174, 0.000236654945184, 0.000305703491904, 0.000276061356999, 0.000822361966129, 0.000508801313117, 0.000334064679919, 0.000397378782509, 0.00017829038552, 8.88610738912e-05, 5.81649801461e-05, 3.79984667234e-05, 2.1309551812e-05, 2.22307517106e-05, 7.82890947448e-06, 3.57463068212e-06 ] }, "melbands_flatness_db":{ "min":0.00437760027125, "max":0.607957184315, "dvar2":0.00331180845387, "median":0.219427987933, "dmean2":0.0528259426355, "dmean":0.034728333354, "var":0.00492821913213, "dvar":0.00150177872274, "mean":0.230123117566 }, "melbands_skewness":{ "min":-2.44428515434, "max":15.3962888718, "dvar2":2.92571592331, "median":2.28337860107, "dmean2":1.4999755621, "dmean":0.987386882305, "var":4.25560426712, "dvar":1.34734094143, "mean":2.84234952927 }, "barkbands_skewness":{ "min":-6.20005989075, "max":18.9707603455, "dvar2":2.02687716484, "median":1.45346200466, "dmean2":1.15091514587, "dmean":0.750691831112, "var":2.42782378197, "dvar":0.866045475006, "mean":1.71697402 }, "silence_rate_60dB":{ "min":0, "max":1, "dvar2":0.0371209047735, "median":0, "dmean2":0.0337187945843, "dmean":0.0168575756252, "var":0.179377868772, "dvar":0.0165733974427, "mean":0.234251752496 }, "spectral_energyband_low":{ "min":4.89638611687e-23, "max":0.116083092988, "dvar2":0.000277574028587, "median":0.00443472480401, "dmean2":0.00833203457296, "dmean":0.00496239587665, "var":9.57977899816e-05, "dvar":0.000101656405604, "mean":0.00667642848566 }, "spectral_energyband_middle_low":{ "min":2.98093395713e-22, "max":0.171243280172, "dvar2":0.000569899275433, "median":0.0082081919536, "dmean2":0.0117948763072, "dmean":0.00737277884036, "var":0.000299356790492, "dvar":0.000242799738771, "mean":0.0127554573119 }, "melbands_kurtosis":{ "min":-1.94107413292, "max":380.680023193, "dvar2":1038.95019531, "median":7.13754844666, "dmean2":17.6919975281, "dmean":11.5336751938, "var":1275.55053711, "dvar":493.653686523, "mean":19.2873706818 }, "spectral_decrease":{ "min":-4.64023344193e-08, "max":6.78438804261e-19, "dvar2":6.20802821665e-17, "median":-4.53350113006e-09, "dmean2":4.26796598063e-09, "dmean":2.69736544212e-09, "var":3.69683427013e-17, "dvar":2.61311086979e-17, "mean":-5.59147705914e-09 }, "erbbands_kurtosis":{ "min":-1.86338639259, "max":171.201263428, "dvar2":23.2438850403, "median":-0.320037484169, "dmean2":2.39585089684, "dmean":1.52739417553, "var":35.0008544922, "dvar":11.0155954361, "mean":1.24987971783 }, "melbands_crest":{ "min":1.85922825336, "max":32.9627304077, "dvar2":27.1548709869, "median":12.5910797119, "dmean2":5.60343551636, "dmean":3.39730739594, "var":20.3299713135, "dvar":10.5175638199, "mean":13.3324451447 }, "melbands_spread":{ "min":0.26147004962, "max":299.135498047, "dvar2":1027.73010254, "median":17.4329528809, "dmean2":16.3484096527, "dmean":10.0459423065, "var":529.263366699, "dvar":403.605499268, "mean":23.2355747223 }, "spectral_energy":{ "min":1.02320440393e-20, "max":0.179453358054, "dvar2":0.000923860818148, "median":0.0185781233013, "dmean2":0.0165870357305, "dmean":0.0105188144371, "var":0.000572183460463, "dvar":0.00039060486597, "mean":0.0224339049309 }, "mfcc":{ "mean":[ -715.191650391, 133.878646851, -2.74888682365, 38.7127075195, 3.85699295998, -10.4443674088, -5.89105558395, 4.36424779892, 2.37372231483, 1.66640949249, -7.12301874161, -9.74494552612, -3.86338329315 ], "icov":[ [ 7.98077235231e-05, -5.86888636462e-05, 0.000145378129673, -9.86643281067e-05, 3.03972447e-05, -0.000187377940165, 0.000134168396471, -0.000129314183141, 1.27186794998e-05, -7.31398395146e-05, 1.38320649512e-06, 0.000111114335596, -8.96842757356e-05 ], [ -5.86888636462e-05, 0.000914695789106, -1.55892048497e-05, 0.000330161477905, -0.000239893066464, 0.00115360564087, -0.000499361369293, 0.000324924068991, -1.15215043479e-05, -0.000243278453127, 0.000191972227185, -9.64893956734e-07, 0.000270225456916 ], [ 0.000145378129673, -1.55892048497e-05, 0.0013757571578, 7.94086445239e-05, -0.000468786456622, -0.00135524733923, 0.00098228675779, -0.000316469959216, -0.000591932330281, 0.000769039965235, -0.000745072495192, 0.000638137804344, 0.000274067162536 ], [ -9.86643281067e-05, 0.000330161477905, 7.94086445239e-05, 0.00385635741986, -0.00140862353146, 0.000500513473526, 0.000532710750122, -0.00153480307199, 0.000852926750667, -0.000837227795273, 0.00151946756523, -0.00070260866778, 0.000143392870086 ], [ 3.03972447e-05, -0.000239893066464, -0.000468786456622, -0.00140862353146, 0.0056857005693, -0.00172490451951, -0.00111165409908, 0.000201825780096, 0.000247466086876, -0.00217686733231, 0.00112909392919, -0.000958321907092, -0.000166401950992 ], [ -0.000187377940165, 0.00115360564087, -0.00135524733923, 0.000500513473526, -0.00172490451951, 0.00837340857834, -0.00406587868929, 0.00216831197031, -0.0023798532784, 0.00346444058232, -0.00286303297617, 0.00123248388991, -0.000868651026394 ], [ 0.000134168396471, -0.000499361369293, 0.00098228675779, 0.000532710750122, -0.00111165409908, -0.00406587868929, 0.00986782740802, -0.00542975915596, 0.00409825751558, -0.0044681020081, 0.00282385596074, -0.00354772782885, 0.00168551225215 ], [ -0.000129314183141, 0.000324924068991, -0.000316469959216, -0.00153480307199, 0.000201825780096, 0.00216831197031, -0.00542975915596, 0.0144132943824, -0.00864001736045, 0.00550767453387, -0.00397388311103, 0.00314126117155, -0.00206855195574 ], [ 1.27186794998e-05, -1.15215043479e-05, -0.000591932330281, 0.000852926750667, 0.000247466086876, -0.0023798532784, 0.00409825751558, -0.00864001736045, 0.0176015142351, -0.0112102692947, 0.0083336783573, -0.00373222492635, 0.00208288733847 ], [ -7.31398395146e-05, -0.000243278453127, 0.000769039965235, -0.000837227795273, -0.00217686733231, 0.00346444058232, -0.0044681020081, 0.00550767453387, -0.0112102692947, 0.0205363947898, -0.0105180032551, 0.00535045098513, -0.00213157944381 ], [ 1.38320649512e-06, 0.000191972227185, -0.000745072495192, 0.00151946756523, 0.00112909392919, -0.00286303297617, 0.00282385596074, -0.00397388311103, 0.0083336783573, -0.0105180032551, 0.0160211343318, -0.00672314595431, 0.00358490552753 ], [ 0.000111114335596, -9.64893956734e-07, 0.000638137804344, -0.00070260866778, -0.000958321907092, 0.00123248388991, -0.00354772782885, 0.00314126117155, -0.00373222492635, 0.00535045098513, -0.00672314595431, 0.0181408431381, -0.00800348073244 ], [ -8.96842757356e-05, 0.000270225456916, 0.000274067162536, 0.000143392870086, -0.000166401950992, -0.000868651026394, 0.00168551225215, -0.00206855195574, 0.00208288733847, -0.00213157944381, 0.00358490552753, -0.00800348073244, 0.0156487096101 ] ], "cov":[ [ 18717.6230469, 1395.88500977, -2566.72802734, 557.851989746, -126.109024048, -374.194091797, 26.1053237915, 164.080841064, 80.1878204346, 192.214401245, -182.145751953, -47.5592041016, 152.686767578 ], [ 1395.88500977, 1649.59350586, -550.320007324, -49.1516876221, -56.1948204041, -331.535217285, 9.86240959167, -34.6940498352, -6.41311454773, 74.1020736694, -56.9916381836, -16.3797187805, -19.4202880859 ], [ -2566.72802734, -550.320007324, 1546.81799316, -94.7429580688, 133.984313965, 339.89239502, -54.6255912781, 10.0923881531, 34.4428405762, -69.080619812, 85.0990753174, -36.5973091125, -56.1265907288 ], [ 557.851989746, -49.1516876221, -94.7429580688, 342.6902771, 83.1379013062, -15.0537748337, 17.4024486542, 46.2917900085, 21.9955101013, 12.8328580856, -40.3507461548, 8.21014022827, 19.1214065552 ], [ -126.109024048, -56.1948204041, 133.984313965, 83.1379013062, 261.195220947, 98.0570144653, 69.749458313, 21.4776115417, 23.9828796387, 28.7067451477, 2.99768400192, 18.3751049042, 10.1154251099 ], [ -374.194091797, -331.535217285, 339.89239502, -15.0537748337, 98.0570144653, 288.139526367, 71.6913833618, 15.3370637894, 9.08637428284, -21.2720279694, 42.7490844727, 11.0748538971, 0.872315227985 ], [ 26.1053237915, 9.86240959167, -54.6255912781, 17.4024486542, 69.749458313, 71.6913833618, 187.006271362, 49.2006340027, 4.36477804184, 25.2697525024, 7.5669798851, 29.0018577576, 7.81967544556 ], [ 164.080841064, -34.6940498352, 10.0923881531, 46.2917900085, 21.4776115417, 15.3370637894, 49.2006340027, 122.378990173, 54.7077331543, 6.68141078949, -6.7650809288, -0.911539852619, 7.60771179199 ], [ 80.1878204346, -6.41311454773, 34.4428405762, 21.9955101013, 23.9828796387, 9.08637428284, 4.36477804184, 54.7077331543, 120.954666138, 41.4050827026, -25.8017272949, -5.81494665146, -0.236202299595 ], [ 192.214401245, 74.1020736694, -69.080619812, 12.8328580856, 28.7067451477, -21.2720279694, 25.2697525024, 6.68141078949, 41.4050827026, 102.835891724, 31.3814048767, -2.45175004005, -1.74627566338 ], [ -182.145751953, -56.9916381836, 85.0990753174, -40.3507461548, 2.99768400192, 42.7490844727, 7.5669798851, -6.7650809288, -25.8017272949, 31.3814048767, 120.884010315, 22.8159122467, -8.79971408844 ], [ -47.5592041016, -16.3797187805, -36.5973091125, 8.21014022827, 18.3751049042, 11.0748538971, 29.0018577576, -0.911539852619, -5.81494665146, -2.45175004005, 22.8159122467, 87.9682235718, 38.346157074 ], [ 152.686767578, -19.4202880859, -56.1265907288, 19.1214065552, 10.1154251099, 0.872315227985, 7.81967544556, 7.60771179199, -0.236202299595, -1.74627566338, -8.79971408844, 38.346157074, 87.662071228 ] ] }, "spectral_contrast_valleys":{ "min":[ -27.644701004, -27.7437572479, -27.5804691315, -27.6421985626, -27.3466243744, -27.4174346924 ], "max":[ -5.21189641953, -4.43200492859, -5.37789392471, -5.91939544678, -5.84870004654, -8.253657341 ], "dvar2":[ 0.418128162622, 0.42821636796, 0.406443417072, 0.387645244598, 0.499291837215, 0.697984993458 ], "median":[ -7.62850189209, -6.92876195908, -7.67359733582, -8.07751655579, -7.46400737762, -11.0671672821 ], "dmean2":[ 0.747626721859, 0.710296332836, 0.67908090353, 0.625626146793, 0.595694363117, 0.680769026279 ], "dmean":[ 0.493877381086, 0.47190451622, 0.458809673786, 0.433981686831, 0.418061226606, 0.529967188835 ], "var":[ 2.56318879128, 2.56686043739, 2.68657803535, 2.71048474312, 2.86386156082, 2.03321886063 ], "dvar":[ 0.185303419828, 0.210249379277, 0.205063581467, 0.197276696563, 0.240655809641, 0.327577888966 ], "mean":[ -7.9825963974, -7.30778980255, -8.13263988495, -8.62220096588, -8.10116863251, -11.1167650223 ] }, "barkbands_flatness_db":{ "min":0.00845116842538, "max":0.463767468929, "dvar2":0.00153901893646, "median":0.152025014162, "dmean2":0.0385256558657, "dmean":0.0259312130511, "var":0.00293617043644, "dvar":0.000700293399859, "mean":0.161552548409 }, "dynamic_complexity":5.97568511963, "spectral_skewness":{ "min":-0.258594423532, "max":7.78090715408, "dvar2":0.501113593578, "median":1.41668355465, "dmean2":0.598508477211, "dmean":0.382409095764, "var":0.599681735039, "dvar":0.224964693189, "mean":1.57063114643 }, "erbbands_flatness_db":{ "min":0.0321905463934, "max":0.434577912092, "dvar2":0.00118384102825, "median":0.181439816952, "dmean2":0.0333808884025, "dmean":0.024810899049, "var":0.00294912024401, "dvar":0.000594827288296, "mean":0.178649738431 }, "hfc":{ "min":1.12110872149e-16, "max":96.712890625, "dvar2":109.576454163, "median":11.9836702347, "dmean2":6.97959280014, "dmean":4.67007303238, "var":197.084396362, "dvar":50.9854736328, "mean":14.6673564911 }, "barkbands_crest":{ "min":2.1863629818, "max":25.4534358978, "dvar2":11.5983400345, "median":8.56367301941, "dmean2":3.74820661545, "dmean":2.30216050148, "var":11.5966396332, "dvar":4.54739236832, "mean":9.14883136749 } }, "highlevel":{ "timbre":{ "all":{ "dark":0.0808309540153, "bright":0.919169068336 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"bright", "probability":0.919169068336 }, "ismir04_rhythm":{ "all":{ "Rumba-American":0.0406456775963, "VienneseWaltz":0.338310062885, "Samba":0.0297329928726, "Rumba-Misc":0.0135653112084, "Rumba-International":0.0278510767967, "Tango":0.330144882202, "Waltz":0.00898563489318, "ChaChaCha":0.0889096781611, "Jive":0.11033257097, "Quickstep":0.0115221142769 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"VienneseWaltz", "probability":0.338310062885 }, "voice_instrumental":{ "all":{ "instrumental":0.999981045723, "voice":1.89501206478e-05 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"instrumental", "probability":0.999981045723 }, "gender":{ "all":{ "male":0.108683988452, "female":0.891315996647 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"female", "probability":0.891315996647 }, "genre_rosamerica":{ "all":{ "hip":0.070330247283, "rhy":0.225707545877, "jaz":0.0771619826555, "dan":0.0574826933444, "roc":0.270465612411, "cla":0.0938607081771, "pop":0.175827592611, "spe":0.0291636306792 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"roc", "probability":0.270465612411 }, "mood_electronic":{ "all":{ "electronic":0.339881360531, "not_electronic":0.660118639469 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"not_electronic", "probability":0.660118639469 }, "genre_electronic":{ "all":{ "house":0.187250360847, "trance":0.185409858823, "dnb":0.00702595943585, "techno":0.0184047427028, "ambient":0.601909101009 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"ambient", "probability":0.601909101009 }, "mood_sad":{ "all":{ "not_sad":0.700305402279, "sad":0.299694597721 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"not_sad", "probability":0.700305402279 }, "tonal_atonal":{ "all":{ "atonal":0.125749841332, "tonal":0.874250173569 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"tonal", "probability":0.874250173569 }, "mood_party":{ "all":{ "party":0.234383180737, "not_party":0.765616834164 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"not_party", "probability":0.765616834164 }, "moods_mirex":{ "all":{ "Cluster2":0.0673071071506, "Cluster3":0.397048592567, "Cluster1":0.061667304486, "Cluster4":0.190215244889, "Cluster5":0.283761769533 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"Cluster3", "probability":0.397048592567 }, "danceability":{ "all":{ "danceable":0.143928021193, "not_danceable":0.85607200861 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"not_danceable", "probability":0.85607200861 }, "genre_dortmund":{ "all":{ "raphiphop":4.74844455312e-05, "electronic":0.984485208988, "jazz":0.000787914788816, "pop":0.000125292601297, "folkcountry":0.00235203420743, "rock":0.0010081063956, "alternative":0.00961782038212, "funksoulrnb":6.0458383814e-05, "blues":0.00151570443995 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"electronic", "probability":0.984485208988 }, "mood_acoustic":{ "all":{ "acoustic":0.415711194277, "not_acoustic":0.584288835526 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"not_acoustic", "probability":0.584288835526 }, "mood_happy":{ "all":{ "not_happy":0.910523295403, "happy":0.0894767045975 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"not_happy", "probability":0.910523295403 }, "mood_aggressive":{ "all":{ "not_aggressive":0.922077834606, "aggressive":0.0779221653938 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"not_aggressive", "probability":0.922077834606 }, "genre_tzanetakis":{ "all":{ "hip":0.154464527965, "jaz":0.308918893337, "bl":0.0514711923897, "roc":0.0772226303816, "cla":0.0343172624707, "pop":0.0617748275399, "met":0.0441242903471, "co":0.102957598865, "reg":0.0617764480412, "dis":0.102972343564 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"jaz", "probability":0.308918893337 }, "mood_relaxed":{ "all":{ "not_relaxed":0.87636756897, "relaxed":0.123632438481 }, "version":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" }, "value":"not_relaxed", "probability":0.87636756897 } }, "metadata":{ "audio_properties":{ "analysis_sample_rate":44100, "length":214.866668701, "downmix":"mix", "bit_rate":0, "codec":"flac", "md5_encoded":"2b46dab358c1b79a3decd5bd93d7221f", "equal_loudness":0, "replay_gain":-14.4778690338, "lossless":1 }, "version":{ "lowlevel":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "essentia_build_sha":"50a0fbec89d6a9cedea3d45b6611406f7e8c7b1a", "essentia_git_sha":"v2.1_beta1-7-ge0e83e8-dirty" }, "highlevel":{ "essentia":"2.1-beta1", "extractor":"music 1.0", "gaia_git_sha":"857329b", "models_essentia_git_sha":"v2.1_beta1", "essentia_git_sha":"v2.1_beta1-228-g260734a", "essentia_build_sha":"8e24b98b71ad84f3024c7541412f02124a26d327", "gaia":"2.4-dev" } }, "tags":{ "albumartistsort":[ "Various Artists" ], "disctotal":[ "1" ], "file_name":"04 La Grange.flac", "artists":[ "ZZ Top" ], "musicbrainz_workid":[ "42722fe8-9de7-3729-a506-3c7f41c617a9" ], "releasecountry":[ "DE" ], "totaldiscs":[ "1" ], "albumartist":[ "Various Artists" ], "musicbrainz_albumartistid":[ "89ad4ac3-39f7-470e-963a-56509c546377" ], "composer":[ "Dusty Hill", "Frank Beard", "Billy Gibbons" ], "catalognumber":[ "491384 2" ], "tracknumber":[ "4" ], "replaygain_track_peak":[ "0.999969" ], "engineer":[ "Terry Manning", "Robin Hood Brians" ], "album":[ "Armageddon:The Album" ], "asin":[ "B000024C3A" ], "replaygain_album_gain":[ "-9.32 dB" ], "musicbrainz_artistid":[ "a81259a0-a2f5-464b-866e-71220f2739f1" ], "producer":[ "Bill Ham" ], "script":[ "Latn" ], "media":[ "CD" ], "label":[ "Columbia" ], "artistsort":[ "ZZ Top" ], "acoustid_id":[ "3ed3441e-facc-4fcd-9ef7-9fbc68c206a2" ], "replaygain_album_peak":[ "0.999969" ], "lyricist":[ "Dusty Hill", "Frank Beard", "Billy Gibbons" ], "musicbrainz_releasegroupid":[ "f51d56e4-0211-3533-a9a5-08c02d8bb04a" ], "compilation":[ "1" ], "barcode":[ "5099749138421" ], "releasestatus":[ "official" ], "composersort":[ "Hill, Dusty", "Beard, Frank", "Gibbons, Billy" ], "date":[ "1998" ], "isrc":[ "USWB10505222" ], "discnumber":[ "1" ], "musicbrainz_recordingid":[ "cd3f5efa-bc5e-4064-a765-960494ad4bb4" ], "tracktotal":[ "14" ], "originaldate":[ "1998-06-23" ], "language":[ "eng" ], "artist":[ "ZZ Top" ], "title":[ "La Grange" ], "releasetype":[ "album", "soundtrack" ], "musicbrainz_albumid":[ "cfc31187-aebd-309f-a92f-7138c17df7c2" ], "work":[ "La Grange" ], "totaltracks":[ "14" ], "replaygain_track_gain":[ "-9.38 dB" ], "musicbrainz_releasetrackid":[ "befe2741-462b-3568-ba06-c8cc8e4f6eaf" ] } } } beetbox-beets-00724b7/test/rsrc/image_unknown_type.mp30000664000175000017500000002432415253035401022333 0ustar pieterpieterID3SAPIC3image/pngÿalbum cover‰PNG  IHDR6ˆIÖ pHYs  šœtIMEÞ  J™tEXtCommentCreated with GIMPW�IDAT×cüÿÿ?‚9Ñ…'IEND®B`‚ÿûPÄInfo(!w  &&,,,33999@@FFFLLSSSYY```fflllssyyy€€†††ŒŒ“““™™   ¦¦¬¬¬³³¹¹¹ÀÀÆÆÆÌÌÓÓÓÙÙàààææìììóóùùùÿÿ9LAME3.97 ¥-þ@$|B@!w_»õ^ÿûPÄ1ªü@TØ5"L‹‰€TÇÿÿÿÿÿBhNs‡y�„}@3žÇ;çBú2¿úŸï!?úþ}C¡„'B�‰¨ÀbÊ€,=°² 7›âýcE`M.¦2 :ºJw� f}w§[?ÿÿÿÿ®�‘Ò�W:®ª…F Œø·BÒ5¥Ê纡Ö^³­*+R:kB·ß¿Û®Ÿÿßÿå™ü¾[�&8—Ub0'QX`€h¡eÿÿŸÿÙ2yÕYäÿûRÄ!ƒ)± @} 86`€³¡µ�àv"6‡¬ƒF” ³äÄÓ”š£ŸÃ=ØŠÿÃÿíçÞvó?Va˜VÓ¯S˜ä¤ËŒIùóläe÷M[#@~¸¨H'ŠÝz£U0¤fÿÿÿúZc{²™Î¤d îî‰tÖÇiƒ1ާ+Ó>b—Wn¯›¾·ÿÿÿüÿújÝkv}I*shìCÚ #9§™„Ä! ×u»kÑ{µjk¦¨™É+Q@·ãÚ·]šÙ+¶ŽºmÿöéFÿ¿nïâçÃWõÈó¯ÿûRÄ;ƒ­µ @×À÷¶aˆ N#œ4ìœHšW®JU?¦^gÍç=¿¥v„y*g^M)\ŒèÑZ¿½W$4>ÚdLN[Íûåú>¥S3õê*Ööß G_ÊxV#³B)ë´eT¶H Œ–šN@Ñk%©§GI,™eU]¦zQ.û«,¶-¯¬ª£"Ùõó·ÿõ¤~ù}ßJWò�}ÞÖT˜E¤>é ÈMŠB#–�¤D™?Èÿï–\dáO=!›Ÿbtph½'r†PŒ·¨ˆX.vlÈKÿûRÄWƒ ­µ =¶!'¡½…Ö.™|Ÿÿ÷ºùãnµXNkíÝbß aWIvȇ¢'HT'@if³³"rÙ•µz:ö²í£<êàŠZZVˆl¥VC¦žÌ´dO¯÷G+>F{)M¨¦³k-«¡‘§!M.hñqõ•Ò'ÆfŒz0@úÿÿúï�ºYïmV¶ígÔÖwµT†‘ x…!G!'GtÕ ÌgùÖ�2éK.ªüÖµ«mÞ“ºŠkœR1U¦cë’ë&ÈÊ ÄhÓF…ÿûRÄnƒ‰Y± = ¶ Ä'¡’�#¤´UdVißr˜Œ —N^’1·|ÓÜQêåZ=ÞÎëO7Z¶ÆÒ�}ùã�û³«×ÆwáñC¼[fB¢¯> ’†R*ˆŠ(£ ?ÎŒŽÿk;L¨�f*nS¡SyÌsfiÝT…*2ÙŠ&®ã;+È•ïÿ¦�µ ¿î‚YSõcY4FÚ™s­Î(M 4�q°È¬4EXuà�(ÐfJ8 vhã dznE"p z³3¬Ó¢zÿþr|í…ÿûRÄ„ Áµ@ 7Á#¶`È' ÷oò°×«¬Übß—w.Lû7eŠ’@K”¥)um.W§[MF¢‹vR6"î‘mÚvbÖf±QY˜ªGuJd³ý¾º~ü2[q޵öŸ�šŠÜfÊBýI�Œ“Ù+q Ñ áY¤û¾èàl;4·pÌ2!˜�äê£fŒKËCŽ˜…I¤«»Y%>®#Þ¾Ûøþ?Þ¯‰�y—³,¸b¡AY‡ž �,‘+�…” %*Œ?ÿÿÿËÿÿÿÿéíçX‘©ÿûRÄ–ƒ ³ =ý¶aH› Ò+Œ§º…-zÎv»c±¸F”ø1Þ�V”Ôß?Bøü'‘ßÈ‹ûßþoë$–R[ Ådt�¯# 4± KY$íq:4s²#M’ÀÊÀÕ= „gìdLt2•f;^«é�cµ]Lô[;£ÕS–ÕßÿúßD÷¾½ú~"‚i]1N^ w/jɃO)ª MFW+MÈ�6_+i¼oÌŠ¬ó%Èìéô™Á® )Ë $'¬ž\W'5³’ŸŸ6?'ÿþpüÏ&Ý™ÞãqÿûR݃ɯ =9¶ È£Xô¡Ùì”<ö =}aÔw¥“ꫜL»©ä¤NýÝgf¡V X‚�Š÷uQNkØJ$&¨gÈ©s©ÐªèÈ„\ôôµ?M?Ýÿ’ÛXßéCe+0Ylö¦Ñi4�,b`ø=@DˆWÿÿÿ-oU¦—ƒIT;f�Ê·j‘ ÇÕ’:ìtÑ… ¹ès5KÝ[$Ú?Ó#D ˆ§�øþ?þxç“ëˆÌ�ô¬-5ñ d_e°ÙSä9Ç$, ÿûRÄÄJͳ �= 6!'¡Øaþÿ?éö”`ÂI‰‚”]ÏKi»eóf;éi#R ¶/;:FSœ}LÄ×s ÓÔÏW¶ó£–=h¸c ¤4\jŒ" Eî A 8. `&¡ r ðäà‡å�¥?ôõÿñò‡¬¿-ŽB¼}åøåVAT÷QÞ>™Z­v_ÿWS›QW3µPÍÇ ›;ÙóÙN~U~íÿëåxJ§nÑ,¹!h,è–Ôš Òdj�-i² ¿DH\”ÿûRÄÕ ¡¯ �5ᡌ˜ËA€ J ŠÆ@ßÿÿÿEV"£¸ÌkÌeR‘÷w)ЬÇtz¯.æE!êK©nèÆvz¹W[ºûþúµu—ö¶ëÆ7”…N�J(ô˜"5±›Öó@ÁaL=#ŽÅ @ÿü¿ü R‡ÿÿÿ䉕àt½wiÒ«UGQl�wE²‰ì¬#GðPà‘ƒ°ºâNÜ#›±Î_ùSÌžž‘œ¬?Wý¢�“c‚ÃNB¥%©ëÎn_XèƒaåÑ0²Áej±ÿûRÄèƒ 5µ`‡¶à!¸I¶ÇïÿÿÿÿiòÌ—31˜[šÏ-¾y?ï œ””󤊮nK6‘â–ªÔÕ{±†yÕN~;sùU/µ¾ö¼½Í¯Š¸»k¡œÐMl0>Pø`ùÑP 8XLÆT,aLq€ÿÿÿþ¥Yÿÿu­>yñ²ïr‡•vá†Ïù¸JK×u|â•1ÚEf®´0’ rl즽þÕ¥éö6\on-dfY”š·®ßi ÕìÑ*¢'m9Å!D##à98ùÿûRÄèƒ e³ �-ÉA¶¡ &øÿÿÿ¯ÿÿÿÞü�"1µ“Y˜2 ÊiR+E½‹'Ç  NàÍOJä(aØ™dÚ%‡y©µþû3;%fr®g,«ŸXP˜¹üKÔ1¬´¼Õ�îS&!§“I…ó—–—ª°Ðÿÿÿüçÿÿÿb]ˆÍaI¤ÝÑÂàšW„=Ë»¨K=\ˆi“ÅñlÁIus?W;ŸñÉeûåß8g—UYñCcÂIêË®)M–VX`‰L3b3EØ„$TVÿûRÄìƒLeµ@�žÁw¶ ¦¨Œ<Â/ÿÿÿÿÿÿþwËMr:jdZ‘—uƒÊ@œÍåW‚ÉÉWŠ�ÉG’=A ‚Á.�yXžÎ<²,·ÎçîWQ`®f[:º+gdr´�’—2vÕ02+#`˜PH"(ø•ÐÿîM©4D6±Ï‹2•ÕJùݲn¬0^ŒgZ"‘ClV�¤±ÔªÒîEy~Ÿóï±¾²ü ‰ú…Èa5TŠ…W¦djj¨a#ÉÉTDL@Ðl”\Ò¶Ä€ÿÿÿëðÿÿûRÄêKq³@�= ‚¶ ³Ùó‘v¾Y™©¶q‰'þj»%#»+Ñž„l2ƒŘ$hœ^´ Ñ‘PIÄå/é^S4à?Ì›Ë3ѱ1WO\+uîŒý”† —¤:�!H¸€N /Š„sµ?@ù>ÿÿÿÿÿÿŸ;Ô)*_�ª¹jdJŒå$Ç™Ya´ LŒê ʃˆ „Ï8Ù«c¾ï¹ç}» Q©ûÝðm™¡Q†çXËïTQÙØ7(ÏB¢£Ääm�2• ÿùKÿÿÿûRÄéƒ ™±@�= q6 H¦ùúÿÿÿçlA¯û÷l|õ¿Têmš(þ™ýˆê-r ðm±Ôe¶ïȧ9Y™å¦â›þþcwßo¬÷OÏ̆awV­“¨)“dK‹ž°àðÆå“&Θxÿÿÿù”޲ÿÿëáÚ¾Ë �œ�ú]¹²ñ¾ê­\)„›�q„]»LBåÂU—RÐó†eNÞ~þ~W™Ïßž¾R»±;'––ZÆ×À\µx©,�·ÙKÂßM·ŽÿÿûRÄë }µ@ ;A”6à³Øÿÿþ¦/—ÿÿǘ�9sIBé¡ EËu;#XŠÊV¢�‚…¹Î—D8�TuGtF[Š‘.Ôïò+»0–õÍêl²ÑÇQêAŽj$¦?~ê•(@MNV'ž -Œ–©6pÿÿÿïúúÿÿ‘œ™P\Т/?ôéB%¯ZÖ*Jt¢a.fæýÁšÖÔ’p‰µ-sÿ.ßÿý9¿ô¿î?K=�¶ÓK^gϬÁ•Ö3‹ :--€Üý:ö„› Û`@ÿûRÄìƒ %µ` 7Á’6 3ØÑ Ë×ÿúµ6Úò²ä4�"ª(‡)�芢êCÕ°¹$3ÝXî-,t9XÆ»4çeSUÿú©Õf¨š?Y“jM¸ñ ðß%\ȸm ‰`dºND ˆÈVÅꀽWÿÿõÝï5’©î›k3·SH ~œëÍX);“ZÔŸQ‘ˆ{ù­- JIxeÞçù·Wýüùó+Ö{¿°òõLäo&�³I1ŠŸÔÄI¢ÈìD`5ÃÀh6 �•A1@�•²ÿûRÄëƒK™µÀ��…6 H³ØÊ$D�ëª~Çÿÿ‹<÷cb4Ås\\ÏB·ÐérZå^ï™n†åMÄÚS¼™Rg̺ìÏÎßzÿü÷×z¬uW¾ØÂ¥µJB‰VsŠÁjá`j¥ ¡‰ÈFŠœ½.ábD °òà0»/ÿõ)�_ Í ¼hÞecöÔ»éäcE3³ÔÑdÙïhÃ(·h÷ÚÎòƒî>¯ÿù‰^?ÿÿ¿ûþ»ˆíüuEŒe�Æ ©ÔQ …””Â:   ÐáÿûRÄêƒ yµÀ�žÁj6`Œ&ùÿÿþ_š@;v¿ÿ©­D üC0ðu"�,g¼C„¦ #6†þœ|¯“Å5„ùnÍÒ7�ˆ�¹ÏΟÞgržnßù¼´4ö7õÛ]å¬+Þ‚æaCÔÈO]:HOˆX×0>heÕ,�­úìÝÕ(½Tšn‰5ªâ4uƒ½é–ýŸ¾Z<�˜öÕë³ûã°gZ£¤ãñsŸ¹.îMózffvŸó�ütïbí³[Õ6TzäjY:ÿ Dâ*qÕ8†ÿûRÄí =µ@ 5Ak6a(¢at$;^‚Z,–HÚº­ �ÿÿÿ÷H(©¸Dzœ†3EЮe§3¦;&QÂä9ou%Ån C”‚d=+_ÿÿþÝèT»X™%8á< bHÃG‹ ‚01C‚ Qÿÿþ�53{ÿú¢°ÚsÉ–¥~ß|…™AÑ4Í�˱Sá:Ì#rm%di?2³Èïô½´ü¿çc_ût×™¶Ne [|óLL,�%é8&Y7™lõ:1¹£±ìÿûRÄì‚ ±µ @A}¶ ¨³ ‚?ÿÿþͨVÝÁ¿ÿøŸln4 �‘ò8õTÅû,EY¯ «ÉN57C“5TlÉ‚n{ Ó€¬¥=guÿŸéÈêYò¼eP–•‚~ÙU (i–q &®pH@)H„�©ŠpBÿÿÿý×%—7ÿµü)ýM>©-;c®k9r/©Ä…ä‡ áb]C‚†AˆÉëŠ$0äLYpÛõÿÿœ§oª½dV’{8ªtú‘Q 1#moHt´YerRDL(ÿûRÄì ‘±À “�=¶¡Œ–  ÅÓ˜]ÿ° 4zb£ÈfËþ|¤0 ¥  ˆ‚ªC•¤>ÁH›IV¾{¦×°å2l“)M1 R3ÿÿÿT·e£±ŽèŠŠ ÊU,1ÑŽ–$Á� Õ`Ò µ¬Õ\u"˜ÿô¿™æ¡…?«m8ëT),ùK_û¾^UQó3õ­H†©ò”>‰ò2%~#¯�øùþ~:ŽÛt(s8×¢¤¨†« ñ2F �ݱ`ôÐwk�¹ÆÉ(ˆ€ÿûRÄìKõ³@��w6`Œ§iÿÿþi3�m EMÿÿ¼È_nLDWcIÅ3“Ú ¨G!)\ÊyûE:ŽÇpÖÃ&CmMZÙ7‡¤ÿ–þ|º™ÿ¨ Èì&ÚÙžL™‰*(¡"bLÕ$"�]!*©•Qÿÿÿ S¬eÿùFg/’³4&g§õÑ Ì蔿J1¬ TÃ1ëK;„nå\Äšc(0£N´,òÛsüçsŸ)%�“‰ S*DsŸü‡óüóu�ûb¤ÅF䉜¤àüÆ\Â(ćVZa”BŠ ,`v�²JŠ• ´@�Ò·ÿîÙgs{ÿù•©<Æ&Nr=îyÎÆ¾¼vì8¿™æ’ö«XÛ;G们ªçÿÓ·íëÊ®£QJìŠÊ ÎìcÄ1ÅPˆ&4ÿûRÄïƒ }±@ ‰}¶ Œ§i85a«d?ÿÿòm?À2ÓZŸýÊfyÝÃá•QŸÏ)%[+lg®V£#‘¡^¬à��*�ݺ©�×êìÞ÷ûÛ¿/!rÈT®}÷'.�¢U惒¦Òç¢mÀ›Q\V`}f€QÿÿþN×�Lù¿ÿºñ–¤^CžêÞÎwÓ `ÖVq%Kà yÝ¢C=Zó$Ô‹:Êt¢Òòú^\ÙçŪ*鋃 É,m' œ2F �¤š¤ÿûRÄë‚ u³@�>É‚¶ ¨§hL›À�R)\ÚúášÿÿýSÙÎÇ&‹7ÿMœ"ŒÞ‡–kŠ: ”a!Á%-ÐÿûRÄé‚ I¯ ¡ ;IX6a´�è› ÿÿÿ±ÌÅp†@£¡,Ìßÿœ%èw*LS³3ÁËìÝ209TÄžs)ʦEtº¹T΋S©èVf{nÏFûÿÿÿµ:ŽÞBÛ¶'¨bZÔ(–HË €™í“Ì”¨ ‹j¾u[kiþî—ÿŽŒ£e aö¿ùezà’<Zõ2UÎE3-P¢p¢²;™�Ó1•Tò¡*­IÊÃv:5ÕÕ¦–WbÿÿÿÿKF½mK^áÆØ#.•ÿÿýÿûRÄëJñ±¡ UÑ?µâtŠ»�<Èæ(²äb+‘=í5˜‰—Ù¡jÿý�jB5Œ�t{·ˆ�J¼b"ìðÒÅ $/7“Û­Ê_ÿ‘fÜëæìË��‰•›{¾{9ï|Ú8>0 ë `…eKkI?‹²žrØÃ³çmŒ«Üó±)’Ò2þÎÔÆ<¥ØÏ•s9‰º!YÔyÌbM™† **:Ì×mÑU[ÿÿÿÿÝ™¨ö»:µdaö•�C (¹Š9»î ?ÿÕÿûRÄõNµà™�ƒ¶ ô!&ø£':¸—8µc…3¶ôéïsAЫõª'ßû¯4÷{2ÓKcÕ>È…X™‹eÄ43B3Ýn…ùŸ—åÿoJ§¹Sœ™Œc$‰4šFÌWU®¡"M3¥Ãž*j(Cp ¢rÝ« ÿÿØd<ͱ¦ŒD8L».ÿ Y“€¬=�{¹?]T.sž]…u¦m©9Ú�ÊÝ *»æ°›ß_ü¿ïçñõ^_Ýõ:­Vá[4®a÷’» Ð/*B„Ô ÿûRÄê m§  ­Ù”¶ ´!³¡£ËcD�œ§Çó�‘”¡Ð@ß*´¿â²ŸKÿ4#õp”[¡kUI„G$7)¡gÖÚ$ÍlÖˡγ?ÿÿûw§g»3vA„©Âܪ@3¡�îF$Êrï³@ÿÿÙ²ODd9ƒJ7"5Ïü¥þטWBMsé[Ae[íCPÐ� )ÓËË´ÏrSR6*O3z›1ùÄËŽ^ÇYÿÿó¿;Ÿg<„÷!MÕ]Ïfžá¦QCêi$zR²Ó`ÿûRÄë‚ é³  ±Ñ“6 ¨!§ÙJá€6µ�ÿÿÿ½Њ1�~„¦ÿù&GIÐäæZ Î+×·ÒzZ®U$·s…)iw*•·78YäQÖ‘U«ñ!žóÿþþrGÜsn[Ò„çßä‚^eÚiœÌU‚¯É�Ð.K*߬Eÿúô*å“3Yħÿì’"§íöš)œ³ÈŒó¶  ªAj¥hÜP £ ê�*9`¢ jÿŸŸçÿò¿ý·{³ç­2eÎ@ÎÇNh¢ÿûRÄë‚ ± �>ÉN6aèŠz´†Õ³‚‰‘$ ·mcŒttäÕ3ÞÞ^ó?¿þw§G/>}Š«ŸÃ6õÚWMH(€ˆçB1#ª‹F‰Æ#ÖÎŽ£¢À6ÿû?L‚V@˜‚ïóH€ä¾nˆR…•2»d‹·g�š÷‹[z¾àšÝˆ=Æ)ú,Ľ>el×î�‹h›ê©š¯Ÿùë¾úÿþ8žõi¿AšI̳¹Æ F<É$ñ �p†â„(¿r4IÿþÿûRÄï -¯¡ 7Ƀ¶`ô!§h( L ”�ã·t?ÓþûèºV¶áÈs5B¶U)8�&°õH?pÄ  ÚÛ«Â uÒ/5amë>åùÿÿÿÿþß;3¶únôY#šKC²þ-R�z¥ºÌÀ±i½¾HÑ$ e¹îÖ8fBÞ-vtïÿyÑfœ…Dµ³… óë=B“ÐszI›ba’ª\‰T’“]–_??ïÿÿÿ·÷;™{~uÚ²cÓIUP%€ŒC+‡0ç8W-Œ€ÿÿÊ-ÿûRÄç‚ ]± ¡ Ý ¡ã´�Ò{™ Ó¤rìF‡,ÈÒÏ'=A¼C—'émåP™ ª›ÊÃ[T¶³Û�‡&”�cÛòn•5-~Égù_ÿ‡3úiZ¼­÷ŒbŠàÖ4ÉÅ g¬tÉH,Œ2†¦!ipM4 ‘ 4ÌŒÀ×—ÿäÖË™ÉHÈÕ–¡‘“Y�ZËPÉ•”'#Y&²Ë!”¹¬œ²öJGü¿ÿö‘¬¿#“,²Ô5k,ŽF³Ï²æ_ù�Ë–( NŽF¡�¬˜‚šŠf\ÿûRÄñ Y³  Á‡¶!hšúrnªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªLAME3.97ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄì‚ õ± @oÙ�¶`h¦øªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªÿûRÄìƒË]°Ú €t4€ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªbeetbox-beets-00724b7/test/rsrc/coverart.ogg0000664000175000017500000002107515253035401020333 0ustar pieterpieterOggSþ–ç=݃[vorbisD¬€»€»€»¸OggSþ–ç=Âjy&ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿ2vorbisXiph.Org libVorbis I 20050304ÙCOVERART=iVBORw0KGgoAAAANSUhEUgAAAAIAAAADCAIAAAA2iEnWAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKDgwQSgEWmQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAVSURBVAjXY/z//z8DAwMTAwMDggIAORsDA9GFfycAAAAASUVORK5CYII=vorbisBCVcT)F™RÒJ‰s”1F™b’J‰¥„BH�sS©9לk¬¹µ „SP)™RŽRic�)™RKI%t:'�c[IÁÖ˜k‹A¶„ šRL)Ä”RŠBSŒ)Å”RJB%t:æSŽJ(A¸œs«µ––c‹©t’Jç$dLBH)…’J¥SNBH5–ÖR)sRRjAè „B¶ „ ‚Ð�UÀ@² PСЄ†¬2 (Žâ(Ž#9’cI² ÀpI‘ɱ$KÒ,KÓDQU}Õ6UUöu]×u]×u 4d@H§™¥  d Y F(ÂBCVb(9ˆ&´æ|sŽƒf9h*Åætp"ÕæIn*ææœsÎ9'›sÆ8çœsŠrf1h&´æœsƒf)h&´æœsžÄæAkª´æœsÆ9§ƒqFçœsš´æAj6Öæœs´¦9j.Åæœs"åæIm.ÕæœsÎ9çœsÎ9çœsª§spN8çœs¢öæZnBçœs>§{sB8çœsÎ9çœsÎ9çœs‚Ð�UA6†q§ HŸ£�EˆiȤÝ£Ã$h r ©G££‘Rê ”TÆI)� 4d!„RH!…RH!…Rˆ!†bÈ)§œ‚ *©¤¢Š2Ê,³Ì2Ë,³Ì2ë°³Î:ì0ÄC ­´KMµÕXc­¹çœkÒZi­µÖJ)¥”RJ) Y€d�AF!…Rˆ!¦œrÊ)¨ BCV€<ÉsDGtDGtDGtDGtDÇsUõ}Sv…áteß×…ßYn]8–Ñu}a•máXeY9~áX–Ý÷•et]_XmÙVY†_ø�åö}ãxu]nÝç̺ï Çï¤ûÊÓÕmc™}ÝYf_wŽá:¿ð㩪¯›®+ §, ¿íëÆ³û¾²Œ®ëûª, ¿*Û±ë¾óü¾°,£ìúÂj˰ڶ1ܾn,¿pËkëÊ1ë¾Q¶u|_x Ãótu]yf]ÇöutãG8~Ê€€Ê@¡!+€8�$‰¢dY¢(Y–(Š¦èº¢hº®¤i¦©ižiZšgš¦iª²)š®,išiZžfšš§™¦hš®kš¦¬Š¦)˦jʲiš²ìº²m»®lÛ¢iʲiš²lš¦,»²«Û®ì꺤Y¦©yžijžgš¦jʲiš®«yžjzžhªž(ªªjªª­ªª,[žgššè©¦'Šªjª¦­šª*˦ªÚ²iª¶lªªm»ªìú²mëºiª²mª¦-›ªjÛ®ìê²,Ûº/išijžgššç™¦iš²lšª+[ž§šž(ªªæ‰¦jªª,›¦ªÊ–癪'Šªê‰žkšª*˦jÚªiš¶lªª-›¦*Ë®mû¾ëʲnªªl›ªjë¦jʲl˾ïʪ)˦ªÚ²iª²-Û²ï˲¬û¢iʲiª²mªª.˲m³lûºhš²mª¦-›ª*Û²-ûº,ÛºïÊ®o«ª¬ë²-ûºîú®pëº0¼²lûª¬úº+Ûºoë2Ûö}DÓ”eS5mÛTUYveÙöeÛö}Ñ4m[UU[6MÕ¶eYö}Y¶ma4MÙ6UUÖMÕ´mY–ma¶eáveÙ·e[öuוu_×}ã×eÝæº²í˲­ûª«ú¶îûÂpë®ð p0¡ ²ˆŒaŒ1�RÎ9¡QÊ9ç dÎA!•Ì9!”’9¡””2ç ”’R¡””Z !””Rk8Ø )±8@¡!+€TƒãX–癢jÚ²cIž'Šª©ª¶íH–牢iªªm[ž'Ц©ª®ëëšç‰¢iªªëêºhš¦©ª®ëºº.š¢©ªªëº²®›¦ªª®+»²ì릪ªªëÊ®,ûªº®+˲më°ª®ëʲlÛ¶oܺ®ë¾ïû‘­ëº.üÂ1 Gà @6¬ŽpR4XhÈJ €0!ƒB!„�RJ!¥”0à`B(4dE'C)¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RH)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ©¤”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)•RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”R �Šp�z0¡ ²HŒQJ)Æœƒ1æcÐI()bÌ9Æ”’Rå„Ri-·Ê9!¤ÔRm™sRZ‹1æ3礤[Í9‡RR‹±æškVk®5çZZ«5לs͹´k®9לsË1לsÎ9çsÎ9çœsÎà48€ذ:ÂIÑX`¡!+€T¥sÎ9èRŒ9ç„"…sÎ9!TŒ9çtB¨sÌ9!„�9ç„B!s:è „B„B¡”ÎA!„J(!„B!„:!„B!„B!„RJ!„B ¡”P`�@€ «#œ�²€– R΄AŽA� AÊQ3 BL9Ñ™bNj3S�9�tjAÙ^2 € À (øBˆ1AˆÌ …U°À  æÀD„D�˜ H»¸€.\ÐÅ]BB‚X@ 88á†'Þð„œ STê àà ""š«°¸ÀÈÐØàèðø8>€ˆˆæ*,.02468:<€€€@€€OggS@–þ–ç=ý‚å'02310276;:?CCBl…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹¬Ø%ô B8FkF#ëœzÊýýžåJI`Ÿ76BU5À: š†îK.Þ[/IÀ´˜˜€Ž€ ~ÊýýžåJ¼çÛJÙ@!TÕ€ €z wPˆ{@Û‚š_,ß5ðè@ 4>ªýÿüå žík¥°@!TUè40ÑMtô™àÉÆ+ÚÙÁ…WÇуàÐ>ªýÿüšäâvy¨…PU¡ô…|G×�OӱЂ††�ÊpBÀ&€>ªýÿüšäîô4ª…PU'Ð@$¸O}�Ç%åMÒ;†:€ žä>ªýÿüšäÒ´ð&”ªÊ* @t𨴯ùçaï¥)t (4 ƒ˜šýÿOre1éM0BU 1>ÞY(¥ÚsYÀ&-RJgè¡ÕMkòØÀ‚VšýÿOr¥2ØåIØUUÅ@EO5š‚nE~IôÆÓ´JÊqØ)d¢U)°$ @šýÿOr¥28åMèªÊj ÌY�¬"æeç…d×Ôdþ‘òcw¢ ±“¦‘€d :šýÿOr¥`°Û›¸TU:Ì]¹¤¿\Ïô³\ÏÒ{QFH4¬T05Þyýök”‹2¸ÛÛXaE…P + &EÒæ^ ô#©”¶&Ú!ir}Ï””Ωaku¨“)lY �‚&˜ HÞyýök”‹2˜íMP*jT¦Þ1{Ã�1^_Y•¢~vçt×ZŸ}¹.ó­¡£ª9“5\1á)èàÁ_#ÞyýÿþåR Ny“B1ê,˜r(¶Øò³4ptmp sR›¦£L/g9‚èÞ?®Í0—M)°”,ZýÎu¹ƒ‘Þ8 4´X‰ h©u À÷ßÒ‹ö~>S£Èü†ý$=cr¦Èß7²ü¼öŽ¥ÏÃŒóù0ƒÊ«®b¥*¯ß·þQ�ÿŠá¨Y4®#öO¤Å± Š«=¡ P{údX]ÎÔýÎ59 £¼ „f)6ðÖ”³A`fœ“€½^�Ä!ƒ<©¬˜i0/d¥·?/Ôh³=é«m¤ò¶Þ­™ž��wÛÕZ:Ý–ÿ‰�^®¦×Ö‘&uVwû’CÅ_Åjð-˜mŒýÎu9 %½ Ð"++IÀ@âÊAGÕ�rý5]óo”X€¯/sãÎ�\ú çHÇ‘ÙqoÅóÈÐ3ú.+¼ð¬qÖ\E�¬SF’¿1R-à"ç ÜI¦ÏlÂjÂɘÌìæˆýÎwÙ4-= Ĥ¼ÌdÀ¢ÐIà,1æ8‘qü]âj­_è÷⥧Թéô''ïsçõu|‰ìwûæ¹ÅÇë�³Îå‹�/ó¡<:�0ÑÛå$¡Í½'—3Œˆí®�ý ýÎu9q­< B¡¡ËÂÉg�Pà€~57kg§P¿d´]�ÙÛü¹œÎo¿’_Ú¹Js)êã5÷Òä¤Åp–ô•õÚc\^;Ç¥QåtFôbˆ[D®áì §­“ýÎ5¹ƒVÞh’ʦ¡°@vv¿´ÄN˜¾d ¦²²Ki*¯u67[˜`&· 'nV‡§¯‹“ËÈcºt“Ÿq’C>-VþFŸÄ¼VÙ ]êïtGNÊy49ªéaœÙMãýÎ5¹ƒä�¡Xd‰‘\%`8�'\àÁÁû5ô�7‰M?/'x‘,ׯ×}Y¿Ž½nmcfFU)¸¸ð“‡0ÙëÞ¾ÕÑøÚ��·•êP[©+T²ûë¼ý2š\ÍüÓSœ ÂG.W¹èX©;·åUFÀhkôo†FØ/÷àÂu cÊ:ýÎ7Ùƒ–Þ8€˜š• ›0Ød7•\´×vÎ}ií½E«MÝ M3‹Š"äðºÏ~µ½b³¶#Ah©'òR‚ÑÖ&y,]~�MG“-9¶#8…þùäë¼�#s/yýÎ7Ù8ƒQ¾1ˆ•Ö%ˆ8€iup;š¤_I5…ÀÖÿ?»ØÄ&òÒµädu¡n±{½ï…é!‰Ÿ»:•¬Ï…úzÅU.25žBÉ–+Êèq0ïîQ®*/CUë&^ܱé-ýÎ59q#} „&å68ZÀ€ôлt3ü´WÜ™ohm™äP»-¨Y?Ç{ž°êŽLXø8&MöØ f%ªO©›÷NÉ”‰Íͯ®b¢ì½›ìÎÈPw¡ëWI;–ýÎwÙ(ƒ–ž„*hRdÁPL�Kºá?7œ�I—»B��Á¦Ñ|_O&±arúäºvQà$¹k×°d­Áå²l­Lc/["°R#lcú,èVÀÝ�Š…«äàHïbz¬Û{8˜TýÎ7Ù8ƒQÞ1ˆÉJQ3=HÐi—� ‚©æÊì•ä¸óM6¿ÝRmöµ|fê «ö’ôÑZ*Ìü(NbÎÑÙ&ç²ýÎu¹ƒ–ž@-jIÁ…&&èh‹o\ˆœ‰[¢ÆüJx2ÝÏÚ ^Cí7^:«YGcF¦òO}žÝºž‡ƒž�™‰°±<É~¾¬2Pâü"SÔÞ‰íõªÀö™!Gæ&ÛóS’‰�ÎI…¨ýÎu¹8ƒQÞ(BÌR¬H¦Ð‡YB,ƒ’²-oÅx3CT§XÈèòßÑ| éÈÓùÆûѳ^^ª„^‰)5=‚%G½pïb€{fy](€>(Ö÷:;ubjÙ:kGG:OggSD¬þ–ç=‡¿²¬‹‹‹‹‹‹ýÎ59 %½ ‚”. :>�þè]µ¤?÷TãÌxL€çsÔ˜žM›PÏXšÁ„—+q!^#§ÃaâèÑ|S«ã.�„™ãµ•«Q®%(Îsnå¶©lõ]”N-{~ýÎwÙ8ƒ™ž0B“b…qÄñ–X9vñ)l}¬Å¼�b‘Id=!û…t,W¢7Åæÿ9±¸õñ­Ûÿâ® Rñˆçƒfƒ©ÄÀoé<ïËÓ—·§¾UÚe±”׫üpõ0Úé[(wÉÎ"…ýÎu¹8ƒ–Þ„2h–¢"hrðÈ)=|éP›Û"ýr:Iò"q�ö°Ì˜è¹¨š¯à޾Rß"à€"«•uÞ½‰ þ¹Ú‡¿š.øAsñ©Ïˆnµïn7…£'òèeŽ~ ýÎu¹ƒÞ0B Í c@2 °8èä>h»ï_6ƒzyu—YÆü|$Ô•»¹Žëö¬ÊÀÅ…÷ñSìÙ n'E²0!¸¶²ö>~v3üayè™zŸ›9óMÔk ¦1×5„éW7ñ#ÞežÈiýÎwÙ8ƒ‘ž1h–bÞFh‚¦zmœòp4<¯å²é*é´ ´ÚäœÉ"N¨„ªñ|oâSðjl’ÌôøœxŽMqIß–Š'S´Î—WøKw®²:&U0TÌn;�‘bbž ÆPÈeýί² 8P‹<Üà0P8�Ó¹­j xz}]�Übeetbox-beets-00724b7/test/rsrc/unicode’d.mp30000664000175000017500000022304115253035401021213 0ustar pieterpieterID3xATIT2fullTPE1 the artistTRCK2/3TALB the albumTPOS4/5TDRC2001TCON the genreTBPM6TCMP1TDOR0000TIPL arrangerTPUB the labelTCOMthe composerTIT1the groupingTENCiTunes v7.6.2COMMengiTunPGAP0USLTengthe lyricsTXXXLABELthe labelCOMMengthe commentsTPE2the album artistTXXXR128_ALBUM_GAIN0TXXXR128_TRACK_GAIN0TXXXREPLAYGAIN_TRACK_GAIN0.00 dBTXXX REPLAYGAIN_TRACK_PEAK0.000244TXXX;MusicBrainz Album Id9e873859-8aa4-4790-b985-5a953e8ef628UFID;http://musicbrainz.org8b882575-08a5-4452-a7a7-cbb8a1531f9eTXXX<MusicBrainz Artist Id7cf0ea9d-86b9-4dad-ba9e-2355a64899eaCOMMhengiTunNORM 000003E8 000003E8 000009C4 000009C4 00000000 00000000 00000007 00000007 00000000 00000000COMMengiTunSMPB 00000000 00000210 00000A2C 000000000000AC44 00000000 000021AC 00000000 00000000 00000000 00000000 00000000 00000000TXXXh<MusicBrainz Album Type['[', "'", '[', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '[', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '[', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '[', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '[', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ']']ÿû`À F=íÉ‘A#ô‰¹ÿÿÿÿF0ÃßÿC ÿ_ùïÿÿÿÿóÏ£)çÚa”2ùŠz<‚žyõ=xù=O `ÐÊÇ�  ¥à�Æyé>`øÜá ÐÀXè" z)ãBœ"À$)‚ �A„ ÿÿÿÿÿøÿ×?ÿûÿÿÿÿþ¾Ývb£×B�¬¦ ³4Àã°²+¸µÂ¤Ír¹Á�ÔR°Ä%;�îR£Q[ÿÿÿïÖÜîÿ³¾Ú7UW6dTUT!ub8´Çø çèx?ñ.Ì€ˆˆˆˆ�ÿÚÚ¢³<ŒaeŸDY/ÿÿÿ½ÿPœ¼·$D¬(躡ïPŒi§ÿû`À€Š9à… éâH#4•¸‹RÒAbÉuÏ&Ž ü:=ÄÝL´2!Ô¶#9îŽÔ#"5¿ÿÿÿú­ÿfE$ìȉ,ª1HËez²1’ª!ĨR ˜‰Ì§)¢((â¢,Êc°š)ÄÜX¢¬,qE„T9N@øˆtÿÿÒþ÷ÿ?ÿû`À ò= mÁ¸È#t�¸¿ÿÿóËäܯðÉ÷IN¡æiÞÿ{ÞžYg§S—ÜëdE/'ÿÿÿÿÿÿÿçþ§Ì¸g Wëï&%ÍirÄDuñ6.ÝítÜ‘mtP&ê,Ž�«¢’Duhâb¨D›ÀN±ÿÿÿÿÿý`Zÿý{ÿÿÿÿÿçÌímÞó¥/Þj¾GH„<&ñÎC¥ÿü„žl÷ÿÿÿÿÿÿÿýþÿçJÎÉP��1•¥I’òÔä»ò9£3³ZHFÊ;ŽÔr/viƒÃ�1  Ü‰…£2‡ ìÁ�ÿÿÿÿÿÖõÿþyÿ?ÿÿùz\¨Û+dDΪ�1ˆÆckTIw˜ÿûbÀ æ% „MɬH#t‰¸™¨…¶R²¶Í´öÿÿÿÿdÝꓳÐ÷1êr© ÊϳîÒ»³lÖ• lΆmC‘Uê÷c,ì$(tÈ4BKÿÿÿÿÿëåý²ëZSÿÿÿÿü¹QRÅ­ÝŒ‡>³Ìl®®è§1Œ¨ˆËf:V¨m&¾åDGB;?ÿÿÿÿÿù­RÌé+ƒ9‡}•+ϳ+±ÍUÐèÊbPSú;1Œ%Ü; Š…R•Ìwt”€Î9Bÿÿÿÿþ¶ƒÿëÿ•ÿÿÿÿäìúRwó5�lª„s>ʸõ#ÌäºuFlëÐêɕћÿÿÿÚÿ³«ÔªFJȪyŒEus–ÿû`À" ? „­Á¬Æ#t•¹a2ft*3άVwVl̸â•êc�@@Ç‚o2ÇåQÇ;> ¢£€?ÿÿõ�sÿÿÿÿÿü»µ®å:=¨îïv:ºº•VB/Îlêèö-ÊZ$Û™5OÿÿÿþÍ'*MD£�'» È.–z¹›S«”ÌêW!„Ça溡Z!3#NǞ#!ƒ¢âcH5VA¸ò¨`†`±�óõùþ¿ÿÿÿÿ®•g;RWT�ÙUÕ½ÔÝQeÑÑTľÎB%OÿÿÿõùÑgêÕ9F F‘�T‡j9"Î(cJb#!Ç�xˆÕ3³ ªEÿû`À, Ú= „­É¯È#4‰¸vcœqL8áaàÊPq¢�Ñ2$48ÿÿÿÿþÖ¯uÿºÿÿÿÿÿ?£‘Ý”„5›Rl›ogGÐŒªöi7ºÕŽ·ìKwÿÿÿÿÿÚÒ"1Ý_™Ü§8¤T„Dg�ä;YƒœFä%PìÆ \ÈäRŠF €‚äS3: ÁÈQBªà•Ü(ÿÿÿÿþÍ�—ÿ/ü¡ßŸõÿÿÿo‘œíbnYØz(‰‘ëu×J:ä·Id£ïZÐÔÙÿÿÿÿÿþŸJ'»Jƒ Ff®ï©Ne+ È 8ä*&*†q2 0�Ì AŠAD…0’�Q!2ª”¥A§aQEÿû`À6€ ¶A „­Á¬E£t�¹0ÿÿÿý°/ó׿ü¿ÿÿÿÿò]s¹œÐô… 仪Dþ9FzÓ¦[7‘t¥+M¹2ä³ÿÿÿÿÿÿÿéÿ9æÓ*FE‘D‰»ë2³×r™9“Ò·I­|¼UèÊã±Áz°spÂ+† JÛØ8ÿÿÿÿþ��©ü¼ògRfÒÏåÿÿýþ•$íc1üý§º!Yz:d÷#ê×*º%Pú?{¯ÿÿÿÿÿèɦ·5\ÎR£¾ì‚ŠTv{˜Ä$A™ RkÑi†ˆ!£±ÅÊ�Ö(|¨rˆ˜pðé¢î<ÂÁÀ+)�h0À5�"ü¿ÿÿÿÿÿdîÿûbÀBVA „­ÁÄÇ£4•¹�F±:¼Û>yê­)Ý�ì¬åºQò²+7cfTÿÿÿëÙ[óÉW£•hr¿ÿÿÿÿ�iO‰�&�׊aÒ¶§ö’ѺkL“ÔW0÷?ÜpµpÝÿÿÿÿÿÿÿ1ÿ×ýúÚuz÷¤sò8ë›~9�çˆ^;Ž’˜…ìar:¦hZ—Ro|†AwÚÖìXòo®Ü**>@Ö0ÿÿÿÿÿëËWuûJ�FÑYìîåˆòYÙræ\ˆîjí»*"±Hßÿÿÿÿ~î‰m¨—g*:˜…+"ofi•ÞÂ#E� �¨²)JçWACê,$aqÊÇ)„€p1Œ"Pè‘ÅH‡(Ñ¡`8�ÿûbÀo€5 … ɽH"Ì•¸3èòÿ¯ÿÿÿÖ×Ýzè¼ì×»Èr/È¢ Ê®”d£3Ñ—yN¤qÿÿÿ÷ä{"Zåu#ÌeR ¸ñŽÄsî®e-ESi‘�pÕ( ›0“�„bŽ3‡Àãs�†�yNEr”ÓŠˆ¨€� ŒÀÿÿÿÿÿí�yïÿéßÿÿÿýz.¥1,o5ä+9·Ežuvf±Îõ¹v}ÈÈ–NÿÿÿÿDû}l³µ+3UTŠCo¼¥>%èOyS!�XŒ‡‘Æi;�\ê8#)Ń:‰cÅ•Êt(P‘À?ÿÿÿÒÿùÿóÿÿÿÿù´š÷fÿû`Àx 9 ­Ù¤G£t‰¹b$„vºftgdû©kU-™œèƤÆVäfÛÿÿÿÿìŸêR>Ó­ÕK5(i5; Îñ“•ÑŠwiÇ*¹ˆ¤"âŠ*.*1â¦c´x´çRH@“ˆ#•bÀÿÿÿö@¿ÿ-»<ŽÄjµ=]ÖÓTª¤®Æ96Kä<îäsn³¼ó—ÿÿÿýv"Ñõ{Ñ]LëgR�g©ªF5ŽFuõZÇQ3�QÓ ‡Ç°›”a‡¨Ô ˜µÌ.tP‰GQCå<ÊÿÿÿÿÖþ]ÿþ«¯ÿÿÿþÞˆy‘žr3ÚÛg§Ÿ¤m4U++!d“Ö¶_J´Í{ÿû`Àƒ nA „­ÁªG£4¹ÿÿÿÿÿÿÿÿöù7ÈqyiHsC0¤Er_?* –gÐNP�‰îF¸v#UCªˆ9ŽB!* jè�A‡1Y(0ÿÿÿÿý`_óòþ_ÿÿÿÿüßíÑžïzJ_¹K&´išôE3Šeu!&>ˆˆþFÿÿÿÿéÌý<ˆs±Q#•ÞcÚï39’Àœ“Ùœ[%ÜÑÝÄÇ8s¸Îd†; áXä …C0­ƒÿùZõº�Výi ­b¹*ªOf3U§,ÍD=®E%^ÝËÿÿÿÿóHêí³=Uή¯­]�™žØâ®ª9ÕŒfd#9ÿû`À� òA „mÁžÈ#t‰¸Ñ�Ô�¤C»Tˆpø…Å”HƒbÈ s‘� E,*Qÿÿÿÿÿý`9oËêkÿýýÿÿÿÎë"åE§KQîÖÝ�Jî·<†aG TGȪW›F}]iÿÿÿÿêÞªú#f«¢Ì¨ÅUTH̵Eç̪·;f¤€ÜâÀÙÑÕN]Dœr¬¨qNÈaÝ(ÿÿÿþ²ûçþ}~_]ÿÿëïôìÌÇûèw.šQÞrØÌÌäb-lzèÒÒšÿÿÿÿßé­ÝíSUÐæg«DL†îB�ÓœxÝ� ¶QE§™ˆc±îD €Ñ3‡PƒÃ¡ÿûbÀœ 2A €­Á²H#4‰¸$)Ÿ1Qd‚ £ýÿçÿÿÿÿýÖþ—tÍT!˜¦ÈwS5îêëfº�ÐÅ*”�lý؈ŠßÿÿÿÿôºµYÊÊKžÓÊÄB²¢�Ïvj±•QXÌB *”a”£¤q3”Á7 áº¡b±Îƒ!¬k **�6Hÿÿÿÿ¶ü¿¿Ëå_ÿòùß%é,«¿uÜöeæBÊìöJ¹Mwº®í­]Õr«7ÿÿÿû¢Ú®d+Tµ#!•ˆDeœ‡æ)Øì…F•®q`³�QËÊ·K ‡!:ÁÎÂÃ�ur‹C˜®àÿÿÿÿú@¾_âüÿû`À©€ ž; „­ÉÁG#4•¹¯ÿÿÿÿçïÿ%2ó¥xzžõËa©—ÝßÈͶMŸšÃ™);þe­Ûÿÿÿÿÿÿÿÿù~~KrS¬[uvzŸzYq¢ñ òlQ�wÑß#}¨\‰jZ |‹T �¸Ä!ÌéÀÀàÿÿÿÿÿ�Ÿž Øç —Ne9Ÿÿÿç eR!áçÖVê¢õœ}!wÂOí3UUÚZWU>ÑÿÜWÿÿÿÿÿÿÿÿ?íñó÷+kLÖÃùŽ*Øëk‘s*—gJ�4`ž¹EÆÇviF"‡$˜z©†9‚XõÂa�Ë”9pèP·XT]Çÿÿÿÿÿc`qîyÿû`À²€ .A „MÁ­G£t�¹‰#±’¿%¾§ÿþY¸tûîú㙬ꙉy¥˜†ýwŠõÚ©¦÷ÞÒ¥©S»éºæÿÿÿÿÿÿÿþÿ¿ÿû¿Ž¹šk¯«YO›­²<6<’±…&TÉ눢Æ!wB±E2ˆ ¸ö³J‡4\V…K1`°’ކ6Ëq1Š@ÿÿÿÿý±ƒÍ#˜Wå¿Ì«ÿÿÿý:*\Ȫuo™��H(έb+JB{1¨¦î·±•jjÿÿÿþ�7¥®·tT2+9#ÝÖ<–ºœÈ©*­ ayŒQ1§3•Ú&=¥B�:``ë‘‚¢§Š ‰Zpð[JQÿû`ÀÀŠA … ÂÈ"´¡¸ €k?ýþ½ÿÿÿÿÿþÕdR•¨É¿WDJ2oR›±ÎÓêUd©Šf3¦Óo5ŸÿÿÿÿòKk­Ê„y™bêìêt3–S’È5‹Ž «�,† 1 áòŽr�JâŠ0¢„#(@Xêè$,�âŠ�8Š4xD*…„ÿÿÿÿÿ’Ëäû×ÿÿÿÿûνey5v}úº*±K÷U2‘ÖgR™–tK"µoEÿÿÿÿÿéîíLÊŒE:2+Ù’}Hî8†fc ‹³)†ÅÌîìBˆaÇds¸“!…„XPr˜xñÊ,Š($0<*5 †4lüÿû`À³€²A „­ÁÛH"ô•¸Ö|ÿÿÿÿÿÿôM‘Û[VÛ²NI”¬ÚÖçbk3›ß¢ªÕ‘Z~¿ÿÿÿõ¡j‡»µ¶g*•Ø”ssB«¥r”¬QGª‰ ”„)å1˜0‚ädÆw<)]Ì($aE8pj‡ÐhÀ³˜À¢¦‰€ÿÿÿÿþ��ßüÿF—=ÆÚþ¿ÿùå®›±÷õÌk*"§f5§¢*YÕC^bºê§»LÜÕ²ÿÿÿÿÿëî‰wcª¦UÎ<Ê;0Ô=QÖ«žŽ¤�:³ó¿ÿÿÿÏé¹&q…+T©µ'ÙTU•ŒgeR á‡B32)—ýž·D|ïÿÿÿÿÓ]«Mɺ+YŒ[Ö¦0Ò)ÊbŽ¥Ž5EQ„ÄEa!˜\h˜AÂ!ذ ³BÃîg À(ñá‚ÂC &P 8|DV&Qÿÿÿÿÿû`À´€ÂA „­Á×Ç£4•¹ÿéä^¤–ú,‹ÿŸÿÿžÒ÷f»‘×d[Òº½ V¹Lës ws)P§z^¬t252]koÿÿÿï§£÷]»ÍÊS2•gsƙٞDkaœÔ9�Ç#˜Â"%F âƒDL*£¢ (B" ‡XÂŽAìb¼>ÿÿÿÿÿ±…åþY//ÿÿÿüæ©J$î”Y?RºÑôVT}ÞŠrQKjßZmu}vÿÿÿþ«ëzttz%¦TS•1ä#ÌÆ½�j=‘Òª”ªQ!0c ÓH,¢å £ÄÄÊ,¡Ñw‡È 8ç1Ðå†0¸ÐÛ ÃjÐöÿûbÀ¶€A ­ÑÙÈ"ô•¸}s—ÿþ¿ÿÿÄ@÷:XÈ®M*¨Cc¹§r”ü­#çDQz­ªý§µ)ÿÿÿÿýþ–ÑNbç›-LQl„0׳ )�Ük ;˜Â,5ܣŃ‹;"Š 8ЦA¨$ÁÑqÆ�\M…EAB@Áç( *ÿÿÿþ��ÿ-ã4Ñ—pþRÿÿÿ³¢îVlìU·K&öu+<Ï™‡tLììv3¡ŠÔ³I{×ÿÿÿÿúûû•YÑ ¥*«“êçªîR†Ð<Ž=ÇÔLU…aÅqáL (sˆ”ñ¨§D4P€È�‚Ä !˜€8ÿÿÿÿÿû`À·€’A „­ÁñÈ"´•¸ÿìŒ w"šçÏ’–«ÿÿþMÿÇýwóó¯÷Üu]fFÌÕH÷SR‰õô±×K¯×ÿÿÿÿÿÿÿÿÿÏw§qóßLò°»O¥O3r²1GÔ­mÍ»±å;=šSÊ8y£2lÏ#•0ÑÄÃHˆpò �¢¥�% « €ÿÿÿÿÿ²ŸÏ_åËzÿÿÿþþŠŒ÷Z2>ô±• ŒÌ]ªC\�È„VGGuyÕ(Êr¢J´ÿÿÿÿû[BUÝŸaj«ö£[‹Õ™HŠèãLRˆ˜«yŒ‡œ¬C%Üq]Qbì->A!Y�â†`£1\Xâ@`Ò y?ÿû`À·6A „­ÁâÈ"ô¡¸—#ÿÿÿÿÊ­ä&ʪË�ÕèêÊ}V¤1Ö³Fnn¹:û[¯ÿÿÿëmjÌës¡ÒÕF!ŠbŠê®Æ)˜†‹‚*‘LŒcˆ°�j¡¬*‰¢ï0p¥>$av!œXè4DHÁÁ5‡ÅĨU(p@1@ÿÿÿþ­ƒüŒÿ¥ÔËïëÿÿÿ7êˆìµR!Ÿ#£µŠè¨~ܦf5æfb1ÞŽÝS"ÛÿÿÿþßèÍiš£P®vJÖ®d1qèq”2ÚÈ0:Å+‘Tƒ6aÂbEl?2‡DD…‡‡\M"B £¢† ”Ácˆ4\6à ÿû`Àµ€.A „­ÁçÈ"´•¸´ý¹~öÿÿÿþT«Û"£—ÜÇž—ÑsÙÑhê®DÎmYd½îdSnÛÿÿÿÿéí¾­:ª3š§š•c%®5HQU<§!ÅEHcDH@8â(‡E`=‡(¹Ã§qR¸²:$&<(j¹‹ÆŠ¸  ˆhˆØ6­ƒóæ¿ÿÿÿÿ#í%)sMªØí1ærÚì·IUkwG‘rîGtTe÷Ñ—ÿÿÿÿÞÕêÛ++Jζ%ƱÞÈÄÌ<‹;‘XÇ8qˆ‚:‹ Aa6qe- @ÊAA¦`‘Dˆa"ÄÆĘ„@ð™”:?ÿÿÿÿý$ÿû`À·€A „­ÁïÈ"´•¸/þN_¬™ôëÿÿä ÷Gõ>¾J¥Ó:²�—G4¸±Q(„tC\î{+©•®gOÿÿÿÿ쮕½Ôˆ³!O<®ë!¨Žd,ŠæR1>‚%f0°¬@ê>qâ¡ô (¨˜åœ4ÖQ!0ø€ºX‚eQC€ÿÿÿÿÿÒäþgì?ÿÿÿÿÿ-‘œ¦ŽI"*ÌD£™•̧Y§In–jH~­’Vkg»T®Š¬‹ÿÿÿÿ•úÑÌŽäRËÕ®¬–K¦í[ÝF"Ψpá®ås ƒ”<îƒáC‡A r$ò 0ˆ×R‹ŽÌWˆ€ÿÿÿÿÛÿÿûbÀµ^A ­ÁéÇâô•¸½ÿÿß›ÿÿü¿->ùŞó/ß&@ºÒzšºË)¢Ô-^Ÿð¼Ž½Ïmûÿÿÿÿÿÿÿÿå‘ßæe ·îV›E‚˜6��Þõ$4C¹»¼­dPÀŽŠ$B¬ŽAÅ£E "£,†8SW©9 € €`5‘çÿËækúëÿÿòÿZšçTC£ú^5Ýõ‘œ¨bT©‘Üz-®–™=¤½ŸÿÿÿýiCž”èËB)©au”‚o,ÑÈ8‡c‡ ""@”AÐD¥*<:*‡ °x:@ùDEEH8:.Œ…Ї†ÿÿÿÿ¶ü¿ùëïÿÿÿÿ©ÿÿ–ŽÍ­îGH¢’°»NÞ±™ÄW%²zÕóØøDo“eÞÿÿÿÿÿÿÿþ_ü?)¹leyX†¿ç)ΜzR̈Ÿ"]Ë•L´'dxÈÐtS 3j±Û é àÿÿÿÿÿÀ~˜dsÿû`À½€>A … ÂH"´•¸æ½ ÿ#ÿÿÿ˲µÐÕc0‰&V‰ZâBÅrÌdpëFEyFˆm ¥*³¬Î¾ë×ÿÿÿÿÿ¿¿mYÊŠVÊÆ}LêÆ+>j=‚¨,å-*UcÅB²=� QSÎPèÑÎ"ÊY˜H  ÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿ¯ÿý~Æ(`JEª*!ÙÙÊbª”Vs ` �#³±Š©ÿ³”ÁB(ÿû`À³€ n? „mÁÑF¢ô•¹ÿûbÀ»€&@ÞMÀ[Àÿû`Àÿ€ÞÀbeetbox-beets-00724b7/test/rsrc/unparseable.ape0000664000175000017500000003220415253035401020774 0ustar pieterpieterMAC –4Ü3Ù0' 0éoÅ|ÍþqôèîˆD¬D¬P('¸è+6¹D€»…›gz¿ãÿnè±`Èé¯CÔC-]áXUÚ½ÛΈý–̹€ËRôa‹% –ýÒñ0ó©'lOéØ[&ï(ïïHõ)œ"i%6aMJO1FÅ@…D8Ùqlpù¤ŒE ]“¹$ê åýwëvy0äÏ\þv7®Œ±I˜®Æ ̇m7¥.uMÒÉè$Åý #­×x|‰SŸúgb;<·|:}|{H?k¬ò"ÁÓ{�äìæwß áÝéÝ¡"v˜útŽ`OM".ÿÄ+.Ë÷"q=f“; åF&8e*’<û´íH4ŠÈiçÞ-w»´7rý:¤Û˜œJ� \ó!¶Ü$W'8[4“ì«„ËAvìMXFÊUÄÍ�HU®qta!;{;ªë¹ ÊÁ­àG^ôad¶Gê™gŒ¾P¥­)«Œ·È úîØ™ÜzИšSŽøg_êˆQ¤Ü=ÏS ªù¶¸âèM¿‡næ”– ­u%ã÷ú¢ÓÁ8½ Ì úx«=j]m6“aú@�“I›L]ö~çên0.*§ãÏæcžânQjŠ0‚ôêí‰6j®ñ1ÚC%g§�4ß\-GhÙ3Ý•[èàH"’—ó@ù>¯3°+©ÙÎÿäÜG½ù§W3r˜ÚKn>œÒÚ+{ç²òô·Š¬´ &…ñ6u¿_zêmeS)K+2òkò± éØ8ôÝ‘c¼3L®ÝÚí�Žªv²WܸÚßèÑ‘�¶Yຓ@§1"kâr}õqIÆþu ¸ ¡©[#ØÈôð¦‘w“f•—C?s·”b Œ[XAÅÊ Ã=‰‹\ ú„yäü�vJe¹•ÙׂfÁ$0²¤y£ž}:ŽÎ Ø­ô[èr‰zØ>Q†Áx �„“(® ~ 9Å5QþK�¸ÓÓÈÓ&)±¶‘9jÜa¥«`¾ê‹A8¤Ì×– ”©¿ƒÕ"“à†;bR3¸ “D©�W væÇ)ãϳS›Î£Ž�ÚÊ̲A}ÏÐꂇTÖ‹¾DcXHwüWE>Èà‘'•:Ð�•ÈœÄqqoie4>#�÷ -&}ì#}F�í5pÅã�±ã³*"•(taà¡ÂàÅ“"Ñ)®BÜ -·,AEexj¥ŸòÚ†›ûu®R�H×n_¶n¶(ö¶Îâg'v9HÃ^%Ü!?¾"XÎ@µÛÚ6×›R÷…­‰¯ÌÎyÔÆá=ÀÏ‚ö¯–8/Ö3VõMæÂ»8¿±ÿu!ð™rP@ÄÔ¯ ›“øqSzá~åjwñ¤xTèv¨TÚ.'ÿî†>ÐäÒš?Î`XºùÊT÷:™—ýÌ Aã?”1²\@ðd±Fâ|ɶÆD½‹°6õ Xõœ“4„,ˆðÁMÝR¿#÷°Œ¥&ìeõ¾­E„›ŸväÊýS²š+vWÈãsJÿËžýxñ¢Ìœã{ö[·>¦pQ… tÿ³òŽ)®Ì ¤Ç`ãmnX±^xõÚ-Ç®“©=®æ�´|�t¢Àr…βþ‰¹!ɰvÈ ^T¿ ßN‘k1½9¥#œÞiÔ[@ÝöSÉ‘’è&ÀÏvš¶¦_Ö.¯oþUœ�æ÷ÙÕt÷xLÚ½êø‰H/ ‚Ïm…Òfè¿ÃÉ‹.y Æ8Ô÷KüQE¶p:•7'§Nn¾„ì 8lh˯îo=›}¯¾•9P}Ví{sÔèÿŽ�ïnsÀXiVÓ”íEI€íH=ÒƒõsºK—Î{ÍÁ»ØÒcyO€g›¡P˜û‘–õ‰¿ÉÅþµ\3yy8#;çtº2‡ÿê[mš ©í‡ÿ‰y0˜ÚäQv{DŸ×®ú3@ä ã­h½lXÂqKž!®!õÐÖ¹ú§çÚ‡ŸîÀø–�%5Pú]×|¹õ´††#i2‰öíÍý Eäùì›êLÿî­ 7X¥¢)E»[Ýá[Z$ѾƺÅ–½¿îKšW¤¥ÒÜíešY#ñÙ,‰í�Þ„ì.eÀÒ<Š[èÍ؆,�I#ŒôÒ·5´BÚ ¢6Ìå)¥ÙùMP™12]ž Bäã'‘i"’-,¹XQ3Á™€Ø_@øå©ÆY5ÎŒDd�m P Uëe*zï =ý…,òc‡-¿gCó½6a‘¢1ucô°,a$õÖ×zܤ æV‚òÀRå “”$}ôÇÅ~ï¸9EZç1°H.1.–j¸¢î¿Ÿ{—N]aL·.7 ¦¯€DQ‰l¨°Ùñ‘±89Ågg˜­vDm˜ê^żäžïðDUV‰.’‹ „OX“EV½ñúůſ>qáz¯™Q}(¯#¸MoNªþ‚,–-ç~bûc–97þƒÛ W_ýÚ 'sžNYO j]feÈu´Ê6ó݃3¬¥Nâ‘+1g¸`äjÄ;Vn6ý²pf_OBdkàžpìuÕqž\HM…k�ûÇbµY2}¶PÏe'¼ÒqCG¡[J�ì7‰P~Oëê ’k¬™‘Õ3“/—A ]%†°h@ ozWÇlýÒ0—u¹rî[ÿ˜KŸ}–ún²gþÌ@)E¢ …/ï׿•A ãì�š¦›ŸÝéFz ‹ìӓ͸B‰@[Ë %Û×á!Ê~nÂ8o¦®H#7±=ªðG Ÿö¿qÍÐóв`Kaÿ„íHÃPXÙóú{ Œ¯Þz“ð|\+Èç|+Nn{W´*ã›Òý2†usá1\$«J÷‰µ®E3Õÿ°Û (ÓÁò‰¥Ql µÓâû¦ˆ\õ€V 6°ì¶†RÐ-]ú–SÑM¬´«}.ÒZ+í)BÏw{”û]ò�×¼BôŽ £[Ú~š–’‹©–uÖêk‹§*ë[“Réù½¼ÈƒKñ^ÿWñ.ý�yx^èS¥`¹ÇXñ T�9 Á‰}­ ,f%cò¶z¤Cdð°‰/oûXfÍÁgî/òŽæÖLb ãz¹IÑ9z,çik߸m2ÃHßè:ÚÈ™U3±6ê›ÐÔVà-­!S)­Tµþòt —Ãߊq‚üãÎ4zM’î=03mcí(f4E×Ù9¨˜Ji�#çØ$Ö€²‡.¼¶½î—f¹OÛša—¿ÇFaöæoËFV¹68qc•ò:u[P¯_«eÒžfàëf›ÛÖ»�$;R¾íŸÄ=§Œ‘!M�Æ—íS±(ÙbéLI�çoWÙ>òŸ“î铳ÒÓ¶—S{Iî=C.…ŠÛÍ'ÃÎ?^“Hut†q§¹›Yn—¦´ˆ®1o2²�òz.½ :L�?ÑÁmt‘¦×x) Lìå\èíöó¬�©K•a¿´¬p\!)ó §÷¯P#û…?#™ðÆÎêX58æ»ù޵¸*l¦&#àp(müL‡3–B±AóéV$®ò÷\Ö^›G�4–Øï”y³Þ°"Q’©s¬¯aò—R%VªwPRõ±ûo�ÆuÒÍ‘?ºËèðÔø| ÑjÅÆ ˆßFZ© Uíçíw¦³ÊåÝLeòt—Þ¡£±ß\®]�nfÈ yø*e6úŒ.ü¦”P��èZ Öâ‚ º!ýi…ï«{ï¤Ý†S¶hÚëêØgeyäÎy&úñ —Ê6#ˆýF(;`;S÷íþX·à‡«¶~Nþ>^„Æjß½#䬭VÏ%Þ†„Ød8tLí¥ƒÚF:änœ_ îõÈxrr«åô± „àŽV¡ÿ—;œ!ÑÆüHÙ¥©½IÄA�º_\d™êÞYšštˆI˾§ãzÒ!¦%,¼"{–( –ƒÆiðÅůÓïI«»ö�e²¢mnøq¥ŒÉ…w³ËX!qõüm­~"œ.Ã5Ì08¡8’ëA&›k÷y»pÌÝg¸þä¡!O úÆ5Ò/#Fv²Ñ¾»AßaI$¶öùIM$éV]ÆŽÎtõº˜ ¹ˆ\€�^ö*­B§X/e�`{Æh ÎLóê¥5ÎV4híE@òEÁhŒ�2²H1C|ggÍʳÏß® :O­ —B¿ ¸9’Œ0²ïXwTl}Š$4¨é�]¸ô‘“l“ÎôFÝÞ¬½0ÆeSbŽ+¿’í‰<ÑL¸J‘õ^‹!h�òï¡SiûA �fa‚B$?é×ZAt¸# – =š ü¿ÎGú—çTûÔûõU¾‘‘+FèX §L7ÿ»-áãx»µ¿˜Nƒ`¯Á�„6$cöÓ ÁÂBÚõ:—þN’mkCØ=ŽãF/}8âÖã^ÚDðAs¹´®#x_™•C«KT]˜ÖƲÔ¾½møa×á}üo† Vú´âä‚€ +Z*³N÷·G�°.™ IÊ›êáS \†Ä?ΤRý}-Jzã¡ÖbÍ­wêµØµ„ �…È�™_’ä7¥Æó¥sRáÁÅtÍ­n—’ëT;×ñŒl CŽS÷Q’ë¥Õ>T¡ã‹#A陡¯:^¯hõQ”ŠåÚÆÐÌU fB\ÿœm˜\ÕMrYó^ù`—A‡ô–œEëQˆïZ‹’�ÿ̪™¾Ð8#”Ú:V:ÞgJo’C‚ß0~×}”ætž4$¥ºóÔò°Ái“@b8epÚµÁµíÆE+˜b÷y–ßb´è³ò„«.ÓÐî˜v0ù›™H9û('�%™ÎqÓÁ‰‡N«)†{œ‰b²§?›,-nþ x½k Î?UT…áʰ4vl”¥P{%ªÝ‹vÄuݦBnðC¿jI÷4CLJ§�ì³Xk?fC¯åjpõß¿h×q”«ì�50RHU*‡ÒØÌ-m‹:Á|ã5´;Q•›µß&¼ùì¶PérçÕnŽŒ�L‘Uçò×5ƒ÷©yéšI,OY¡*„áùŽ“)XLÐN5 8ð‡L¨Vá6«³W 9Q R#+ކ K¢ìýäXÜg.náá2Šá»í2KÒØ—ïTõÂÞËÇÝ„¥F0XC‡,S_ç-ÏÔ,ÞÇñäÄÜà–¸‚ ö3"¤m²wr•‰kBÇR‰žÎrêK¦Éå.yú°V:±Ü;â *� 0èk½—V¼!¾“ŽBçýê ÔŠ¬±ˆì¿´Šú祽ò´D…¶ïbhtÄ·+ǵ!dƯ¢t'UNa¤…‘øÃÈÆ³RV»3J†™¢ñqôòï(Öô�<xm%cw†8Òž gVlz/˜ZÀφ“é{ꇕõGï@îv�•“pذU×ML-wmÕ<õ[ü ‰ŽêiAå8\0"k87Êž??—…� Zî"¶B'ì�ry/ Œ¬G’ñ)Ê•Hœj¾d/¦EÞLÑÆÿ4×8éG©Vä^LÁÊr1ÿ›¤äP =£¿g�Œ˜(F݇VÅÙY´ü4Åd•SÐL×ZÄÈÿ@,Ú†qñ­Û÷sUwOéB©Ø�‹ðáiñŽ$B¿ü(Ü»/ÞœSÀÑùdñëŽ3{Y¨¸¶ÛAò¥ ÙS'¦êçX*=eB3;näŒ1 îr§ír™‚ÊGÛ¶šãÍ®TóÄÍ <¼Ìžá—‰šy³sWûCáÜ=ªÝÃIjÐyg!=°Š¤�m¯\2£ö}bD!bë¯}ÂWœš�¢åÐÓÝ=XØj´:×…*hýøA81 #$ÄcØWfš'çF]iJo·âY…ÿ�d çmdÃß B~!=9- •ÔµþÞ yMMfª¿l�p‹ÙÞuÁßá°æ•¹6¹•]«Ùøk²¨6´%{둞: µ·Å³ë₍ï�û`眺!T̺p=�ygxæ(q–˜®ÈZn¼@Š�E¾ûö½aœe¯c6ho†Uè�Å[óuø"Ðï¤}†aÌä�“ÐÉ>:óˆŽ)ß»^]Q¬˜#õy«‰Câ«9åÜÅÎÞÑÅ…ÿG¹DZjœ³í&⥎Aà=ä²½um©q>©jJF¨’!ÙÍÀZ »{Ê^Š©óf!— o:Kç\tÚJ8™X@ —úÎj Ü4«º;07:MóÑ!©çñ3Vï‚€dܱ MÝppËTýµ]÷?l��órˆÔÔV/b „Ö†68¨º.'“[±$ƒ<בiﮂ¶æŽˆ¿4 Í®§ðú€1Ü�ñ.†úôÂ~pç”d>?ØÕ¾æw‰8­±P¹Lçbð\8Q·Ì²mï�f\ ƒe+‰õ½Í® ù?Êìªd)dœ“ÉóŽ�¥µ„�…®W™®´ÑIr$YB8v�@Ø 06�Šf%¸.ý·�Ê+1_Ê£€Ìî^Ѥà <•ºîp[GépÏŒwÌ ‚ìÙ´EâÔq6ÛªƒñË´×›ý�_ƒ-/¼‰kç qNúãKŽñLDu÷ïá’ c_DM!ÌâçwsV·¨¹ -ðUÓ÷ãØŸA¯�Š´¼q®g@Ukwíìp~SE9½tݲduÍ�tÿ}*Á&ïYe�zÂîÛSÙñEóÝâ=|çÁ Ʀ ;ïÐ<_�oâLÜ�òÔ|’'Y÷ûÈá=‡2¶y¢nï²Ì}VœúRìtOæ¼ þ•A0gÎ:KÉ{‡ìµÂ]è­I‰}/àÀjóÒ�ah•_t ®I$5‘uÌ&.µÒq¤2ÍÎ^¿w…dMMOè1-)zàuñÃX<Û]ÖIâ ŽÈ" Ý,ˆ/g® €ã|õ¯˜>éŸu¦¶ËÀ9ÃVÿ�ûžÉÒ/ò5k€ì-!“[Äø&þñŒ FÖ Ö{ëñq±ØõwhŽ¥ æéyõ3²]—æäéˆÛÛP\5NDùìÙžožcAÈSéâVm>[þâ}kE:Ž"üºÍTÆ ?WŸ î'aï3QíjŠuØxgÇúnrj–èMQyµäçŸÏ�høV´W†–&ÞÿÛEÙ)ó–È«<ªýLÓmÿѵJEöíÄDâ|ødæCj¹žßA§+äˆ׉Ôwˆ,Ý rcÆýMÜ­«M“Ïפ�kFKg˜ÓÇ ü¡ÇZcxé ìÊ)lQYŽ*Ru¹tO’2¢¼^½òµW@ýäÞ‚½ƒÄÐ`þÜÂT�¯šÜ† fCpK:©Þl)Ü9Øc––Mž¸¦ß®&)n,•ì‹Nñ%ù»ß4�ç{Ä?3�Ð^@>èÈJ„.òE|ƒ 0¡×\�ì§=e÷7üØsÉZ$ 5Þ«w? \."<$Ó)´�ßpäRwèƒÌß6Î;nì\+@°ÃiÍõ”ë–Rxã7Öî.V€~傦Bmk4ñ@áé‚%?-f$1¿²ÍFbñçšã•²ßPïeCS r:ýJ(üqÀf‹µ9âç˜äˆ¶L iáØÕÁNS(†î)»%w–yûyðS(Ô$("­�¤-­£H2Á‹²f>šËÙVïà$xbƒ‹žsÆhÃ%uÎIíòm+'ðNÝç�d럈?¿põË—8}ÖÖÊàpÝb�è�î§‘™ßè¬�à̈ŠPÄ«¯(KL.Íg ¼kH¼a+Œxé‚3ü1˜›+éOéçÌ…ar±7& ëÁvõdVóùOÉËê6!ï3ÞB4ÿø,F|sÄ·¡ž¦ë¿õw@*B`Ð_]æq>ù/ �èÃñ�½ø�×Ô"êÎÇNiK&”…=.ÿh¾À-JÓìæÎ;RvÓõ¨„À;YD¯ŸðÂpâšôT>JmÑØ„§3a¿ÕS ¬J+`Õ=*ãŒ1o05ÖY¼ò1¨k¯2eîÉÒÚÃ:ÅŽò5IrÝ �å¬WÚ1Ë1(£ X=~É`ä5ø;B,ƒd—´5ŠB KZOù>üS.�TÝ Š é%*¸ŒźþíoOú4yJ˜Ô8"B‘¶`G YSôâ#Ÿ‰ U¨I• 1ú÷nùäîy)~Nj7��÷•ZÜg¹\|¢¢EÐ «ÿ«0‚ŽínSîÅ�À¼“UúP Rf=²ÎÒòUE¹!¿_’šïÛ?~ åŽ+æΰÔ[£!W;þ#�„µ‘ú%‚tqšeŠ*ÚÅö»˜ÊŽLð û‹òY9WTd Ê+¿vsÓ~Vò!@œº’š�Ý ;éWÉïl�ÑÚUéf€æ6€ÒG¾�´y ²ü–¥%rŽŠLb@çå-���,ßÚy Á¥Ý MxR ä¼�o^‹ÉüdçN¬Ÿôf¤ÏóÄåmà% Û1÷[òKÇ;‹.žúBºÅ,ý�¢á:þ£þ^§ÁÌ&µ> ê/!†3|Ö«SÞ—yTßF?øË0E22¢>¤jQu?ìžx€©’ûî~$[Ó«™8ô¯ù{Üw!?I‰’a ×)!ö@à°½È@¶ jTz\žù+þU¼•øÐêêÆüß¼–T½Œ‘£ºBŒ+.ú€Ý%Û'±Zú oMO™œ8b(ºÔßg.ÙØE·�ácGZÒËêŸB—æ¾Wx‚»5õÔ0¤'œç##9]!@&˜Ìó�Ý¢FýL†FŠÐ*ß•Âa¤6˜ï`­£ 1\j¶Œ©ûܦ#ÂôÊÁ«ÌÀ5~µZ œ¬;s–í¹ØŸ¯o9­5 :!Ï$½—¡`môŽJºÒ¨ÑC+œþH;q !LO‚ñ�ªá’b�5­O~ 6D„o§õÉòÑkCZå¹@ȶD›©t†xÅø Ûõ˜¿4‡ï¬Ž<œŒU§9ë—žægù²Ÿ•ë–zÛ"rU¯ BœŒ‡,¿|¼?;Éùñî¾²ñ0sê�@aŠ€Ë³�éYòó:‰’@5¦1ñq±0ÆYDãc:âPoBê.Õ­²WZ²ÍDL÷·ÞÜ ÅìZ­°ezž> \_¼7tm–îÓë9&¢DütÉð—Ü•hI >kæ…F€‡þÒLöÑqWPBX`á#¦´«ÚæAßùþƒ#ÎÓXn³$u1�Y ÀuÃ|þE)èx†H¿õ.®-¿\t¿<7¶dÆ®(ìTü¾%ž(Í‚%Çê–¨«¸™Ç¨-’7ï±=ªaß’Ö±ü@†?À‘ÈT¡}ý‰öó·p ÷§àp(¶�RW‚»\ŸT@² �ž½îâ²;)BhôR9ïþ÷ïß®�ã«´ßì?}_™‰l¿ &°Y–ˆèê½odŠ‘ô*ƒïðÊ¿d�D«´âí€�Ì ³ûª]›õëha >ôyTMp´2‹¸e q¬±�8/ߟjÈ ÚǫɿÀÏ k³ Y® ¾ m’èº].Ê}ûß`æ4Ê�1Sy˜;€à,ɯt r!Mƒõ1Á�:°/i)¸X£ŽŸçÌa‘Xö–ø 4ðˆRš(Œ”ŽÕÕxºäIfQ3så/ŒÀ†Ñöž5ÒÕÃ',ö÷,½Ç²ªu[rwÝþ ÖÏn i á‰Tç†Ó9�XÏs§³Šè \·Ø =ºœôî˜1 "¸coäÅ/ê¡ã……¶“ ƒéžk?'-ÍHWªk …ukÈ1 0f›-Ý�Д˜¬5²gñéãªøÖc˜» q�;ˆZÀî5\ÂÓY5*÷[àØx–Àñ¯ß R»Y b¢úÄ_(%�…×L™ëa h²§5(·yÓn>�‘›éDŠ-¤Á»ˆ/HòÒ{uäef�/TCIÇ·R+FlÁ±øÄ» ÷UãÚ8ïúfBûa¦Þ<š’9 ¡ŒUvnɆŒ`g K³1–ŠN�Dß·¬ ÇL§? :ÚYS3oÜ 2b~ôg ó(š/¨y'æ”´¸ç@I%�JšZÐö3 lülŠY±=± ^!ua¯¼eAöè(†Ÿ34þܵÿÏSºaþ^ÀrŠÑrmgG`+n]8Ôī¿‹ù¨ˆ_Ã`ñ øHpn]á¼.2Dìò{µ¨ðDáÁí¶|’�>– ÇÓö~­mW�ÌÚxI�#¯g—zžÈ;‡*Õ~¶ïÅ ¦ëÞzi�9§6@û<û²ÂÔÆºI&o /Þ…t¯Ô,ˆ=?«v•s»Ü¥ÒÎ @™R)e~3ÛÑë�ûcêhiI�—·Ë�¸¥9«¾9Ü|F{ÿC2V1��°÷ÞSYêôše�@µ 9_,˜ í ñ9%¶ó£ùÂúÃbŸ…#æ2ä`O\úÈf+e^ìϦ�ê«_~úÆaÕgÛÖ;¸i † ï‘:§3mmØÁÚþ„ Ÿ{w©!dP-ÆæSêg£0ºÂÁ[Ü{efOŠ ˆ–s@¶ôÏÑ_!”um²hñM}õ!�å‹ë+Ò&�‚6YH C‹DµÕ{_ÅÅЧ0T7m`)C/4 Õ/a‡ •uâ©}XÛãcF ‰›Çš“SéºÄGÔÀbý�zðó¹EísÚ‚X¥çs ÚÿÙ‘žÿ:°÷dþ%ÎN—fÉóá ôVÍó ç掶¤CXÏIýóê +{A:3�Î×\4ñ&0]-k•ÈM$8£Äúâþ…éã§�jë]at ¸ÿ±/æ‰h& Ì(ÞŒj MΜûÊ+˜«ó½ãϹ¡ÇÉ8,'ÂC²Y0‚ùnù­eCÄ«®"¡Å«B¨û1øêåŒù�N>R.pñ1ü§)L­©Ó…WRW‡ÛZû°Ålÿç„£ª–ÝŒµé¤ &Ì‘ÔÜ+UáÌ&Ú«u´ýÝÖ~XªÏ"cÁ"l@u¸Ñ0¾ùòÈý×Ó'Ø ‚S¢XŠÀãZ¨\%téÔrŠ‹n¤¥5Ìç*¨\QzáÆ=@%â|¿øÑû.TÂO"µØ¸dGúE"sXYà!¾äx�­}M§ÖÎAdL¹Öï�„\•«üóͽlö·¦²ñeQMY¼’ãÆÓÑêìÎâ�Ðò^§ŸºŠÚð­)è›òê)—*ñæö} q ç‡ 0‹ãe¨ÇpwvšÓ æ¥I¯¼ØW‡ô,2_FüZl�à:Ô%,,�Ü!º9¾…yÓ”)[�~CZD,ÚëM“ß|NÀù_¨ÃJ[‘1hëäÔn¥Å-ª^÷rsÌ«§ymLBÁ÷Py‡…ÿk#”ÑQ{óxÅôgü[ ØH¬­a¼ ù¯¤w¢wGÕŸù^;Œ<ó?ó¨<¡Ý!ÆbNmÖð<^Ë´™É ýPÖË�Ò6»y^‹ù¡Ð†¤¿•;Ñ„@Š¢¤vf+]û²2{æ¡ÜVFªÚó¨e¦&™k1ÕVîj6¼_£™f½×L2bJ¯SÌÙmý�«3QIÜ]¹»ÜÖæ_Ÿ£‡ð8øŸ None: """Copy `in_file` to `out_file` and append the string `tag`.""" with Path(out_file).open("wb") as out_f, Path(in_file).open("rb") as in_f: out_f.write(in_f.read()) out_f.write(tag.encode()) if __name__ == "__main__": convert(sys.argv[1], sys.argv[2], sys.argv[3]) beetbox-beets-00724b7/test/ui/0000775000175000017500000000000015253035401015447 5ustar pieterpieterbeetbox-beets-00724b7/test/ui/test_ui.py0000664000175000017500000004135015253035401017500 0ustar pieterpieter"""Tests for the command-line interface.""" import os import platform import sys import unittest from pathlib import Path from unittest.mock import patch import pytest from confuse import ConfigError from beets import config, plugins, ui from beets.exceptions import UserError from beets.test import _common from beets.test.helper import BeetsTestCase, IOMixin, PluginTestCase from beets.ui import _open_library, commands class PrintTest(IOMixin, unittest.TestCase): def test_print_without_locale(self): with patch.dict(os.environ, {}, clear=False): os.environ.pop("LANG", None) ui.print_("something") @patch.dict(os.environ, {"LANG": "", "LC_CTYPE": "UTF-8"}, clear=False) def test_print_with_invalid_locale(self): ui.print_("something") class ShowModelChangesTest(IOMixin, BeetsTestCase): def test_uses_database_state_when_old_not_provided(self): item = self.add_item_fixture(title="old title") old_label = format(item.get_fresh_from_db()) item.title = "new title" assert ui.show_model_changes(item) is True assert self.io.getoutput().splitlines() == [ old_label, " title: old title -> new title", ] class TestPluginTestCase(PluginTestCase): plugin = "test" def setUp(self): self.config["pluginpath"] = [_common.PLUGINPATH] super().setUp() class ConfigTest(IOMixin, TestPluginTestCase): def setUp(self): super().setUp() # Don't use the BEETSDIR from `helper`. Instead, we point the home # directory there. Some tests will set `BEETSDIR` themselves. del os.environ["BEETSDIR"] # Also set APPDATA, the Windows equivalent of setting $HOME. appdata_dir = self.temp_path / "AppData" / "Roaming" self._orig_cwd = Path.cwd() self.test_cmd = self._make_test_cmd() commands.default_commands.append(self.test_cmd) # Default user configuration if platform.system() == "Windows": self.user_config_dir = appdata_dir / "beets" else: self.user_config_dir = self.temp_path / ".config" / "beets" self.user_config_dir.mkdir(parents=True, exist_ok=True) self.user_config_path = self.user_config_dir / "config.yaml" # Custom BEETSDIR self.beetsdir = self.temp_path / "beetsdir" self.beetsdir.mkdir(parents=True, exist_ok=True) self.env_config_path = self.beetsdir / "config.yaml" self.cli_config_path = self.temp_path / "config.yaml" self.env_patcher = patch( "os.environ", {"HOME": str(self.temp_path), "APPDATA": str(appdata_dir)}, ) self.env_patcher.start() self._reset_config() def run_command(self, *args, **kwargs): # We need to reload the lib based on the # current config self.lib = _open_library(self.config) super().run_command(*args, **kwargs) def tearDown(self): self.env_patcher.stop() commands.default_commands.pop() os.chdir(self._orig_cwd) super().tearDown() def _make_test_cmd(self): test_cmd = ui.Subcommand("test", help="test") def run(lib, options, args): test_cmd.lib = lib test_cmd.options = options test_cmd.args = args test_cmd.func = run return test_cmd def _reset_config(self): # Config should read files again on demand config.clear() config._materialized = False def write_config_file(self): return self.user_config_path.open("w") def test_paths_section_respected(self): with self.write_config_file() as config: config.write("paths: {x: y}") self.run_command("test") assert self.test_cmd.lib.path_formats[0] == ("x", "y") def test_nonexistant_db(self): with self.write_config_file() as config: config.write("library: /xxx/yyy/not/a/real/path") self.io.addinput("n") with pytest.raises(UserError): self.run_command("test") def test_user_config_file(self): with self.write_config_file() as file: file.write("anoption: value") self.run_command("test") assert config["anoption"].get() == "value" def test_replacements_parsed(self): with self.write_config_file() as config: config.write("replace: {'[xy]': z}") self.run_command("test") replacements = self.test_cmd.lib.replacements repls = [(p.pattern, s) for p, s in replacements] # Compare patterns. assert repls == [("[xy]", "z")] def test_multiple_replacements_parsed(self): with self.write_config_file() as config: config.write("replace: {'[xy]': z, foo: bar}") self.run_command("test") replacements = self.test_cmd.lib.replacements repls = [(p.pattern, s) for p, s in replacements] assert repls == [("[xy]", "z"), ("foo", "bar")] def test_cli_config_option(self): self.cli_config_path.write_text("anoption: value") self.run_command("--config", str(self.cli_config_path), "test") assert config["anoption"].get() == "value" def test_cli_config_file_overwrites_user_defaults(self): self.user_config_path.write_text("anoption: value") self.cli_config_path.write_text("anoption: cli overwrite") self.run_command("--config", str(self.cli_config_path), "test") assert config["anoption"].get() == "cli overwrite" def test_cli_config_file_overwrites_beetsdir_defaults(self): os.environ["BEETSDIR"] = str(self.beetsdir) self.env_config_path.write_text("anoption: value") self.cli_config_path.write_text("anoption: cli overwrite") self.run_command("--config", str(self.cli_config_path), "test") assert config["anoption"].get() == "cli overwrite" # @unittest.skip('Difficult to implement with optparse') # def test_multiple_cli_config_files(self): # cli_config_path_1 = self.temp_path / 'config.yaml' # cli_config_path_2 = self.temp_path / 'config_2.yaml' # # with open(cli_config_path_1, 'w') as file: # file.write('first: value') # # with open(cli_config_path_2, 'w') as file: # file.write('second: value') # # self.run_command('--config', cli_config_path_1, # '--config', cli_config_path_2, 'test') # assert config['first'].get() == 'value' # assert config['second'].get() == 'value' # # @unittest.skip('Difficult to implement with optparse') # def test_multiple_cli_config_overwrite(self): # cli_overwrite_config_path = self.temp_path / 'overwrite_config.yaml' # # self.cli_config_path.write_text("anoption: value") # # with open(cli_overwrite_config_path, 'w') as file: # file.write('anoption: overwrite') # # self.run_command('--config', str(self.cli_config_path), # '--config', cli_overwrite_config_path, 'test') # assert config['anoption'].get() == 'cli overwrite' # FIXME: fails on windows @unittest.skipIf(sys.platform == "win32", "win32") def test_cli_config_paths_resolve_relative_to_user_dir(self): self.cli_config_path.write_text("library: beets.db\nstatefile: state") self.run_command("--config", str(self.cli_config_path), "test") assert config["library"].as_path() == self.user_config_dir / "beets.db" assert config["statefile"].as_path() == self.user_config_dir / "state" def test_cli_config_paths_resolve_relative_to_beetsdir(self): os.environ["BEETSDIR"] = str(self.beetsdir) self.cli_config_path.write_text("library: beets.db\nstatefile: state") self.run_command("--config", str(self.cli_config_path), "test") assert config["library"].as_path() == self.beetsdir / "beets.db" assert config["statefile"].as_path() == self.beetsdir / "state" def test_command_line_option_relative_to_working_dir(self): config.read() os.chdir(self.temp_path) self.run_command("--library", "foo.db", "test") assert config["library"].as_path() == Path.cwd() / "foo.db" def test_cli_config_file_loads_plugin_commands(self): self.cli_config_path.write_text( f"pluginpath: {_common.PLUGINPATH}\nplugins: test" ) self.run_command("--config", str(self.cli_config_path), "plugin") plugs = plugins.find_plugins() assert len(plugs) == 1 assert plugs[0].is_test_plugin self.unload_plugins() def test_beetsdir_config(self): os.environ["BEETSDIR"] = str(self.beetsdir) self.env_config_path.write_text("anoption: overwrite") config.read() assert config["anoption"].get() == "overwrite" def test_beetsdir_points_to_file_error(self): beetsdir = self.temp_path / "beetsfile" beetsdir.touch() os.environ["BEETSDIR"] = str(beetsdir) with pytest.raises(ConfigError): self.run_command("test") def test_beetsdir_config_does_not_load_default_user_config(self): os.environ["BEETSDIR"] = str(self.beetsdir) self.user_config_path.write_text("anoption: value") config.read() assert not config["anoption"].exists() def test_default_config_paths_resolve_relative_to_beetsdir(self): os.environ["BEETSDIR"] = str(self.beetsdir) config.read() assert config["library"].as_path() == self.beetsdir / "library.db" assert config["statefile"].as_path() == self.beetsdir / "state.pickle" def test_beetsdir_config_paths_resolve_relative_to_beetsdir(self): os.environ["BEETSDIR"] = str(self.beetsdir) self.env_config_path.write_text("library: beets.db\nstatefile: state") config.read() assert config["library"].as_path() == self.beetsdir / "beets.db" assert config["statefile"].as_path() == self.beetsdir / "state" class PluginTest(TestPluginTestCase): def test_plugin_command_from_pluginpath(self): self.run_command("test") class CommonOptionsParserCliTest(IOMixin, BeetsTestCase): """Test CommonOptionsParser and formatting LibModel formatting on 'list' command. """ def setUp(self): super().setUp() self.item = _common.item() self.item.path = b"xxx/yyy" self.lib.add(self.item) self.lib.add_album([self.item]) def test_base(self): output = self.run_with_output("ls") assert output == "the artist - the album - the title\n" output = self.run_with_output("ls", "-a") assert output == "the album artist - the album\n" def test_path_option(self): output = self.run_with_output("ls", "-p") assert output == f"{self.lib_path / 'xxx/yyy'}\n" output = self.run_with_output("ls", "-a", "-p") assert output == f"{self.lib_path / 'xxx'}\n" def test_format_option(self): output = self.run_with_output("ls", "-f", "$artist") assert output == "the artist\n" output = self.run_with_output("ls", "-a", "-f", "$albumartist") assert output == "the album artist\n" def test_format_option_unicode(self): output = self.run_with_output("ls", "-f", "caf\xe9") assert output == "caf\xe9\n" def test_root_format_option(self): output = self.run_with_output( "--format-item", "$artist", "--format-album", "foo", "ls" ) assert output == "the artist\n" output = self.run_with_output( "--format-item", "foo", "--format-album", "$albumartist", "ls", "-a" ) assert output == "the album artist\n" def test_help(self): output = self.run_with_output("help") assert "Usage:" in output # command description is on the same line assert ( "config show or edit the user configuration" in output ), "unexpected command description formatting" output = self.run_with_output("help", "list") assert "Usage:" in output with pytest.raises(UserError): self.run_command("help", "this.is.not.a.real.command") def test_stats(self): output = self.run_with_output("stats") assert "Approximate total size:" in output # # Need to have more realistic library setup for this to work # output = self.run_with_output('stats', '-e') # assert 'Total size:' in output def test_version(self): output = self.run_with_output("version") assert "Python version" in output assert "no plugins loaded" in output # # Need to have plugin loaded # output = self.run_with_output('version') # assert 'plugins: ' in output class CommonOptionsParserTest(unittest.TestCase): def test_album_option(self): parser = ui.CommonOptionsParser() assert not parser._album_flags parser.add_album_option() assert bool(parser._album_flags) assert parser.parse_args([]) == ({"album": False}, []) assert parser.parse_args(["-a"]) == ({"album": True}, []) assert parser.parse_args(["--album"]) == ({"album": True}, []) def test_path_option(self): parser = ui.CommonOptionsParser() parser.add_path_option() assert not parser._album_flags config["format_item"].set("$foo") assert parser.parse_args([]) == ({"path": None}, []) assert config["format_item"].as_str() == "$foo" assert parser.parse_args(["-p"]) == ( {"path": True, "format": "$path"}, [], ) assert parser.parse_args(["--path"]) == ( {"path": True, "format": "$path"}, [], ) assert config["format_item"].as_str() == "$path" assert config["format_album"].as_str() == "$path" def test_format_option(self): parser = ui.CommonOptionsParser() parser.add_format_option() assert not parser._album_flags config["format_item"].set("$foo") assert parser.parse_args([]) == ({"format": None}, []) assert config["format_item"].as_str() == "$foo" assert parser.parse_args(["-f", "$bar"]) == ({"format": "$bar"}, []) assert parser.parse_args(["--format", "$baz"]) == ( {"format": "$baz"}, [], ) assert config["format_item"].as_str() == "$baz" assert config["format_album"].as_str() == "$baz" def test_format_option_with_target(self): with pytest.raises(KeyError): ui.CommonOptionsParser().add_format_option(target="thingy") parser = ui.CommonOptionsParser() parser.add_format_option(target="item") config["format_item"].set("$item") config["format_album"].set("$album") assert parser.parse_args(["-f", "$bar"]) == ({"format": "$bar"}, []) assert config["format_item"].as_str() == "$bar" assert config["format_album"].as_str() == "$album" def test_format_option_with_album(self): parser = ui.CommonOptionsParser() parser.add_album_option() parser.add_format_option() config["format_item"].set("$item") config["format_album"].set("$album") parser.parse_args(["-f", "$bar"]) assert config["format_item"].as_str() == "$bar" assert config["format_album"].as_str() == "$album" parser.parse_args(["-a", "-f", "$foo"]) assert config["format_item"].as_str() == "$bar" assert config["format_album"].as_str() == "$foo" parser.parse_args(["-f", "$foo2", "-a"]) assert config["format_album"].as_str() == "$foo2" def test_add_all_common_options(self): parser = ui.CommonOptionsParser() parser.add_all_common_options() assert parser.parse_args([]) == ( {"album": False, "path": None, "format": None}, [], ) class TestEncoding: """Tests for the `terminal_encoding` config option and our `_in_encoding` and `_out_encoding` utility functions. """ def test_out_encoding_overridden(self, config): config["terminal_encoding"] = "fake_encoding" assert ui._out_encoding() == "fake_encoding" def test_in_encoding_overridden(self, config): config["terminal_encoding"] = "fake_encoding" assert ui._in_encoding() == "fake_encoding" def test_out_encoding_default_utf8(self, config): config["terminal_encoding"] = None with patch("sys.stdout") as stdout: stdout.encoding = None assert ui._out_encoding() == "utf-8" def test_in_encoding_default_utf8(self, config): config["terminal_encoding"] = None with patch("sys.stdin") as stdin: stdin.encoding = None assert ui._in_encoding() == "utf-8" beetbox-beets-00724b7/test/ui/__init__.py0000664000175000017500000000000015253035401017546 0ustar pieterpieterbeetbox-beets-00724b7/test/ui/test_ui_init.py0000664000175000017500000000561715253035401020531 0ustar pieterpieter"""Test module for file ui/__init__.py""" import unittest from copy import deepcopy from pathlib import Path from random import random import pytest from beets import config, ui from beets.exceptions import UserError from beets.test.helper import BeetsTestCase, IOMixin class InputMethodsTest(IOMixin, unittest.TestCase): def _print_helper(self, s): print(s) def _print_helper2(self, s, prefix): print(prefix, s) def test_input_select_objects(self): full_items = ["1", "2", "3", "4", "5"] # Test no self.io.addinput("n") items = ui.input_select_objects( "Prompt", full_items, self._print_helper ) assert items == [] # Test yes self.io.addinput("y") items = ui.input_select_objects( "Prompt", full_items, self._print_helper ) assert items == full_items # Test selective 1 self.io.addinput("s") self.io.addinput("n") self.io.addinput("y") self.io.addinput("n") self.io.addinput("y") self.io.addinput("n") items = ui.input_select_objects( "Prompt", full_items, self._print_helper ) assert items == ["2", "4"] # Test selective 2 self.io.addinput("s") self.io.addinput("y") self.io.addinput("y") self.io.addinput("n") self.io.addinput("y") self.io.addinput("n") items = ui.input_select_objects( "Prompt", full_items, lambda s: self._print_helper2(s, "Prefix") ) assert items == ["1", "2", "4"] # Test selective 3 self.io.addinput("s") self.io.addinput("y") self.io.addinput("n") self.io.addinput("y") self.io.addinput("q") items = ui.input_select_objects( "Prompt", full_items, self._print_helper ) assert items == ["1", "3"] class ParentalDirCreation(IOMixin, BeetsTestCase): def test_memory_path_skips_creation_prompt(self): ui._ensure_db_directory_exists(Path(":memory:")) assert not self.io.getoutput() def test_create_yes(self): non_exist_path = self.temp_path / "nonexist" / str(random()) # Deepcopy instead of recovering because exceptions might # occur; wish I can use a golang defer here. test_config = deepcopy(config) test_config["library"] = str(non_exist_path) self.io.addinput("y") lib = ui._open_library(test_config) lib._close() def test_create_no(self): non_exist_path_parent = self.temp_path / "nonexist" non_exist_path = non_exist_path_parent / str(random()) test_config = deepcopy(config) test_config["library"] = str(non_exist_path) self.io.addinput("n") with pytest.raises(UserError): ui._open_library(test_config) assert not non_exist_path_parent.exists() beetbox-beets-00724b7/test/ui/test_ui_importer.py0000664000175000017500000000550515253035401021423 0ustar pieterpieter"""Tests the TerminalImportSession. The tests are the same as in the test_importer module. But here the test importer inherits from ``TerminalImportSession``. So we test this class, too. """ from unittest import mock from beets import importer from beets.test.helper import TerminalImportMixin from test import test_importer class TestNonAutotaggedImport( TerminalImportMixin, test_importer.TestNonAutotaggedImport ): pass class TestImport(TerminalImportMixin, test_importer.TestImport): pass class ImportSingletonTest( TerminalImportMixin, test_importer.ImportSingletonTest ): def test_singleton_manual_search_updates_candidates(self): self.importer.io.addinput("e") self.importer.io.addinput("ManualArtist") self.importer.io.addinput("ManualTrack") self.importer.io.addinput("a") self.importer.run() assert not self.lib.albums() assert self.lib.items().get().title == "ManualTrack" class ImportTracksTest(TerminalImportMixin, test_importer.ImportTracksTest): pass class ImportCompilationTest( TerminalImportMixin, test_importer.ImportCompilationTest ): pass class ImportExistingTest(TerminalImportMixin, test_importer.ImportExistingTest): pass class ChooseCandidateTest( TerminalImportMixin, test_importer.ChooseCandidateTest ): def test_manual_search_updates_candidates(self): self.importer.io.addinput("e") self.importer.io.addinput("ManualArtist") self.importer.io.addinput("ManualAlbum") self.importer.io.addinput("m") self.importer.io.addinput("1") self.importer.io.addinput("a") self.importer.run() album = self.lib.albums().get() assert "ManualAlbum" in album.album def test_manual_id_updates_candidates(self): album_info = self.matcher._make_album_match("IDArtist", "IDAlbum", 1) with mock.patch( "beets.metadata_plugins.albums_for_ids", return_value=[album_info] ): self.importer.io.addinput("i") self.importer.io.addinput("custom_release_id") self.importer.io.addinput("m") self.importer.io.addinput("1") self.importer.io.addinput("a") self.importer.run() album = self.lib.albums().get() assert "IDAlbum" in album.album class GroupAlbumsImportTest( TerminalImportMixin, test_importer.GroupAlbumsImportTest ): pass class GlobalGroupAlbumsImportTest( TerminalImportMixin, test_importer.GlobalGroupAlbumsImportTest ): pass class TestImportDuplicateAlbumUpgrade( TerminalImportMixin, test_importer.TestImportDuplicateAlbumUpgrade ): def setup_beets(self): super().setup_beets() self.config["import"]["duplicate_action"] = "ask" self.importer.add_duplicate_action(importer.DuplicateAction.UPGRADE) beetbox-beets-00724b7/test/ui/commands/0000775000175000017500000000000015253035401017250 5ustar pieterpieterbeetbox-beets-00724b7/test/ui/commands/test_move.py0000664000175000017500000001072115253035401021630 0ustar pieterpieterimport shutil from beets import library from beets.test.helper import BeetsTestCase, IOMixin class MoveTest(IOMixin, BeetsTestCase): def setUp(self): super().setUp() self.initial_item_path = self.lib_path / "srcfile" shutil.copy(self.resource_path, self.initial_item_path) # Add a file to the library but don't copy it in yet. self.i = library.Item.from_path(self.initial_item_path) self.lib.add(self.i) self.album = self.lib.add_album([self.i]) # Alternate destination directory. self.otherdir = self.temp_path / "testotherdir" self.otherdir.mkdir() self.item_moved_to = self.otherdir / "Compilations" def test_move_item(self): self.run_command("move") self.i.load() assert b"libdir" in self.i.path assert self.i.filepath.exists() assert not self.initial_item_path.exists() def test_copy_item(self): self.run_command("move", "-c") self.i.load() assert b"libdir" in self.i.path assert self.i.filepath.exists() assert self.initial_item_path.exists() def test_move_album(self): self.run_command("move", "-a") self.i.load() assert b"libdir" in self.i.path assert self.i.filepath.exists() assert not self.initial_item_path.exists() def test_copy_album(self): self.run_command("move", "-a", "-c") self.i.load() assert b"libdir" in self.i.path assert self.i.filepath.exists() assert self.initial_item_path.exists() def test_move_item_custom_dir(self): self.run_command("move", "--dest", str(self.otherdir)) self.i.load() assert b"testotherdir" in self.i.path assert self.i.filepath.exists() assert not self.initial_item_path.exists() def test_move_album_custom_dir(self): self.run_command("move", "-a", "--dest", str(self.otherdir)) self.i.load() assert b"testotherdir" in self.i.path assert self.i.filepath.exists() assert not self.initial_item_path.exists() def test_move_album_custom_dir_timid(self): self.io.addinput("s") # select self.io.addinput("y") # yes self.run_command("move", "-a", "--dest", str(self.otherdir), "-t") self.i.load() assert b"testotherdir" in self.i.path assert self.i.filepath.exists() assert not self.initial_item_path.exists() def test_pretend_move_item(self): self.run_command("move", "--dest", str(self.otherdir), "-p") self.i.load() assert self.i.filepath == self.initial_item_path def test_pretend_move_album(self): self.run_command("move", "-a", "-p") self.i.load() assert self.i.filepath == self.initial_item_path def test_export_item_custom_dir(self): self.run_command("move", "--dest", str(self.otherdir), "-e") self.i.load() assert self.i.filepath == self.initial_item_path assert self.item_moved_to.exists() def test_export_album_custom_dir(self): self.run_command("move", "--dest", str(self.otherdir), "-a", "-e") self.i.load() assert self.i.filepath == self.initial_item_path assert self.item_moved_to.exists() def test_pretend_export_item(self): self.run_command("move", "--dest", str(self.otherdir), "-e", "-p") self.i.load() assert self.i.filepath == self.initial_item_path assert not self.item_moved_to.exists() def test_move_missing_singleton_continues(self): self.i.load() old_path = self.i.filepath old_path.unlink() self.run_command("move") self.i.load() assert self.i.filepath == old_path def test_move_album_with_missing_track(self): self.i.load() old_i_path = self.i.filepath old_i_path.unlink() i2_path = self.lib_path / "srcfile2" shutil.copy(self.resource_path, i2_path) i2 = library.Item.from_path(i2_path) self.lib.add(i2) i2.album_id = self.album.id i2.store() self.run_command("move", "-a") self.i.load() i2.load() assert self.i.filepath == old_i_path assert i2.filepath.is_relative_to(self.lib_path) assert i2.filepath.exists() def test_move_item_skips_missing_file(self): self.i.load() old_path = self.i.filepath old_path.unlink() self.i.move() assert self.i.filepath == old_path beetbox-beets-00724b7/test/ui/commands/test_write.py0000664000175000017500000000224615253035401022017 0ustar pieterpieterfrom beets.test.helper import BeetsTestCase, IOMixin class WriteTest(IOMixin, BeetsTestCase): def write_cmd(self, *args): return self.run_with_output("write", *args) def test_update_mtime(self): item = self.add_item_fixture() item["title"] = "a new title" item.store() item = self.lib.items().get() assert item.mtime == 0 self.write_cmd() item = self.lib.items().get() assert item.mtime == item.current_mtime() def test_non_metadata_field_unchanged(self): """Changing a non-"tag" field like `bitrate` and writing should have no effect. """ # An item that starts out "clean". item = self.add_item_fixture() item.read() # ... but with a mismatched bitrate. item.bitrate = 123 item.store() output = self.write_cmd() assert output == "" def test_write_metadata_field(self): item = self.add_item_fixture() item.read() old_title = item.title item.title = "new title" item.store() output = self.write_cmd() assert f"{old_title} -> new title" in output beetbox-beets-00724b7/test/ui/commands/test_config.py0000664000175000017500000001134015253035401022125 0ustar pieterpieterimport os from pathlib import Path from unittest.mock import patch import pytest import yaml from beets import config from beets.exceptions import UserError from beets.test.helper import BeetsTestCase, IOMixin class ConfigCommandTest(IOMixin, BeetsTestCase): def setUp(self): super().setUp() for k in ("VISUAL", "EDITOR"): if k in os.environ: del os.environ[k] temp_dir = self.temp_path config_path = temp_dir / "config.yaml" lines = ["library: lib", "option: value", "password: password_value"] config_path.write_text("\n".join(lines)) self.config_path = str(config_path) cli_config_path = temp_dir / "cli_config.yaml" cli_config_path.write_text("option: cli overwrite") self.cli_config_path = str(cli_config_path) config.clear() config["password"].redact = True config._materialized = False def _run_with_yaml_output(self, *args): output = self.run_with_output(*args) return yaml.safe_load(output) def test_show_user_config(self): output = self._run_with_yaml_output("config", "-c") assert output["option"] == "value" assert output["password"] == "password_value" def test_show_user_config_with_defaults(self): output = self._run_with_yaml_output("config", "-dc") assert output["option"] == "value" assert output["password"] == "password_value" assert output["library"] == "lib" assert not output["import"]["timid"] def test_show_user_config_with_cli(self): output = self._run_with_yaml_output( "--config", self.cli_config_path, "config" ) assert output["library"] == "lib" assert output["option"] == "cli overwrite" def test_show_redacted_user_config(self): output = self._run_with_yaml_output("config") assert output["option"] == "value" assert output["password"] == "REDACTED" def test_show_redacted_user_config_with_defaults(self): output = self._run_with_yaml_output("config", "-d") assert output["option"] == "value" assert output["password"] == "REDACTED" assert not output["import"]["timid"] def test_config_paths(self): output = self.run_with_output("config", "-p") paths = output.split("\n") assert len(paths) == 2 assert paths[0] == self.config_path def test_config_paths_with_cli(self): output = self.run_with_output( "--config", self.cli_config_path, "config", "-p" ) paths = output.split("\n") assert len(paths) == 3 assert paths[0] == self.cli_config_path def test_edit_config_with_visual_or_editor_env(self): os.environ["EDITOR"] = "myeditor" with patch("os.execlp") as execlp: self.run_command("config", "-e") execlp.assert_called_once_with("myeditor", "myeditor", self.config_path) os.environ["VISUAL"] = "" # empty environment variables gets ignored with patch("os.execlp") as execlp: self.run_command("config", "-e") execlp.assert_called_once_with("myeditor", "myeditor", self.config_path) os.environ["VISUAL"] = "myvisual" with patch("os.execlp") as execlp: self.run_command("config", "-e") execlp.assert_called_once_with("myvisual", "myvisual", self.config_path) def test_edit_config_with_automatic_open(self): with patch("beets.util.open_anything") as open_: open_.return_value = "please_open" with patch("os.execlp") as execlp: self.run_command("config", "-e") execlp.assert_called_once_with( "please_open", "please_open", self.config_path ) def test_config_editor_not_found(self): msg_match = "Could not edit configuration.*here is problem" with ( patch("os.execlp", side_effect=OSError("here is problem")), pytest.raises(UserError, match=msg_match), ): self.run_command("config", "-e") def test_edit_invalid_config_file(self): Path(self.config_path).write_text("invalid: [") config.clear() config._materialized = False os.environ["EDITOR"] = "myeditor" with patch("os.execlp") as execlp: self.run_command("config", "-e") execlp.assert_called_once_with("myeditor", "myeditor", self.config_path) def test_edit_config_with_custom_config_path(self): os.environ["EDITOR"] = "myeditor" with patch("os.execlp") as execlp: self.run_command("--config", self.cli_config_path, "config", "-e") execlp.assert_called_once_with( "myeditor", "myeditor", self.cli_config_path ) beetbox-beets-00724b7/test/ui/commands/test_completion.py0000664000175000017500000000434615253035401023041 0ustar pieterpieterimport os import subprocess import sys from pathlib import Path import pytest from beets.test import _common from beets.test.helper import RUNNING_IN_CI, IOMixin, has_program from beets.ui.commands.completion import BASH_COMPLETION_PATHS from ..test_ui import TestPluginTestCase @pytest.mark.xfail( RUNNING_IN_CI and sys.platform == "linux", reason="Completion is for some reason unhappy on Ubuntu 24.04 in CI", ) class CompletionTest(IOMixin, TestPluginTestCase): def test_completion(self): # Do not load any other bash completion scripts on the system. env = dict(os.environ) env["BASH_COMPLETION_DIR"] = os.devnull env["BASH_COMPLETION_COMPAT_DIR"] = os.devnull # Open a `bash` process to run the tests in. We'll pipe in bash # commands via stdin. cmd = os.environ.get("BEETS_TEST_SHELL", "/bin/bash --norc").split() if not has_program(cmd[0]): self.skipTest("bash not available") tester = subprocess.Popen( cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=env ) # Load bash_completion library. completion_paths = map(Path, map(os.fsdecode, BASH_COMPLETION_PATHS)) for path in completion_paths: if path.exists(): bash_completion = path break else: self.skipTest("bash-completion script not found") try: with bash_completion.open("rb") as f: tester.stdin.writelines(f) except OSError: self.skipTest("could not read bash-completion script") # Load completion script. self.run_command("completion") completion_script = self.io.getoutput().encode("utf-8") tester.stdin.writelines(completion_script.splitlines(True)) # Load test suite. test_script_name = _common.RSRC / "test_completion.sh" with test_script_name.open("rb") as test_script_file: tester.stdin.writelines(test_script_file) out, _ = tester.communicate() assert tester.returncode == 0 assert out == b"completion tests passed\n", ( "test/test_completion.sh did not execute properly. " f"Output:{out.decode('utf-8')}" ) beetbox-beets-00724b7/test/ui/commands/test_fields.py0000664000175000017500000000064215253035401022131 0ustar pieterpieterfrom beets import library from beets.test.helper import IOMixin, ItemInDBTestCase class FieldsTest(IOMixin, ItemInDBTestCase): def test_fields_func(self): items = library.Item.all_keys() albums = library.Album.all_keys() output = set(self.run_with_output("fields").split()) items -= output albums -= output assert len(items) == 0 assert len(albums) == 0 beetbox-beets-00724b7/test/ui/commands/test_import.py0000664000175000017500000001570515253035401022203 0ustar pieterpieterimport os import unittest from unittest.mock import Mock, patch import pytest from beets import config, library from beets.autotag import AlbumInfo, AlbumMatch, Source, TrackInfo, distance from beets.exceptions import UserError from beets.test import _common from beets.test.helper import BeetsTestCase, IOMixin from beets.ui.commands.import_ import paths_from_logfile from beets.ui.commands.import_.display import show_change from beets.ui.commands.import_.session import summarize_items class ImportTest(BeetsTestCase): def test_quiet_timid_disallowed(self): config["import"]["quiet"] = True config["import"]["timid"] = True with pytest.raises(UserError): self.run_command("import") def test_parse_paths_from_logfile(self): if os.path.__name__ == "ntpath": logfile_content = ( "import started Wed Jun 15 23:08:26 2022\n" "asis C:\\music\\Beatles, The\\The Beatles; C:\\music\\Beatles, The\\The Beatles\\CD 01; C:\\music\\Beatles, The\\The Beatles\\CD 02\n" # noqa: E501 "duplicate-replace C:\\music\\Bill Evans\\Trio '65\n" "skip C:\\music\\Michael Jackson\\Bad\n" "skip C:\\music\\Soulwax\\Any Minute Now\n" ) expected_paths = [ "C:\\music\\Beatles, The\\The Beatles", "C:\\music\\Michael Jackson\\Bad", "C:\\music\\Soulwax\\Any Minute Now", ] else: logfile_content = ( "import started Wed Jun 15 23:08:26 2022\n" "asis /music/Beatles, The/The Beatles; /music/Beatles, The/The Beatles/CD 01; /music/Beatles, The/The Beatles/CD 02\n" # noqa: E501 "duplicate-replace /music/Bill Evans/Trio '65\n" "skip /music/Michael Jackson/Bad\n" "skip /music/Soulwax/Any Minute Now\n" ) expected_paths = [ "/music/Beatles, The/The Beatles", "/music/Michael Jackson/Bad", "/music/Soulwax/Any Minute Now", ] logfile = self.temp_path / "logfile.log" logfile.write_text(logfile_content) actual_paths = list(paths_from_logfile(logfile)) assert actual_paths == expected_paths @patch("beets.ui.term_width", Mock(return_value=54)) class ShowChangeTestCase(IOMixin, BeetsTestCase): def _show_change(self): """Return an unicode string representing the changes""" long_name = f"a{' very' * 10} long name" album = "another album" albumartist = f"another artist with {long_name}" def make_item(**kwargs): return _common.item(album=album, albumartist=albumartist, **kwargs) items = [ make_item(track=1, title="first title"), make_item(track=2, title="", path=b"/path/to/file.mp3"), make_item(track=3, title="caf\xe9"), make_item(track=4, title=f"title with {long_name}"), ] info = AlbumInfo( album="caf\xe9", album_id="album id", artist="the artist", artist_id="artist id", tracks=[ TrackInfo(title="first title", index=1), TrackInfo(title="second title", index=2), TrackInfo(title="third title", index=3), TrackInfo(title="fourth title", index=4), ], ) item_info_pairs = list(zip(items, info.tracks)) self.config["ui"]["color"] = False self.config["import"]["detail"] = True source = Source.from_items(items) change_dist = distance( source.data, info, item_info_pairs, len(items) - len(info.tracks) ) change_dist._penalties = {"album": [0.1], "artist": [0.1]} show_change( source, AlbumMatch(change_dist, info, dict(item_info_pairs)) ) return self.io.getoutput() def test_newline_layout(self): self.config["ui"]["import"]["layout"] = "newline" msg = self._show_change() assert ( msg == """ Match (90.0%): the artist - café ≠ album, artist None, None, None, None, None, None, None ≠ Artist: another artist with a very very very very very very very very very very long name -> the artist ≠ Album: another album -> café * (#1) first title (1:00) ≠ (#2) file.mp3 (1:00) -> (#2) second title (0:00) ≠ (#3) café (1:00) -> (#3) third title (0:00) ≠ (#4) title with a very very very very very very very very very very long name (1:00) -> (#4) fourth title (0:00) """ ) def test_column_layout(self): self.config["ui"]["import"]["layout"] = "column" msg = self._show_change() assert ( msg == """ Match (90.0%): the artist - café ≠ album, artist None, None, None, None, None, None, None ≠ Artist: another artist -> the artist with a very very very very very very very very very very long name ≠ Album: another album -> café * (#1) first title (1:00) ≠ (#2) file.mp (1:00) -> (#2) second (0:00) 3 title ≠ (#3) café (1:00) -> (#3) third title (0:00) ≠ (#4) title (1:00) -> (#4) fourth (0:00) with a very title very very very very very very very very very long name """ # noqa: W291 ) @patch("beets.library.Item.try_filesize", Mock(return_value=987)) class SummarizeItemsTest(unittest.TestCase): def setUp(self): super().setUp() item = library.Item() item.bitrate = 4321 item.length = 10 * 60 + 54 item.format = "F" self.item = item def test_summarize_item(self): summary = summarize_items([], True) assert summary == "" summary = summarize_items([self.item], True) assert summary == "F, 4kbps, 10:54, 987.0 B" def test_summarize_items(self): summary = summarize_items([], False) assert summary == "0 items" summary = summarize_items([self.item], False) assert summary == "1 items, F, 4kbps, 10:54, 987.0 B" # make a copy of self.item i2 = self.item.copy() summary = summarize_items([self.item, i2], False) assert summary == "2 items, F, 4kbps, 21:48, 1.9 KiB" i2.format = "G" summary = summarize_items([self.item, i2], False) assert summary == "2 items, F 1, G 1, 4kbps, 21:48, 1.9 KiB" summary = summarize_items([self.item, i2, i2], False) assert summary == "3 items, G 2, F 1, 4kbps, 32:42, 2.9 KiB" beetbox-beets-00724b7/test/ui/commands/__init__.py0000664000175000017500000000000015253035401021347 0ustar pieterpieterbeetbox-beets-00724b7/test/ui/commands/test_update.py0000664000175000017500000001543315253035401022151 0ustar pieterpieterimport mediafile from mediafile import MediaFile from beets import library from beets.plugins import BeetsPlugin from beets.test import _common from beets.test.helper import BeetsTestCase, IOMixin from beets.util import MoveOperation, remove class UpdateTest(IOMixin, BeetsTestCase): def setUp(self): super().setUp() # Copy a file into the library. item_path = _common.RSRC / "full.mp3" item_path_two = _common.RSRC / "full.flac" self.i = library.Item.from_path(item_path) self.i2 = library.Item.from_path(item_path_two) self.lib.add(self.i) self.lib.add(self.i2) self.i.move(operation=MoveOperation.COPY) self.i2.move(operation=MoveOperation.COPY) self.album = self.lib.add_album([self.i, self.i2]) # Album art. artfile = self.temp_path / "testart.jpg" artfile.touch() self.album.set_art(artfile) self.album.store() artfile.unlink() def _update(self, *args, reset_mtime=True): self.io.addinput("y") if reset_mtime: self.i.mtime = 0 self.i.store() self.run_command("update", *args) def test_delete_removes_item(self): assert list(self.lib.items()) remove(self.i.path) remove(self.i2.path) self._update() assert not list(self.lib.items()) def test_delete_removes_album(self): assert self.lib.albums() remove(self.i.path) remove(self.i2.path) self._update() assert not self.lib.albums() def test_delete_removes_album_art(self): art_filepath = self.album.art_filepath assert art_filepath.exists() remove(self.i.path) remove(self.i2.path) self._update() assert not art_filepath.exists() def test_modified_metadata_detected(self): mf = MediaFile(self.i.filepath) mf.title = "differentTitle" mf.save() self._update() item = self.lib.items().get() assert item.title == "differentTitle" def test_modified_plugin_media_field_detected(self): plugin = BeetsPlugin() plugin.add_media_field( "customtag", mediafile.MediaField( mediafile.MP3DescStorageStyle("customtag"), mediafile.StorageStyle("customtag"), ), ) try: mf = MediaFile(self.i.filepath) mf.customtag = "F#" mf.save() self._update() item = self.lib.get_item(self.i.id) assert item["customtag"] == "F#" finally: delattr(mediafile.MediaFile, "customtag") library.Item._media_fields.remove("customtag") def test_modified_metadata_moved(self): mf = MediaFile(self.i.filepath) mf.title = "differentTitle" mf.save() self._update("-m") item = self.lib.items().get() assert b"differentTitle" in item.path def test_modified_metadata_not_moved(self): mf = MediaFile(self.i.filepath) mf.title = "differentTitle" mf.save() self._update("--nomove") item = self.lib.items().get() assert b"differentTitle" not in item.path def test_selective_modified_metadata_moved(self): mf = MediaFile(self.i.filepath) mf.title = "differentTitle" mf.genres = ["differentGenre"] mf.save() self._update("-m", "--field=title") item = self.lib.items().get() assert b"differentTitle" in item.path assert item.genres != ["differentGenre"] def test_selective_modified_metadata_not_moved(self): mf = MediaFile(self.i.filepath) mf.title = "differentTitle" mf.genres = ["differentGenre"] mf.save() self._update("--nomove", "--field=title") item = self.lib.items().get() assert b"differentTitle" not in item.path assert item.genres != ["differentGenre"] def test_modified_album_metadata_moved(self): mf = MediaFile(self.i.filepath) mf.album = "differentAlbum" mf.save() self._update("-m") item = self.lib.items().get() assert b"differentAlbum" in item.path def test_modified_album_metadata_art_moved(self): artpath = self.album.artpath mf = MediaFile(self.i.filepath) mf.album = "differentAlbum" mf.save() self._update("-m") album = self.lib.albums()[0] assert artpath != album.artpath assert album.artpath is not None def test_selective_modified_album_metadata_moved(self): mf = MediaFile(self.i.filepath) mf.album = "differentAlbum" mf.genres = ["differentGenre"] mf.save() self._update("-m", "--field=album") item = self.lib.items().get() assert b"differentAlbum" in item.path assert item.genres != ["differentGenre"] def test_selective_modified_album_metadata_not_moved(self): mf = MediaFile(self.i.filepath) mf.album = "differentAlbum" mf.genres = ["differentGenre"] mf.save() self._update("-m", "--field=genres") item = self.lib.items().get() assert b"differentAlbum" not in item.path assert item.genres == ["differentGenre"] def test_mtime_match_skips_update(self): mf = MediaFile(self.i.filepath) mf.title = "differentTitle" mf.save() # Make in-memory mtime match on-disk mtime. self.i.mtime = self.i.filepath.stat().st_mtime self.i.store() self._update(reset_mtime=False) item = self.lib.items().get() assert item.title == "full" def test_multivalued_albumtype_roundtrip(self): # https://github.com/beetbox/beets/issues/4528 # albumtypes is empty for our test fixtures, so populate it first album = self.album correct_albumtypes = ["album", "live"] # Setting albumtypes does not set albumtype, currently. # Using x[0] mirrors https://github.com/beetbox/mediafile/blob/057432ad53b3b84385e5582f69f44dc00d0a725d/mediafile.py#L1928 # noqa: E501 correct_albumtype = correct_albumtypes[0] album.albumtype = correct_albumtype album.albumtypes = correct_albumtypes album.try_sync(write=True, move=False) album.load() assert album.albumtype == correct_albumtype assert album.albumtypes == correct_albumtypes self._update() album.load() assert album.albumtype == correct_albumtype assert album.albumtypes == correct_albumtypes def test_modified_metadata_excluded(self): mf = MediaFile(self.i.filepath) mf.lyrics = "new lyrics" mf.save() self._update("--exclude-field=lyrics") item = self.lib.items().get() assert item.lyrics != "new lyrics" beetbox-beets-00724b7/test/ui/commands/test_remove.py0000664000175000017500000000627415253035401022167 0ustar pieterpieterfrom beets import library from beets.test.helper import BeetsTestCase, IOMixin from beets.util import MoveOperation class RemoveTest(IOMixin, BeetsTestCase): def setUp(self): super().setUp() # Copy a file into the library. self.i = library.Item.from_path(self.resource_path) self.lib.add(self.i) self.i.move(operation=MoveOperation.COPY) def test_remove_items_no_delete(self): self.io.addinput("y") self.run_command("remove") items = self.lib.items() assert len(list(items)) == 0 assert self.i.filepath.exists() def test_remove_albums_no_delete(self): album = self.add_album_fixture(2) self.io.addinput("y") output = self.run_with_output("remove", "-a") items = self.lib.items(f"album:{album.album}") assert len(list(items)) == 0 assert "Really remove 2 items and 1 album from the library?" in output def test_remove_items_with_delete(self): self.io.addinput("y") self.run_command("remove", "-d") items = self.lib.items() assert len(list(items)) == 0 assert not self.i.filepath.exists() def test_remove_items_with_force_no_delete(self): self.run_command("remove", "-f") items = self.lib.items() assert len(list(items)) == 0 assert self.i.filepath.exists() def test_remove_items_with_force_delete(self): self.run_command("remove", "-d", "-f") items = self.lib.items() assert len(list(items)) == 0 assert not self.i.filepath.exists() def test_remove_items_select_with_delete(self): i2 = library.Item.from_path(self.resource_path) self.lib.add(i2) i2.move(operation=MoveOperation.COPY) for s in ("s", "y", "n"): self.io.addinput(s) output = self.run_with_output("remove", "-d") assert "Really DELETE 2 files?" in output items = self.lib.items() assert len(list(items)) == 1 # There is probably no guarantee that the items are queried in any # spcecific order, thus just ensure that exactly one was removed. # To improve upon this, self.io would need to have the capability to # generate input that depends on previous output. num_existing = 0 num_existing += 1 if self.i.filepath.exists() else 0 num_existing += 1 if i2.filepath.exists() else 0 assert num_existing == 1 def test_remove_albums_select_with_delete(self): a1 = self.add_album_fixture() a2 = self.add_album_fixture() path1 = a1.items()[0].filepath path2 = a2.items()[0].filepath items = self.lib.items() assert len(list(items)) == 3 for s in ("s", "y", "n"): self.io.addinput(s) output = self.run_with_output("remove", "-d", "-a") assert "Really DELETE 2 files and 2 albums?" in output items = self.lib.items() assert len(list(items)) == 2 # incl. the item from setUp() # See test_remove_items_select_with_delete() num_existing = 0 num_existing += 1 if path1.exists() else 0 num_existing += 1 if path2.exists() else 0 assert num_existing == 1 beetbox-beets-00724b7/test/ui/commands/test_list.py0000664000175000017500000000621615253035401021641 0ustar pieterpieterimport os import pytest from beets.exceptions import UserError from beets.test import _common from beets.test.helper import BeetsTestCase, IOMixin class ListTest(IOMixin, BeetsTestCase): def setUp(self): super().setUp() self.item = _common.item( path=os.fsencode(self.lib_path / "xxx/yyy"), flex=1 ) self.lib.add(self.item) self.lib.add_album([self.item]) self.another_item = _common.item( path=os.fsencode(self.lib_path / "another/path"), flex=2 ) self.lib.add(self.another_item) def test_list_outputs_item(self): stdout = self.run_with_output("list") assert "the title" in stdout def test_list_unicode_query(self): self.item.title = "na\xefve" self.item.store() self.lib._connection().commit() stdout = self.run_with_output("list", "na\xefve") out = stdout assert "na\xefve" in out def test_list_item_path(self): stdout = self.run_with_output("list", "flex:1", "-f", "$path") assert stdout.strip() == str(self.lib_path / "xxx/yyy") def test_list_album_outputs_something(self): stdout = self.run_with_output("list", "-a") assert len(stdout) > 0 def test_list_album_path(self): stdout = self.run_with_output("list", "-a", "-f", "$path") assert stdout.strip() == str(self.lib_path / "xxx") def test_list_album_omits_title(self): stdout = self.run_with_output("list", "-a") assert "the title" not in stdout def test_list_uses_track_artist(self): stdout = self.run_with_output("list") assert "the artist" in stdout assert "the album artist" not in stdout def test_list_album_uses_album_artist(self): stdout = self.run_with_output("list", "-a") assert "the artist" not in stdout assert "the album artist" in stdout def test_list_item_format_artist(self): stdout = self.run_with_output("list", "-f", "$artist") assert "the artist" in stdout def test_list_item_format_multiple(self): stdout = self.run_with_output( "list", "flex:1", "-f", "$artist - $album - $year" ) assert stdout.strip() == "the artist - the album - 0001" def test_list_album_format(self): stdout = self.run_with_output("list", "-a", "-f", "$genres") assert "the genre" in stdout assert "the album" not in stdout def test_limit_query_results(self): args = "list", "-p" stdout = self.run_with_output(*args).strip() assert len(stdout.splitlines()) == 2 stdout = self.run_with_output(*args, "-l", "1").strip() assert len(stdout.splitlines()) == 1 with pytest.raises(UserError, match="must be a non-negative integer"): self.run_with_output(*args, "-l", "-1") def test_limit_sort_by_flex_attr(self): args = "list", "-p", "-l", "1" stdout = self.run_with_output(*args, "flex+").strip() assert stdout == os.fsdecode(self.item.path) stdout = self.run_with_output(*args, "flex-").strip() assert stdout == os.fsdecode(self.another_item.path) beetbox-beets-00724b7/test/ui/commands/test_modify.py0000664000175000017500000002552315253035401022157 0ustar pieterpieterimport re import pytest from mediafile import MediaFile from beets import logging from beets.exceptions import UserError from beets.test.helper import BeetsTestCase, IOMixin, TestHelper from beets.ui.commands.modify import ModifyOperation, modify_parse_args _p = pytest.param class ModifyHelper(IOMixin): def modify_inp(self, inp: list[str], *args): for chat in inp: self.io.addinput(chat) self.run_command("modify", *args) def modify(self, *args): self.modify_inp(["y"], *args) class ModifyTest(ModifyHelper, BeetsTestCase): def setUp(self): super().setUp() self.album = self.add_album_fixture() [self.item] = self.album.items() # Item tests def test_modify_item(self): self.modify("title=newTitle") item = self.lib.items().get() assert item.title == "newTitle" def test_modify_item_abort(self): item = self.lib.items().get() title = item.title self.modify_inp(["n"], "title=newTitle") item = self.lib.items().get() assert item.title == title def test_modify_item_no_change(self): title = "Tracktitle" item = self.add_item_fixture(title=title) self.modify_inp(["y"], "title", f"title={title}") item = self.lib.items(title).get() assert item.title == title def test_modify_write_tags(self): self.modify("title=newTitle") item = self.lib.items().get() item.read() assert item.title == "newTitle" def test_modify_dont_write_tags(self): self.modify("--nowrite", "title=newTitle") item = self.lib.items().get() item.read() assert item.title != "newTitle" def test_move(self): self.modify("title=newTitle") item = self.lib.items().get() assert b"newTitle" in item.path def test_not_move(self): self.modify("--nomove", "title=newTitle") item = self.lib.items().get() assert b"newTitle" not in item.path def test_no_write_no_move(self): self.modify("--nomove", "--nowrite", "title=newTitle") item = self.lib.items().get() item.read() assert b"newTitle" not in item.path assert item.title != "newTitle" def test_update_mtime(self): item = self.item old_mtime = item.mtime self.modify("title=newTitle") item.load() assert old_mtime != item.mtime assert item.current_mtime() == item.mtime def test_reset_mtime_with_no_write(self): item = self.item self.modify("--nowrite", "title=newTitle") item.load() assert 0 == item.mtime def test_selective_modify(self): title = "Tracktitle" album = "album" original_artist = "composer" new_artist = "coverArtist" for i in range(10): self.add_item_fixture( title=f"{title}{i}", artist=original_artist, album=album ) self.modify_inp( ["s", "y", "y", "y", "n", "n", "y", "y", "y", "y", "n"], title, f"artist={new_artist}", ) original_items = self.lib.items(f"artist:{original_artist}") new_items = self.lib.items(f"artist:{new_artist}") assert len(list(original_items)) == 3 assert len(list(new_items)) == 7 def test_selective_modify_output(self): """Test that the output shows the correct changes. See #4880 where attempts to modify 'added' field resulted in TypeError. Modifying simple fields, like 'artist' resulted in the following output: $ beet modify artist:OLD artist=NEW artist: OLD -> ModifyOperation(operator=None, value='NEW') """ self.io.addinput("s") # select self.io.addinput("y") # yes new_added = "2020-01-01 00:00:00" pattern = re.compile(rf"added: .* -> {new_added}") output = self.run_with_output("modify", f"added={new_added}") # we expect to see this printed twice assert len(pattern.findall(output)) == 2 def test_modify_formatted(self): for i in range(3): self.add_item_fixture( title=f"title{i}", artist="artist", album="album" ) items = list(self.lib.items()) self.modify("title=${title} - append") for item in items: orig_title = item.title item.load() assert item.title == f"{orig_title} - append" # Album Tests def test_modify_album(self): self.modify("--album", "album=newAlbum") album = self.lib.albums().get() assert album.album == "newAlbum" def test_modify_album_write_tags(self): self.modify("--album", "album=newAlbum") item = self.lib.items().get() item.read() assert item.album == "newAlbum" def test_modify_album_dont_write_tags(self): self.modify("--album", "--nowrite", "album=newAlbum") item = self.lib.items().get() item.read() assert item.album == "the album" def test_album_move(self): self.modify("--album", "album=newAlbum") item = self.lib.items().get() item.read() assert b"newAlbum" in item.path def test_album_not_move(self): self.modify("--nomove", "--album", "album=newAlbum") item = self.lib.items().get() item.read() assert b"newAlbum" not in item.path def test_modify_album_formatted(self): item = self.lib.items().get() orig_album = item.album self.modify("--album", "album=${album} - append") item.load() assert item.album == f"{orig_album} - append" def test_album_modify_artists_not_split(self): self.modify("--album", "artists=Charli XCX") for item in self.lib.items(): assert item.artists == ["Charli XCX"], ( f"artists should be a list with one element, " f"got {item.artists!r}" ) def test_album_modify_genres_not_split(self): self.modify("--album", "genres=Rock") for item in self.lib.items(): assert item.genres == ["Rock"], ( f"genres should be a list with one element, got {item.genres!r}" ) # Misc def test_write_initial_key_tag(self): self.modify("initial_key=C#m") item = self.lib.items().get() mediafile = MediaFile(item.filepath) assert mediafile.initial_key == "C#m" def test_set_flexattr(self): self.modify("flexattr=testAttr") item = self.lib.items().get() assert item.flexattr == "testAttr" def test_remove_flexattr(self): item = self.lib.items().get() item.flexattr = "testAttr" item.store() self.modify("flexattr!") item = self.lib.items().get() assert "flexattr" not in item def test_delete_initial_key_tag(self): item = self.add_item_fixture() item.initial_key = "C#m" item.write() item.store() mediafile = MediaFile(item.filepath) assert mediafile.initial_key == "C#m" self.modify("initial_key!") mediafile = MediaFile(item.filepath) assert mediafile.initial_key is None def test_arg_parsing_colon_query(self): query, mods, _ = modify_parse_args( ["title:oldTitle", "title=newTitle"], is_album=False ) assert query == ["title:oldTitle"] assert mods == {"title": ModifyOperation(None, "newTitle")} def test_arg_parsing_delete(self): query, _, dels = modify_parse_args( ["title:oldTitle", "title!"], is_album=False ) assert query == ["title:oldTitle"] assert dels == ["title"] def test_arg_parsing_query_with_exclaimation(self): query, mods, _ = modify_parse_args( ["title:oldTitle!", "title=newTitle!"], is_album=False ) assert query == ["title:oldTitle!"] assert mods == {"title": ModifyOperation(None, "newTitle!")} def test_arg_parsing_equals_in_value(self): query, mods, _ = modify_parse_args( ["title:foo=bar", "title=newTitle"], is_album=False ) assert query == ["title:foo=bar"] assert mods == {"title": ModifyOperation(None, "newTitle")} class TestMultiValue(ModifyHelper, TestHelper): @pytest.fixture def item(self): album = self.add_album_fixture() [item] = album.items() return item @pytest.mark.parametrize( "initial_genres, modify_arg, expected_genres", [ _p([], "genres=Jazz; Blues", ["Jazz", "Blues"], id="assign"), _p( ["Jazz", "Blues"], "genres+=Funk", ["Jazz", "Blues", "Funk"], id="append", ), _p( ["Jazz", "Funk"], "genres+=Funk", ["Jazz", "Funk"], id="append-duplicate", ), _p( ["Jazz", "Blues", "Funk"], "genres-=Blues", ["Jazz", "Funk"], id="remove-exact", ), _p( ["Jazz", "Blues Rock", "Blues"], "genres-=Blues", ["Jazz", "Blues Rock"], id="remove-no-partial-match", ), _p( ["Jazz", "Blues"], "genres+=Funk; Soul", ["Jazz", "Blues", "Funk", "Soul"], id="append-preserves-order", ), ], ) def test_modify_multi_value( self, item, initial_genres, modify_arg, expected_genres ): item.genres = initial_genres item.store() self.modify("--nowrite", "--nomove", modify_arg) item.load() assert item.genres == expected_genres def test_modify_scalar_operator_error(self): with pytest.raises(UserError, match="field 'title' does not support"): self.modify("--nowrite", "--nomove", "title+=foo") @pytest.mark.parametrize( "is_album, legacy_field, list_field", [ _p(True, "genre", "genres", id="album-genre"), _p(False, "genre", "genres", id="item-genre"), _p(False, "composer", "composers", id="item-composer"), ], ) def test_arg_parsing_rewrites_legacy_list_fields( is_album, legacy_field, list_field, caplog ): with caplog.at_level(logging.WARNING, logger="beets"): query, mods, dels = modify_parse_args( [f"{legacy_field}=value1; value2"], is_album=is_album ) assert query == [] assert mods == {list_field: ModifyOperation(None, "value1; value2")} assert dels == [] assert caplog.records, "No log records were captured" assert len(caplog.records) == 1 message = str(caplog.records[0].msg) assert f"The '{legacy_field}' field is deprecated" in message assert f"Use '{list_field}' (separate values by '; ') instead." in message beetbox-beets-00724b7/test/plugins/0000775000175000017500000000000015253035401016513 5ustar pieterpieterbeetbox-beets-00724b7/test/plugins/test_deezer.py0000664000175000017500000001337015253035401021406 0ustar pieterpieterfrom typing import Any import pytest from beets.library import Item from beetsplug.deezer import DeezerPlugin JSONDict = dict[str, Any] @pytest.fixture def plugin(): return DeezerPlugin() class TestSearchQuery: def test_track_query_is_free_text(self, plugin): query, filters = plugin.get_search_query_with_filters( "track", [Item()], "Artist", "Title", False ) assert query == "Title Artist" assert filters == {} def test_track_query_tolerates_missing_artist(self, plugin): query, _ = plugin.get_search_query_with_filters( "track", [Item()], "", "Title", False ) assert query == "Title" def test_album_query_filters_on_album_and_artist(self, plugin): query, filters = plugin.get_search_query_with_filters( "album", [Item()], "Artist", "Album", False ) assert query == 'album:"Album" artist:"Artist"' assert filters == {} def test_album_query_omits_artist_for_various_artists(self, plugin): query, _ = plugin.get_search_query_with_filters( "album", [Item()], "Various Artists", "Album", True ) assert query == 'album:"Album"' def make_track(artist_id: int, position: int) -> JSONDict: """Build a minimal Deezer track payload credited to ``artist_id``.""" return { "title": f"Track {position}", "id": 1000 + position, "link": f"https://www.deezer.com/track/{1000 + position}", "duration": 200, "track_position": position, "disk_number": 1, "artist": {"id": artist_id, "name": f"Artist {artist_id}"}, } class TestGetTrack: def track_data(self, **fields): return { "id": 1, "title": "Title", "duration": 100, "link": "https://www.deezer.com/track/1", **fields, } def test_uses_contributors_when_artist_is_missing(self, plugin): track = plugin._get_track( self.track_data(contributors=[{"id": 2, "name": "Artist"}]) ) assert track.artist == "Artist" assert track.artist_id == "2" def test_falls_back_to_artist_without_contributors(self, plugin): track = plugin._get_track( self.track_data(artist={"id": 2, "name": "Artist"}) ) assert track.artist == "Artist" assert track.artist_id == "2" def test_tolerates_missing_artist_and_contributors(self, plugin): track = plugin._get_track(self.track_data()) assert track.artist is None assert track.artist_id is None class TestVariousArtistsDetection: def make_album( self, album_artist_id: int, contributor_ids: list[int] ) -> JSONDict: """Build a minimal Deezer album payload.""" return { "title": "Some Album", "link": "https://www.deezer.com/album/1", "record_type": "album", "label": "Some Label", "release_date": "2017-01-01", "artist": { "id": album_artist_id, "name": f"Artist {album_artist_id}", }, "contributors": [ {"id": aid, "name": f"Artist {aid}"} for aid in contributor_ids ], "cover_xl": None, } def mock_album( self, requests_mock, album_artist_id, track_artist_ids, contributor_ids=None, ): """Mock the album and album-tracks endpoints for album id 1. ``contributor_ids`` overrides the album-level contributors, which otherwise cover every artist involved. """ if contributor_ids is None: contributor_ids = list( dict.fromkeys([album_artist_id, *track_artist_ids]) ) requests_mock.get( f"{DeezerPlugin.album_url}1", json=self.make_album(album_artist_id, contributor_ids), ) requests_mock.get( f"{DeezerPlugin.album_url}1/tracks", json={ "data": [ make_track(aid, i) for i, aid in enumerate(track_artist_ids, start=1) ] }, ) def test_compilation_with_non_va_album_artist(self, plugin, requests_mock): # Album credited to a single "main" artist that performs on only one # of many tracks: this is a compilation and should be flagged as VA. self.mock_album( requests_mock, album_artist_id=100, track_artist_ids=[100, 200, 300, 400, 500, 600], ) album_info = plugin.album_for_id("1") assert album_info is not None assert album_info.va is True assert album_info.artist == "Various Artists" def test_plurality_artist_album_not_va(self, plugin, requests_mock): # Album whose main artist performs on 2 of 5 tracks (40%) is above # the importer's single-artist threshold and stays single-artist. self.mock_album( requests_mock, album_artist_id=100, track_artist_ids=[100, 100, 200, 300, 400], contributor_ids=[100], ) album_info = plugin.album_for_id("1") assert album_info is not None assert album_info.va is False assert album_info.artist == "Artist 100" def test_single_artist_album_not_va(self, plugin, requests_mock): # Album whose main artist performs on every track is not a compilation. self.mock_album( requests_mock, album_artist_id=100, track_artist_ids=[100, 100, 100, 100], ) album_info = plugin.album_for_id("1") assert album_info is not None assert album_info.va is False assert album_info.artist == "Artist 100" beetbox-beets-00724b7/test/plugins/test_albumtypes.py0000664000175000017500000000623015253035401022312 0ustar pieterpieter"""Tests for the 'albumtypes' plugin.""" from __future__ import annotations from typing import TYPE_CHECKING from beets.test.helper import PluginTestCase from beetsplug.albumtypes import AlbumTypesPlugin from beetsplug.musicbrainz import VARIOUS_ARTISTS_ID if TYPE_CHECKING: from collections.abc import Sequence class AlbumTypesPluginTest(PluginTestCase): """Tests for albumtypes plugin.""" plugin = "albumtypes" def test_renames_types(self): """Tests if the plugin correctly renames the specified types.""" self._set_config( types=[("ep", "EP"), ("remix", "Remix")], ignore_va=[], bracket="()" ) album = self._create_album(album_types=["ep", "remix"]) subject = AlbumTypesPlugin() result = subject._atypes(album) assert "(EP)(Remix)" == result return def test_returns_only_specified_types(self): """Tests if the plugin returns only non-blank types given in config.""" self._set_config( types=[("ep", "EP"), ("soundtrack", "")], ignore_va=[], bracket="()" ) album = self._create_album(album_types=["ep", "remix", "soundtrack"]) subject = AlbumTypesPlugin() result = subject._atypes(album) assert "(EP)" == result def test_respects_type_order(self): """Tests if the types are returned in the same order as config.""" self._set_config( types=[("remix", "Remix"), ("ep", "EP")], ignore_va=[], bracket="()" ) album = self._create_album(album_types=["ep", "remix"]) subject = AlbumTypesPlugin() result = subject._atypes(album) assert "(Remix)(EP)" == result return def test_ignores_va(self): """Tests if the specified type is ignored for VA albums.""" self._set_config( types=[("ep", "EP"), ("soundtrack", "OST")], ignore_va=["ep"], bracket="()", ) album = self._create_album( album_types=["ep", "soundtrack"], artist_id=VARIOUS_ARTISTS_ID ) subject = AlbumTypesPlugin() result = subject._atypes(album) assert "(OST)" == result def test_respects_defaults(self): """Tests if the plugin uses the default values if config not given.""" album = self._create_album( album_types=[ "ep", "single", "soundtrack", "live", "compilation", "remix", ], artist_id=VARIOUS_ARTISTS_ID, ) subject = AlbumTypesPlugin() result = subject._atypes(album) assert "[EP][Single][OST][Live][Remix]" == result def _set_config( self, types: Sequence[tuple[str, str]], ignore_va: Sequence[str], bracket: str, ): self.config["albumtypes"]["types"] = types self.config["albumtypes"]["ignore_va"] = ignore_va self.config["albumtypes"]["bracket"] = bracket def _create_album(self, album_types: Sequence[str], artist_id: str = "0"): return self.add_album( albumtypes=album_types, mb_albumartistid=artist_id ) beetbox-beets-00724b7/test/plugins/test_titlecase.py0000664000175000017500000003331115253035401022102 0ustar pieterpieter"""Tests for the 'titlecase' plugin""" from unittest.mock import patch from beets.autotag import AlbumInfo, TrackInfo from beets.importer import ImportSession, ImportTask from beets.library import Item from beets.test.helper import PluginTestCase from beetsplug.titlecase import TitlecasePlugin class TestTitlecasePlugin(PluginTestCase): plugin = "titlecase" preload_plugin = False def test_auto(self): """Ensure automatic processing gets assigned""" with self.configure_plugin({"auto": True, "after_choice": True}): assert callable(TitlecasePlugin().import_stages[0]) with self.configure_plugin({"auto": False, "after_choice": False}): assert len(TitlecasePlugin().import_stages) == 0 with self.configure_plugin({"auto": False, "after_choice": True}): assert len(TitlecasePlugin().import_stages) == 0 def test_basic_titlecase(self): """Check that default behavior is as expected.""" testcases = [ ("a", "A"), ("PENDULUM", "Pendulum"), ("Aaron-carl", "Aaron-Carl"), ("LTJ bukem", "LTJ Bukem"), ("(original mix)", "(Original Mix)"), ("ALL CAPS TITLE", "All Caps Title"), ] for testcase in testcases: given, expected = testcase assert TitlecasePlugin().titlecase(given) == expected def test_small_first_last(self): """Check the behavior for supporting small first last""" testcases = [ (True, "In a Silent Way", "In a Silent Way"), (False, "In a Silent Way", "in a Silent Way"), ] for testcase in testcases: sfl, given, expected = testcase cfg = {"small_first_last": sfl} with self.configure_plugin(cfg): assert TitlecasePlugin().titlecase(given) == expected def test_preserve(self): """Test using given strings to preserve case""" preserve_list = [ "easyFun", "A.D.O.R", "D'Angelo", "ABBA", "LaTeX", "O.R.B", "PinkPantheress", "THE PSYCHIC ED RUSH", "LTJ Bukem", ] for word in preserve_list: with self.configure_plugin({"preserve": preserve_list}): assert TitlecasePlugin().titlecase(word.upper()) == word assert TitlecasePlugin().titlecase(word.lower()) == word def test_separators(self): testcases = [ ([], "it / a / in / of / to / the", "It / a / in / of / to / The"), (["/"], "it / the test", "It / The Test"), ( ["/"], "it / a / in / of / to / the", "It / A / In / Of / To / The", ), (["/"], "//it/a/in/of/to/the", "//It/A/In/Of/To/The"), ( ["/", ";", "|"], "it ; a / in | of / to | the", "It ; A / In | Of / To | The", ), ] for testcase in testcases: separators, given, expected = testcase with self.configure_plugin({"separators": separators}): assert TitlecasePlugin().titlecase(given) == expected def test_all_caps(self): testcases = [ (True, "Unaffected", "Unaffected"), (True, "RBMK1000", "RBMK1000"), (False, "RBMK1000", "Rbmk1000"), (True, "P A R I S!", "P A R I S!"), (True, "pillow dub...", "Pillow Dub..."), (False, "P A R I S!", "P a R I S!"), ] for testcase in testcases: all_caps, given, expected = testcase with self.configure_plugin({"all_caps": all_caps}): assert TitlecasePlugin().titlecase(given) == expected def test_all_lowercase(self): testcases = [ (True, "Unaffected", "Unaffected"), (True, "RBMK1000", "Rbmk1000"), (True, "pillow dub...", "pillow dub..."), (False, "pillow dub...", "Pillow Dub..."), ] for testcase in testcases: all_lowercase, given, expected = testcase with self.configure_plugin({"all_lowercase": all_lowercase}): assert TitlecasePlugin().titlecase(given) == expected def test_received_info_handler(self): testcases = [ ( TrackInfo( album="test album", artist_credit="test artist credit", artists=["artist one", "artist two"], ), TrackInfo( album="Test Album", artist_credit="Test Artist Credit", artists=["Artist One", "Artist Two"], ), ), ( AlbumInfo( tracks=[ TrackInfo( album="test album", artist_credit="test artist credit", artists=["artist one", "artist two"], ) ], album="test album", artist_credit="test artist credit", artists=["artist one", "artist two"], ), AlbumInfo( tracks=[ TrackInfo( album="Test Album", artist_credit="Test Artist Credit", artists=["Artist One", "Artist Two"], ) ], album="Test Album", artist_credit="Test Artist Credit", artists=["Artist One", "Artist Two"], ), ), ] cfg = {"fields": ["album", "artist_credit", "artists"]} for testcase in testcases: given, expected = testcase with self.configure_plugin(cfg): TitlecasePlugin().received_info_handler(given) assert given == expected def test_titlecase_fields(self): testcases = [ # Test with preserve, replace, and mb_albumid # Test with the_artist ( { "preserve": ["D'Angelo"], "replace": [("’", "'")], "fields": ["artist", "albumartist", "mb_albumid"], }, Item( artist="d’angelo and the vanguard", mb_albumid="ab140e13-7b36-402a-a528-b69e3dee38a8", albumartist="d’angelo", format="CD", album="the black messiah", title="Till It's Done (Tutu)", ), Item( artist="D'Angelo and The Vanguard", mb_albumid="Ab140e13-7b36-402a-A528-B69e3dee38a8", albumartist="D'Angelo", format="CD", album="the black messiah", title="Till It's Done (Tutu)", ), ), # Test with force_lowercase, preserve, and an incorrect field ( { "force_lowercase": True, "fields": [ "artist", "albumartist", "format", "title", "year", "label", "format", "INCORRECT_FIELD", ], "preserve": ["CD"], }, Item( artist="OPHIDIAN", albumartist="OphiDIAN", format="cd", year=2003, album="BLACKBOX", title="KhAmElEoN", label="enzyme records", ), Item( artist="Ophidian", albumartist="Ophidian", format="CD", year=2003, album="Blackbox", title="Khameleon", label="Enzyme Records", ), ), # Test with no changes ( { "fields": [ "artist", "artists", "albumartist", "format", "title", "year", "label", "format", "INCORRECT_FIELD", ], "preserve": ["CD"], }, Item( artist="Ophidian", artists=["Ophidian"], albumartist="Ophidian", format="CD", year=2003, album="Blackbox", title="Khameleon", label="Enzyme Records", ), Item( artist="Ophidian", artists=["Ophidian"], albumartist="Ophidian", format="CD", year=2003, album="Blackbox", title="Khameleon", label="Enzyme Records", ), ), # Test with the_artist disabled ( {"the_artist": False, "fields": ["artist", "artists_sort"]}, Item(artists_sort=["b-52s, the"], artist="a day in the park"), Item(artists_sort=["B-52s, The"], artist="A Day in the Park"), ), # Test to make sure preserve and the_artist # dont target the middle of sentences # show that The artist applies to any field # with artist mentioned ( { "preserve": ["PANTHER"], "fields": ["artist", "artists", "artists_ids"], }, Item( artist="pinkpantheress", artists=["pinkpantheress", "artist_two"], artists_ids=["the the", "the the"], ), Item( artist="Pinkpantheress", artists=["Pinkpantheress", "Artist_two"], artists_ids=["The The", "The The"], ), ), ] for testcase in testcases: cfg, given, expected = testcase with self.configure_plugin(cfg): TitlecasePlugin().titlecase_fields(given) assert given.artist == expected.artist assert given.artists == expected.artists assert given.artists_sort == expected.artists_sort assert given.albumartist == expected.albumartist assert given.artists_ids == expected.artists_ids assert given.format == expected.format assert given.year == expected.year assert given.title == expected.title assert given.label == expected.label def test_cli_write(self): given = Item( album="retrodelica 2: back 2 the future", artist="blue planet corporation", title="generator", ) expected = Item( album="Retrodelica 2: Back 2 the Future", artist="Blue Planet Corporation", title="Generator", ) cfg = {"fields": ["album", "artist", "title"]} with self.configure_plugin(cfg): given.add(self.lib) self.run_command("titlecase") assert self.lib.items().get().artist == expected.artist assert self.lib.items().get().album == expected.album assert self.lib.items().get().title == expected.title self.lib.items().get().remove() def test_cli_no_write(self): given = Item( album="retrodelica 2: back 2 the future", artist="blue planet corporation", title="generator", ) expected = Item( album="retrodelica 2: back 2 the future", artist="blue planet corporation", title="generator", ) cfg = {"fields": ["album", "artist", "title"]} with self.configure_plugin(cfg): given.add(self.lib) self.run_command("-p", "titlecase") assert self.lib.items().get().artist == expected.artist assert self.lib.items().get().album == expected.album assert self.lib.items().get().title == expected.title self.lib.items().get().remove() def test_imported(self): given = Item( album="retrodelica 2: back 2 the future", artist="blue planet corporation", title="generator", ) expected = Item( album="Retrodelica 2: Back 2 the Future", artist="Blue Planet Corporation", title="Generator", ) p = patch("beets.importer.ImportTask.imported_items", lambda x: [given]) p.start() with self.configure_plugin({"fields": ["album", "artist", "title"]}): import_session = ImportSession( self.lib, loghandler=None, paths=None, query=None ) import_task = ImportTask(toppath=None, paths=None, items=[given]) TitlecasePlugin().imported(import_session, import_task) import_task.add(self.lib) item = self.lib.items().get() assert item.artist == expected.artist assert item.album == expected.album assert item.title == expected.title p.stop() beetbox-beets-00724b7/test/plugins/test_substitute.py0000664000175000017500000000367015253035401022345 0ustar pieterpieter"""Test the substitute plugin regex functionality.""" from beets.test.helper import PluginTestHelper from beetsplug.substitute import Substitute class TestSubstitutePlugin(PluginTestHelper): plugin = "substitute" preload_plugin = False def run_substitute(self, config, cases): with self.configure_plugin(config): for input_, expected in cases: assert Substitute().tmpl_substitute(input_) == expected def test_simple_substitute(self): self.run_substitute( {"a": "x", "b": "y", "c": "z"}, [("a", "x"), ("b", "y"), ("c", "z")] ) def test_case_insensitivity(self): self.run_substitute({"a": "x"}, [("A", "x")]) def test_unmatched_input_preserved(self): self.run_substitute({"a": "x"}, [("c", "c")]) def test_regex_to_static(self): self.run_substitute( {".*jimi hendrix.*": "Jimi Hendrix"}, [("The Jimi Hendrix Experience", "Jimi Hendrix")], ) def test_regex_capture_group(self): self.run_substitute( {"^(.*?)(,| &| and).*": r"\1"}, [ ("King Creosote & Jon Hopkins", "King Creosote"), ( ( "Michael Hurley, The Holy Modal Rounders, Jeffrey" " Frederick & The Clamtones" ), "Michael Hurley", ), ("James Yorkston and the Athletes", "James Yorkston"), ], ) def test_partial_substitution(self): self.run_substitute({r"\.": ""}, [("U.N.P.O.C.", "UNPOC")]) def test_rules_applied_in_definition_order(self): self.run_substitute( {"a": "x", "[ab]": "y", "b": "z"}, [("a", "x"), ("b", "y")] ) def test_rules_applied_in_sequence(self): self.run_substitute( {"a": "b", "b": "c", "d": "a"}, [("a", "c"), ("b", "c"), ("d", "a")] ) beetbox-beets-00724b7/test/plugins/test_chroma.py0000664000175000017500000001311215253035401021373 0ustar pieterpieterfrom unittest.mock import MagicMock, patch import pytest from beets import metadata_plugins from beets.autotag import AlbumInfo, TrackInfo from beets.library import Item from beets.test.helper import ImportHelper, IOMixin, PluginMixin chroma = pytest.importorskip("beetsplug.chroma", exc_type=ImportError) TEST_TITLE_1 = "TEST_TITLE_1" TEST_TITLE_2 = "TEST_TITLE_2" FINGERPRINT_1 = "FP_1" FINGERPRINT_1_CLOSE = "FP_1_CLOSE" FINGERPRINT_2 = "FP_2" @patch("acoustid.compare_fingerprints") class TestChroma(IOMixin, PluginMixin, ImportHelper): plugin = "chroma" def setup_lib(self): item1 = Item(path="/file") item1.length = 30 item1.title = TEST_TITLE_1 item1.acoustid_fingerprint = FINGERPRINT_1 item1.add(self.lib) item2 = Item(path="/file") item2.length = 30 item2.title = TEST_TITLE_2 item2.acoustid_fingerprint = FINGERPRINT_2 item2.add(self.lib) def run_search(self, fp): return self.run_with_output("chromasearch", "-s", fp, "-f", "$title") def line_count(self, str_): return len( [line for line in str_.split("\n") if line.strip(" \n") != ""] ) def compare_fingerprints(self, *args, **kwargs): if args[0][1] == args[1][1]: return 1 if args[0][1] == FINGERPRINT_1_CLOSE and args[1][1] == FINGERPRINT_1: return 0.9 return 0.1 def test_chroma_search_exact(self, compare_fingerprints): self.setup_lib() compare_fingerprints.side_effect = self.compare_fingerprints output = self.run_search(FINGERPRINT_2) assert self.line_count(output) == 1 assert TEST_TITLE_2 in output output = self.run_search(FINGERPRINT_1) assert self.line_count(output) == 1 assert TEST_TITLE_1 in output def test_chroma_search_close(self, compare_fingerprints): self.setup_lib() compare_fingerprints.side_effect = self.compare_fingerprints output = self.run_search(FINGERPRINT_1_CLOSE) assert self.line_count(output) == 2 assert TEST_TITLE_1 in output.split("\n")[0] def _seed_acoustid_match(item_path: bytes = b"/fake/path.mp3") -> Item: """Seed the chroma module-level match cache as if acoustid had run.""" chroma._matches[item_path] = ( ["rec-id-1"], ["rel-id-1", "rel-id-1", "rel-id-1"], ) return Item(path=item_path) class TestChromaCandidates(PluginMixin): """Regression tests for issue #6212: chroma must respect which metadata source plugins are enabled. When the musicbrainz plugin is not loaded, chroma must not produce any MusicBrainz-sourced candidates (via either ``candidates`` or ``item_candidates``). When it IS loaded, chroma resolves acoustid matches through the registered plugin instance. ``plugin`` is intentionally not set on the class so that :py:meth:`PluginMixin.load_plugins` honours explicit plugin-name arguments and each test can choose its own combination. The autouse fixture clears the ``@cache``-decorated metadata-source registry and the chroma match state between tests. """ preload_plugin = False @pytest.fixture(autouse=True) def _setup_chroma(self): metadata_plugins.find_metadata_source_plugins.cache_clear() metadata_plugins.get_metadata_source.cache_clear() chroma._matches.clear() yield chroma._matches.clear() self.unload_plugins() metadata_plugins.find_metadata_source_plugins.cache_clear() metadata_plugins.get_metadata_source.cache_clear() def test_candidates_returns_empty_without_musicbrainz(self): self.load_plugins("chroma") plugin = chroma.AcoustidPlugin() item = _seed_acoustid_match() result = plugin.candidates( [item], artist="A", album="B", va_likely=False ) assert list(result) == [] def test_item_candidates_returns_empty_without_musicbrainz(self): self.load_plugins("chroma") plugin = chroma.AcoustidPlugin() item = _seed_acoustid_match() result = plugin.item_candidates(item, artist="A", title="B") assert list(result) == [] def test_candidates_returns_mb_albums_with_musicbrainz(self, monkeypatch): self.load_plugins("chroma", "musicbrainz") fake_album = AlbumInfo( tracks=[], album_id="rel-id-1", album="Fake Album" ) mb_plugin = metadata_plugins.get_metadata_source("musicbrainz") assert mb_plugin is not None monkeypatch.setattr( mb_plugin, "album_for_id", MagicMock(return_value=fake_album) ) plugin = chroma.AcoustidPlugin() item = _seed_acoustid_match() result = list( plugin.candidates([item], artist="A", album="B", va_likely=False) ) assert result == [fake_album] mb_plugin.album_for_id.assert_called_with("rel-id-1") def test_item_candidates_returns_mb_tracks_with_musicbrainz( self, monkeypatch ): self.load_plugins("chroma", "musicbrainz") fake_track = TrackInfo(title="Fake Track", track_id="rec-id-1") mb_plugin = metadata_plugins.get_metadata_source("musicbrainz") assert mb_plugin is not None monkeypatch.setattr( mb_plugin, "track_for_id", MagicMock(return_value=fake_track) ) plugin = chroma.AcoustidPlugin() item = _seed_acoustid_match() result = list(plugin.item_candidates(item, artist="A", title="B")) assert result == [fake_track] mb_plugin.track_for_id.assert_called_with("rec-id-1") beetbox-beets-00724b7/test/plugins/test_lastgenre.py0000664000175000017500000012721315253035401022116 0ustar pieterpieter"""Tests for the 'lastgenre' plugin.""" import re from collections import defaultdict from unittest.mock import Mock, patch import confuse import pytest from beets.library import Album from beets.test import _common from beets.test.helper import IOMixin, PluginTestCase from beetsplug import lastgenre from beetsplug.lastgenre.utils import is_ignored, normalize_genre _p = pytest.param class LastGenrePluginTest(IOMixin, PluginTestCase): plugin = "lastgenre" def setUp(self): super().setUp() self.plugin = lastgenre.LastGenrePlugin() def _setup_config( self, whitelist=False, canonical=False, count=1, prefer_specific=False ): self.config["lastgenre"]["canonical"] = canonical self.config["lastgenre"]["count"] = count self.config["lastgenre"]["prefer_specific"] = prefer_specific if isinstance(whitelist, (bool, (str,))): # Filename, default, or disabled. self.config["lastgenre"]["whitelist"] = whitelist self.plugin.setup() if not isinstance(whitelist, (bool, (str,))): # Explicit list of genres. self.plugin.whitelist = whitelist def test_default(self): """Fetch genres with whitelist and c14n deactivated""" self._setup_config() assert self.plugin._resolve_genres(["delta blues"]) == ["delta blues"] def test_c14n_only(self): """Default c14n tree funnels up to most common genre except for *wrong* genres that stay unchanged. """ self._setup_config(canonical=True, count=99) assert self.plugin._resolve_genres(["delta blues"]) == ["blues"] assert self.plugin._resolve_genres(["iota blues"]) == ["iota blues"] def test_whitelist_only(self): """Default whitelist rejects *wrong* (non existing) genres.""" self._setup_config(whitelist=True) assert self.plugin._resolve_genres(["iota blues"]) == [] def test_whitelist_c14n(self): """Default whitelist and c14n both activated result in all parents genres being selected (from specific to common). """ self._setup_config(canonical=True, whitelist=True, count=99) assert self.plugin._resolve_genres(["delta blues"]) == [ "delta blues", "blues", ] def test_whitelist_custom(self): """Keep only genres that are in the whitelist.""" self._setup_config(whitelist={"blues", "rock", "jazz"}, count=2) assert self.plugin._resolve_genres(["pop", "blues"]) == ["blues"] self._setup_config(canonical="", whitelist={"rock"}) assert self.plugin._resolve_genres(["delta blues"]) == [] def test_format_genres(self): """Format genres list.""" self._setup_config(count=2) assert self.plugin._format_genres(["jazz", "pop", "rock", "blues"]) == [ "Jazz", "Pop", "Rock", "Blues", ] def test_count_c14n(self): """Keep the n first genres, after having applied c14n when necessary""" self._setup_config( whitelist={"blues", "rock", "jazz"}, canonical=True, count=2 ) # thanks to c14n, 'blues' superseeds 'country blues' and takes the # second slot assert self.plugin._resolve_genres( ["jazz", "pop", "country blues", "rock"] ) == ["jazz", "blues"] def test_c14n_whitelist(self): """Genres first pass through c14n and are then filtered""" self._setup_config(canonical=True, whitelist={"rock"}) assert self.plugin._resolve_genres(["delta blues"]) == [] def test_empty_string_enables_canonical(self): """For backwards compatibility, setting the `canonical` option to the empty string enables it using the default tree. """ self._setup_config(canonical="", count=99) assert self.plugin._resolve_genres(["delta blues"]) == ["blues"] def test_empty_string_enables_whitelist(self): """Again for backwards compatibility, setting the `whitelist` option to the empty string enables the default set of genres. """ self._setup_config(whitelist="") assert self.plugin._resolve_genres(["iota blues"]) == [] def test_prefer_specific_loads_tree(self): """When prefer_specific is enabled but canonical is not the tree still has to be loaded. """ self._setup_config(prefer_specific=True, canonical=False) assert self.plugin.c14n_branches != [] def test_prefer_specific_without_canonical(self): """Prefer_specific works without canonical.""" self._setup_config(prefer_specific=True, canonical=False, count=4) assert self.plugin._resolve_genres(["math rock", "post-rock"]) == [ "post-rock", "math rock", ] @patch("beets.ui.should_write", Mock(return_value=True)) @patch( "beetsplug.lastgenre.LastGenrePlugin._get_genre", Mock(return_value=("Mock Genre", "mock stage")), ) def test_pretend_option_skips_library_updates(self): item = self.create_item( album="Pretend Album", albumartist="Pretend Artist", artist="Pretend Artist", title="Pretend Track", genres=["Original Genre"], ) album = self.lib.add_album([item]) def unexpected_store(*_, **__): raise AssertionError("Unexpected store call") # Verify that try_write was never called (file operations skipped) with patch("beetsplug.lastgenre.Item.store", unexpected_store): output = self.run_with_output("lastgenre", "--pretend") assert "genres:" in output album.load() assert album.genres == ["Original Genre"] assert album.items()[0].genres == ["Original Genre"] def test_no_duplicate(self): """Remove duplicated genres.""" self._setup_config(count=99) assert self.plugin._resolve_genres(["blues", "blues"]) == ["blues"] def test_fetch_va_genres_picks_most_popular_track_genre(self): """Among fetched track genres, the most common one wins.""" self._setup_config() self.config["lastgenre"]["source"] = "track" self.plugin.setup() item1 = self.add_item(artist="Artist A") item2 = self.add_item(artist="Artist B") item3 = self.add_item(artist="Artist C") album = self.lib.add_album([item1, item2, item3]) track_genres = { "Artist A": ["Rock"], "Artist B": ["Rock"], "Artist C": ["Jazz"], } self.plugin.client.fetch = lambda kind, obj, *args: ( track_genres[obj.artist] if kind == "track" else [] ) assert self.plugin._fetch_va_genres(album) == ["Rock"] def test_fetch_va_genres_falls_back_to_artist_genre(self): """When a track has no genre, fall back to its artist's genre.""" self._setup_config() item = self.add_item(artist="Artist A") album = self.lib.add_album([item]) self.plugin.client.fetch = lambda kind, obj, *args: ( ["Jazz"] if kind == "artist" else [] ) assert self.plugin._fetch_va_genres(album) == ["Jazz"] def test_fetch_va_genres_empty_when_nothing_found(self): """Return an empty list when neither track nor artist genres exist.""" self._setup_config() item = self.add_item(artist="Artist A") album = self.lib.add_album([item]) self.plugin.client.fetch = lambda kind, obj, *args: [] assert self.plugin._fetch_va_genres(album) == [] def test_fetch_genre(self): class MockPylastElem: def __init__(self, name): self.name = name def get_name(self): return self.name class MockPylastObj: def get_top_tags(self): tag1 = Mock() tag1.weight = 90 tag1.item = MockPylastElem("Pop") tag2 = Mock() tag2.weight = 40 tag2.item = MockPylastElem("Rap") return [tag1, tag2] plugin = lastgenre.LastGenrePlugin() res = plugin.client.fetch_genres(MockPylastObj()) assert res == ["pop", "rap"] plugin.client.min_weight = 50 res = plugin.client.fetch_genres(MockPylastObj()) assert res == ["pop"] def test_sort_by_depth(self): self._setup_config(canonical=True) # Normal case. tags = ("electronic", "ambient", "post-rock", "downtempo") res = lastgenre.sort_by_depth(tags, self.plugin.c14n_branches) assert res == ["post-rock", "downtempo", "ambient", "electronic"] # Non-canonical tag ('chill out') present. tags = ("electronic", "ambient", "chill out") res = lastgenre.sort_by_depth(tags, self.plugin.c14n_branches) assert res == ["ambient", "electronic"] # Ignorelist tests in resolve_genres and _is_ignored def test_ignorelist_filters_genres_in_resolve(self): """Ignored genres are stripped by _resolve_genres (no c14n). Artist-specific and global patterns are both applied. """ self._setup_config(whitelist=False, canonical=False) self.plugin.ignore_patterns = defaultdict( list, { "the artist": [re.compile(r"^metal$", re.IGNORECASE)], "*": [re.compile(r"^rock$", re.IGNORECASE)], }, ) result = self.plugin._resolve_genres( ["metal", "rock", "jazz"], artist="the artist" ) assert "metal" not in result, ( "artist-specific ignored genre must be removed" ) assert "rock" not in result, "globally ignored genre must be removed" assert "jazz" in result, "non-ignored genre must survive" def test_ignorelist_stops_c14n_ancestry_walk(self): """An ignored tag's c14n parents don't bleed into the result. Without ignorelist, 'delta blues' canonicalizes to 'blues'. With 'delta blues' ignored the tag is skipped entirely in the c14n loop, so 'blues' must not appear either. """ self._setup_config(whitelist=False, canonical=True, count=99) self.plugin.ignore_patterns = defaultdict( list, {"the artist": [re.compile(r"^delta blues$", re.IGNORECASE)]} ) result = self.plugin._resolve_genres( ["delta blues"], artist="the artist" ) assert result == [], ( "ignored tag must not contribute c14n parents to the result" ) def test_ignorelist_c14n_no_whitelist_keeps_oldest_ancestor(self): """With c14n on and whitelist off, ignorelist must not change the parent-selection rule: only the oldest ancestor is returned. """ self._setup_config(whitelist=False, canonical=True, count=99) # ignorelist targets an unrelated genre — must not affect parent walking self.plugin.ignore_patterns = defaultdict( list, {"*": [re.compile(r"^jazz$", re.IGNORECASE)]} ) result = self.plugin._resolve_genres(["delta blues"]) assert result == ["blues"], ( "oldest ancestor only must be returned, not the full parent chain" ) def test_ignorelist_c14n_no_whitelist_drops_ignored_ancestor(self): """With c14n on and whitelist off, if the oldest ancestor itself is ignored it must be dropped and the tag contributes nothing. """ self._setup_config(whitelist=False, canonical=True, count=99) self.plugin.ignore_patterns = defaultdict( list, {"*": [re.compile(r"^blues$", re.IGNORECASE)]} ) result = self.plugin._resolve_genres(["delta blues"]) assert result == [], ( "ignored oldest ancestor must not appear in the result" ) # _filter_valid tests def test_filter_valid_no_whitelist_no_ignorelist_returns_all(self): """With neither whitelist nor ignorelist, all non-empty genres pass.""" self._setup_config(whitelist=False) self.plugin.ignore_patterns = defaultdict(list) result = self.plugin._filter_valid(["rock", "jazz", "blues"]) assert result == ["rock", "jazz", "blues"] def test_filter_valid_strips_empty_and_whitespace(self): """Empty strings and whitespace-only strings are always removed.""" self._setup_config(whitelist=False) self.plugin.ignore_patterns = defaultdict(list) result = self.plugin._filter_valid(["rock", "", " ", "blues"]) assert result == ["rock", "blues"] def test_filter_valid_whitelist_drops_unknown_genres(self): """Genres not in the whitelist are removed.""" self._setup_config(whitelist={"rock", "blues"}) result = self.plugin._filter_valid(["rock", "jazz", "blues"]) assert result == ["rock", "blues"] def test_filter_valid_whitelist_is_case_insensitive(self): """Whitelist lookup is lowercased, so genre case doesn't matter.""" self._setup_config(whitelist={"rock"}) result = self.plugin._filter_valid(["Rock", "ROCK", "rock"]) assert result == ["Rock", "ROCK", "rock"] def test_filter_valid_ignorelist_drops_matched_genres(self): """Genres matching ignorelist patterns are removed.""" self._setup_config(whitelist=False) self.plugin.ignore_patterns = defaultdict( list, {"*": [re.compile(r"^metal$", re.IGNORECASE)]} ) result = self.plugin._filter_valid(["rock", "metal", "jazz"]) assert result == ["rock", "jazz"] def test_filter_valid_ignorelist_artist_specific(self): """Artist-specific ignorelist patterns apply only for that artist.""" self._setup_config(whitelist=False) self.plugin.ignore_patterns = defaultdict( list, {"the artist": [re.compile(r"^noise$", re.IGNORECASE)]} ) assert self.plugin._filter_valid( ["noise", "rock"], artist="the artist" ) == ["rock"] assert self.plugin._filter_valid(["noise", "rock"], artist="other") == [ "noise", "rock", ] def test_filter_valid_whitelist_and_ignorelist_combined(self): """Whitelist is applied first; ignorelist further filters the remainder.""" self._setup_config(whitelist={"rock", "metal", "jazz"}) self.plugin.ignore_patterns = defaultdict( list, {"*": [re.compile(r"^metal$", re.IGNORECASE)]} ) result = self.plugin._filter_valid(["rock", "metal", "pop", "jazz"]) assert result == ["rock", "jazz"] @pytest.mark.parametrize( "config_values, item_genre, mock_genres, expected_result", [ _p( { "force": True, "keep_existing": True, "source": "album", # means album or artist genre "whitelist": True, "canonical": False, "prefer_specific": False, "count": 10, }, ["Blues"], {"album": ["Jazz"]}, (["Blues", "Jazz"], "keep + album, whitelist"), id="force-keep-whitelisted", ), _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": True, "canonical": False, "prefer_specific": False, "count": 10, }, ["original unknown", "Blues"], {"album": ["Jazz"]}, (["Blues", "Jazz"], "keep + album, whitelist"), id="force-keep-whitelisted-unknown-original", ), _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": True, "canonical": False, "prefer_specific": False, }, [], {"album": ["Jazz"]}, (["Jazz"], "album, whitelist"), id="force-keep-whitelisted-empty-tag", ), _p( { "force": True, "keep_existing": True, "source": "artist", # means artist genre, original or fallback "whitelist": True, "canonical": False, "prefer_specific": False, "count": 10, }, ["original unknown", "Blues"], {"album": ["Jazz"], "artist": ["Pop"]}, (["Blues", "Pop"], "keep + artist, whitelist"), id="force-keep-artist-configured", ), _p( { "force": False, "keep_existing": False, "source": "album", "whitelist": False, "canonical": False, "prefer_specific": False, }, ["any genre"], {"album": ["Jazz"]}, (["any genre"], "keep any, no-force"), id="no-force-whitelist-disabled", ), _p( { "force": False, "keep_existing": False, "source": "album", "whitelist": False, "canonical": False, "prefer_specific": False, }, [], {"album": ["Jazzin"]}, (["Jazzin"], "album, any"), id="no-force-empty-tag-no-whitelist", ), # Canonicalize original genre when force is **off** and # whitelist, canonical and cleanup_existing are on. # "Cosmic Disco" is not in the default whitelist, thus gets resolved "up" in the # tree to "Disco" and "Electronic". _p( { "force": False, "keep_existing": False, "source": "artist", "whitelist": True, "canonical": True, "cleanup_existing": True, "prefer_specific": False, "count": 10, }, ["Cosmic Disco"], {"artist": []}, (["Disco", "Electronic"], "keep + cleanup, whitelist"), id="canonicalize-existing-genre-with-cleanup", ), _p( { "force": True, "keep_existing": True, "source": "track", # means track,album,artist,... "whitelist": False, "canonical": False, "prefer_specific": False, "count": 10, }, ["unknown genre"], {"track": None, "album": None, "artist": ["Jazz"]}, (["Unknown Genre", "Jazz"], "keep + artist, any"), id="fallback-through-stages-until-found", ), _p( { "force": True, "keep_existing": True, "source": "track", "whitelist": False, "fallback": "fallback genre", "canonical": False, "prefer_specific": False, }, ["any existing"], {"track": None, "album": None, "artist": None}, (["any existing"], "original fallback"), id="keep-original-with-keep-existing-without-whitelist", ), _p( { "force": True, "keep_existing": True, "source": "track", "whitelist": True, "fallback": "fallback genre", "canonical": False, "prefer_specific": False, }, ["Jazz"], {"track": None, "album": None, "artist": None}, (["Jazz"], "original fallback"), id="keep-valid-original-with-keep-existing-with-whitelist", ), _p( { "force": True, "keep_existing": False, "source": "track", "whitelist": True, "fallback": "fallback genre", "canonical": False, "prefer_specific": False, }, ["Jazz"], {"track": None, "album": None, "artist": None}, (["fallback genre"], "fallback"), id="fallback-without-keep-existing", ), _p( { "force": True, "keep_existing": True, "source": "track", "whitelist": True, "fallback": "fallback genre", "canonical": False, "prefer_specific": False, }, [], {"track": None, "album": None, "artist": None}, (["fallback genre"], "fallback"), id="fallback-when-no-original-genre", ), _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": True, "count": 5, "canonical": False, "prefer_specific": False, }, ["original unknown", "Blues", "Rock", "Folk", "Metal"], {"album": ["Jazz", "Bebop", "Hardbop"]}, ( ["Blues", "Rock", "Metal", "Jazz", "Bebop"], "keep + album, whitelist", ), id="limit-many-results", ), # fallback to next stage (artist) if no allowed original present # and no album genre were fetched. _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": True, "fallback": "fallback genre", "canonical": False, "prefer_specific": False, }, ["not whitelisted original"], {"track": None, "album": None, "artist": ["Jazz"]}, (["Jazz"], "keep + artist, whitelist"), id="fallback-to-artist-when-original-and-album-invalid", ), # canonicalization transforms non-whitelisted genres to canonical forms # # "Acid Techno" is not in the default whitelist, thus gets resolved "up" in the # tree to "Techno" and "Electronic". _p( { "force": True, "keep_existing": False, "source": "album", "whitelist": True, "canonical": True, "prefer_specific": False, "count": 10, }, [], {"album": ["acid techno"]}, (["Techno", "Electronic"], "album, whitelist"), id="canonicalize-non-whitelisted-fetched-genre", ), # canonicalization transforms whitelisted genres to canonical forms and # includes originals # # "Detroit Techno" is in the default whitelist, thus it stays and and also gets # resolved "up" in the tree to "Techno" and "Electronic". The same happens for # newly fetched genre "Acid House". _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": True, "canonical": True, "prefer_specific": False, "count": 10, "extended_debug": True, }, ["detroit techno"], {"album": ["acid house"]}, ( [ "Detroit Techno", "Techno", "Electronic", "Acid House", "House", ], "keep + album, whitelist", ), id="canonicalize-whitelisted-original-and-fetched-genres", ), # canonicalization transforms non-whitelisted original genres to canonical # forms and deduplication works. # # "Cosmic Disco" is not in the default whitelist, thus gets resolved "up" in the # tree to "Disco" and "Electronic". New genre "Detroit Techno" resolves to # "Techno". Both resolve to "Electronic" which gets deduplicated. _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": True, "canonical": True, "prefer_specific": False, "count": 10, }, ["Cosmic Disco"], {"album": ["Detroit Techno"]}, ( ["Disco", "Electronic", "Detroit Techno", "Techno"], "keep + album, whitelist", ), id="canonicalize-and-deduplicate-original-and-fetched-genres", ), # canonicalization transforms non-whitelisted original genres to canonical # forms and deduplication works, **even** when no new genres are found online. # # "Cosmic Disco" is not in the default whitelist, thus gets resolved "up" in the # tree to "Disco" and "Electronic". _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": True, "canonical": True, "prefer_specific": False, "count": 10, }, ["Cosmic Disco"], {"album": [], "artist": []}, (["Disco", "Electronic"], "keep + original fallback, whitelist"), id="canonicalize-and-deduplicate-without-new-genres", ), # Semicolon-delimited genre tag from an external mediafile # ("Jazz; Funk; Soul" as a single element) is split by # DelimitedString.normalize() on assignment and returned as three # individual genres via the "original fallback" path when all Last.fm # stages return empty. _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": False, "canonical": False, "prefer_specific": False, "count": 10, }, ["Jazz; Funk; Soul"], {"album": [], "artist": []}, (["Jazz", "Funk", "Soul"], "original fallback"), id="split-semicolon-delimited-original-genres", ), # Multiple whitelisted genres in the multi-valued `genres` field must # NOT be wiped when Last.fm returns no tags — whether the album is not # found at all or exists but has no tags. Both scenarios produce an # empty list from the fetcher and must be preserved via "original # fallback". _p( { "force": True, "keep_existing": True, "source": "album", "whitelist": True, "canonical": False, "prefer_specific": False, }, ["Baroque", "Classical"], {"album": [], "artist": []}, (["Baroque", "Classical"], "original fallback"), id="preserve-multiple-whitelisted-genres-on-empty-fetch", ), ], ) @pytest.mark.usefixtures("config") def test_get_genre( monkeypatch, config_values, item_genre, mock_genres, expected_result ): """Test _get_genre with various configurations.""" # Mock the last.fm fetchers. When whitelist enabled, we can assume only # whitelisted genres get returned, the plugin's _resolve_genre method # ensures it. monkeypatch.setattr( "beetsplug.lastgenre.client.LastFmClient.fetch", lambda _, kind, __: mock_genres[kind], ) # Initialize plugin instance and item plugin = lastgenre.LastGenrePlugin() # Configure plugin.config.set(config_values) plugin.setup() # Loads default whitelist and canonicalization tree item = _common.item() item.genres = item_genre # Run assert plugin._get_genre(item) == expected_result class TestIgnorelist: """Ignorelist pattern matching tests independent of resolve_genres.""" @pytest.mark.parametrize( "ignorelist_dict, artist, genre, expected_forbidden", [ # Global ignorelist - simple word ({"*": ["spoken word"]}, "Any Artist", "spoken word", True), ({"*": ["spoken word"]}, "Any Artist", "jazz", False), # Global ignorelist - regex pattern ( {"*": [".*electronic.*"]}, "Any Artist", "ambient electronic", True, ), ({"*": [".*electronic.*"]}, "Any Artist", "jazz", False), # Artist-specific ignorelist ({"metallica": ["metal"]}, "Metallica", "metal", True), ({"metallica": ["metal"]}, "Iron Maiden", "metal", False), # Case insensitive matching ({"metallica": ["metal"]}, "METALLICA", "METAL", True), # Full-match behavior: plain "metal" must not match "heavy metal" ({"metallica": ["metal"]}, "Metallica", "heavy metal", False), # Regex behavior: explicit pattern ".*metal.*" may match "heavy metal" ({"metallica": [".*metal.*"]}, "Metallica", "heavy metal", True), # Artist-specific ignorelist - exact match ( {"metallica": ["^Heavy Metal$"]}, "Metallica", "classic metal", False, ), # Combined global and artist-specific ( {"*": ["spoken word"], "metallica": ["metal"]}, "Metallica", "spoken word", True, ), ( {"*": ["spoken word"], "metallica": ["metal"]}, "Metallica", "metal", True, ), # Complex regex pattern with multiple features (raw string) ( { "fracture": [ r"^(heavy|black|power|death)?\s?(metal|rock)$|\w+-metal\d*$" ] }, "Fracture", "power metal", True, ), # Complex regex pattern with multiple features (regular string) ( {"amon tobin": ["d(rum)?[ n/]*b(ass)?"]}, "Amon Tobin", "dnb", True, ), # Empty ignorelist ({}, "Any Artist", "any genre", False), ], ) def test_ignorelist_patterns( self, ignorelist_dict, artist, genre, expected_forbidden ): """Test ignorelist pattern matching logic directly.""" logger = Mock() # Set up compiled patterns directly (skipping file parsing) ignore_patterns = defaultdict(list) for artist_name, patterns in ignorelist_dict.items(): ignore_patterns[artist_name.lower()] = [ re.compile(pattern, re.IGNORECASE) for pattern in patterns ] result = is_ignored(logger, ignore_patterns, genre, artist) assert result == expected_forbidden @pytest.mark.parametrize( "ignorelist_config, expected_ignorelist", [ # Basic artist with single pattern ({"metallica": ["metal"]}, {"metallica": ["metal"]}), # Global ignorelist with '*' key ({"*": ["spoken word"]}, {"*": ["spoken word"]}), # Multiple patterns per artist ( {"metallica": ["metal", ".*rock.*"]}, {"metallica": ["metal", ".*rock.*"]}, ), # Combined global and artist-specific ( {"*": ["spoken word"], "metallica": ["metal"]}, {"*": ["spoken word"], "metallica": ["metal"]}, ), # Invalid regex pattern that gets escaped (full-match literal fallback) ( {"artist": ["[invalid(regex"]}, {"artist": ["\\[invalid\\(regex"]}, ), # Disabled via False / empty dict — both produce empty dict (False, {}), ({}, {}), ], ) def test_ignorelist_config_format( self, ignorelist_config, expected_ignorelist ): """Test ignorelist parsing/compilation with isolated config state.""" cfg = confuse.Configuration("test", read=False) cfg.set({"lastgenre": {"ignorelist": ignorelist_config}}) # Mimic the plugin loader behavior in isolation to avoid global config bleed. if not cfg["lastgenre"]["ignorelist"].get(): ignore_patterns = {} else: raw_strs = cfg["lastgenre"]["ignorelist"].get( confuse.MappingValues(confuse.Sequence(str)) ) ignore_patterns = {} for artist, patterns in raw_strs.items(): compiled_patterns = [] for pattern in patterns: try: compiled_patterns.append( re.compile(pattern, re.IGNORECASE).pattern ) except re.error: compiled_patterns.append( re.compile( re.escape(pattern), re.IGNORECASE ).pattern ) ignore_patterns[artist.lower()] = compiled_patterns assert ignore_patterns == expected_ignorelist @pytest.mark.parametrize( "invalid_config, expected_error_message", [ # A plain string (e.g. accidental file path) instead of a mapping ("/path/to/ignorelist.txt", "must be a dict"), # An integer instead of a mapping (42, "must be a dict"), # A list of strings instead of a mapping (["spoken word", "comedy"], "must be a dict"), # A mapping with a non-list value ({"metallica": "metal"}, "must be a list"), ], ) def test_ignorelist_config_format_errors( self, invalid_config, expected_error_message ): """Test ignorelist config validation errors in isolated config.""" cfg = confuse.Configuration("test", read=False) cfg.set({"lastgenre": {"ignorelist": invalid_config}}) with pytest.raises(confuse.ConfigTypeError) as exc_info: _ = cfg["lastgenre"]["ignorelist"].get( confuse.MappingValues(confuse.Sequence(str)) ) assert expected_error_message in str(exc_info.value) def test_ignorelist_multivalued_album_artist_fallback( self, monkeypatch, config ): """`stage_artist=None` fallback must not re-drop per-artist results.""" config["lastgenre"]["ignorelist"] = { "Artist A": ["Metal"], "Artist Group": ["Metal"], } config["lastgenre"]["whitelist"] = False config["lastgenre"]["count"] = 10 plugin = lastgenre.LastGenrePlugin() plugin.setup() def fake_fetch(_, kind, obj, *args): if kind == "album_artist" and args: album_artist = args[0] return {"Artist A": ["Rock"], "Artist B": ["Metal", "Jazz"]}[ album_artist ] return [] monkeypatch.setattr( "beetsplug.lastgenre.client.LastFmClient.fetch", fake_fetch ) obj = Album() obj.albumartist = "Artist Group" obj.album = "Album Title" obj.albumartists = ["Artist A", "Artist B"] genres, label = plugin._get_genre(obj) assert "multi-valued album artist" in label assert "Metal" in genres class TestAliases: """Alias pattern matching and loading tests.""" @pytest.mark.parametrize( "aliases_dict, genre, expected", [ # Static replacement ({"foo bar": ["foobar"]}, "foobar", "foo bar"), # Template with back-reference ({r"\1 music": [r"(fake)[ /-]*music"]}, "fake-music", "fake music"), # Template with multiple back-references ({r"\1-\2": [r"(x)[ /-]*(y)"]}, "x y", "x-y"), # Case-insensitive matching ({"foo bar": ["foobar"]}, "FOOBAR", "foo bar"), # No match — genre returned as-is (lowercased) ({"foo bar": ["foobar"]}, "jazz", "jazz"), # Empty alias list → no-op ({}, "something", "something"), ], ) def test_normalize_genre( self, aliases_dict: dict[str, list[str]], genre: str, expected: str ) -> None: """Test normalize_genre() with static and template canonical names.""" alias_patterns = [ (re.compile(pat, re.IGNORECASE), template.lower()) for template, patterns in aliases_dict.items() for pat in patterns ] assert normalize_genre(Mock(), alias_patterns, genre) == expected def test_normalize_genre_invalid_template_does_not_crash(self) -> None: """Invalid replacement templates are skipped instead of crashing.""" logger = Mock() alias_patterns = [ (re.compile(r"(hip)[ /-]*hop", re.IGNORECASE), r"\g<2> hop") ] assert normalize_genre(logger, alias_patterns, "hip-hop") == "hip-hop" logger.warning.assert_called_once() def test_aliases_config_format(self, config): """Test _load_aliases() loading from inline config dict.""" # Multi-pattern list: proves all patterns are loaded, not just the first config["lastgenre"]["aliases"] = {"hip hop": ["hip-hop", "hiphop"]} plugin = lastgenre.LastGenrePlugin() assert ( normalize_genre(plugin._log, plugin.alias_patterns, "hip-hop") == "hip hop" ) assert ( normalize_genre(plugin._log, plugin.alias_patterns, "hiphop") == "hip hop" ) @pytest.mark.parametrize( "invalid_config, expected_error", [ # Plain string instead of mapping ("/path/to/aliases.txt", "must be a dict"), # Integer (42, "must be a dict"), # Mapping with non-list value ({"hip hop": "hip-hop"}, "must be a list"), ], ) def test_aliases_config_format_errors( self, config, invalid_config, expected_error ): """Test that invalid aliases config values raise confuse.ConfigTypeError.""" config["lastgenre"]["aliases"] = invalid_config with pytest.raises(confuse.ConfigTypeError) as exc_info: lastgenre.LastGenrePlugin() assert expected_error in str(exc_info.value) def test_normalize_before_whitelist(self, config): """Aliases normalize BEFORE whitelist filtering. 'hip-hop' is not on the whitelist but 'hip hop' is. With aliases enabled the tag must survive whitelist filtering. """ config["lastgenre"]["aliases"] = {"hip hop": ["hip-hop", "hiphop"]} plugin = lastgenre.LastGenrePlugin() plugin.setup() # Inject only 'hip hop' into the whitelist to prove the alias fired. plugin.whitelist = {"hip hop"} result = plugin._resolve_genres(["hip-hop"]) assert result == ["hip hop"], ( "alias must normalize 'hip-hop' → 'hip hop' before whitelist check" ) def test_normalize_before_ignorelist(self, config): """Aliases normalize BEFORE ignorelist filtering. If 'hip hop' is ignored but 'hip-hop' is fed in, the alias fires first so the result is empty (correctly ignored). """ config["lastgenre"]["aliases"] = {"hip hop": ["hip-hop"]} plugin = lastgenre.LastGenrePlugin() plugin.setup() plugin.ignore_patterns = {"*": [re.compile("hip hop", re.IGNORECASE)]} result = plugin._resolve_genres(["hip-hop"]) assert result == [], ( "alias must normalize 'hip-hop' before ignorelist check drops it" ) def test_disabled(self, config): """With aliases: false, no normalization is performed.""" config["lastgenre"]["aliases"] = False plugin = lastgenre.LastGenrePlugin() assert plugin.alias_patterns == [] # normalize_genre with an empty list must return the genre unchanged. assert ( normalize_genre(plugin._log, plugin.alias_patterns, "hip-hop") == "hip-hop" ) @pytest.mark.parametrize( "input_genre, expected_genre", [ ("dnb", "drum and bass"), ("drum n bass", "drum and bass"), ("r&b", "r&b"), ("rnb", "r&b"), ("rock & roll", "rock and roll"), ("rock'n'roll", "rock and roll"), ("kpop", "k-pop"), ("k -pop", "k-pop"), ("j rock", "j-rock"), ("post rock", "post-rock"), ("lofi", "lo-fi"), ("lo fi", "lo-fi"), ("p funk", "p-funk"), ("synth funk", "synth funk"), ("synth pop", "synth-pop"), ("synth-wave", "synthwave"), ("avantgarde", "avant-garde"), ("avant gard", "avant-garde"), ("nu-jazz", "nu jazz"), ("nu-metal", "nu metal"), ("nu-soul", "nu soul"), ("nu-disco", "nu disco"), ("nu - disco", "nu disco"), ("electronic music", "electronic"), ("world", "world music"), ("chill", "chill"), ("chill out", "chillout"), ("chill-out", "chillout"), ("dark wave", "dark wave"), ("dark-wave", "dark wave"), ("blues rock", "blues rock"), ("blues-rock", "blues rock"), ("folk-rock", "folk rock"), ("downbeat", "downtempo"), ("shoegazer", "shoegaze"), ("shoegazing", "shoegaze"), ("hip-hop", "hip hop"), ("triphop", "trip hop"), ("punk", "punk rock"), ("alt", "alt"), ("alt rock", "alternative rock"), ("alternative", "alternative"), ("goth", "gothic rock"), ("goth rock", "gothic rock"), ("gothic rock", "gothic rock"), ("prog", "progressive rock"), ("prog rock", "progressive rock"), ("progressive rock", "progressive rock"), ("trad", "trad"), ("traditional", "traditional"), ("indie", "indie"), ("indie rock", "indie rock"), ("juke/footwork", "juke/footwork"), ("Funk / Soul", "funk / soul"), ("psy-trance", "psytrance"), ("psy rock", "psychedelic rock"), ("psych-pop", "psychedelic pop"), ("disney", "disney"), ("old-school death-metal", "old school death metal"), ("old-skool-hip-hop", "old school hip hop"), ("old school-jungle", "old school jungle"), ], ) def test_default_alias_patterns(self, config, input_genre, expected_genre): """Verify that bundled aliases.yaml correctly handles common variants.""" plugin = lastgenre.LastGenrePlugin() result = normalize_genre( plugin._log, plugin.alias_patterns, input_genre ) assert result == expected_genre def test_client_normalizes_in_last_lookup(self): """LastFmClient._last_lookup applies alias normalization then ignorelist.""" alias_patterns = [(re.compile(r"hip-hop", re.IGNORECASE), "hip hop")] ignore_patterns = {"*": [re.compile("hip hop", re.IGNORECASE)]} client = lastgenre.client.LastFmClient( Mock(), 0, ignore_patterns, alias_patterns ) mock_lastfm_obj = Mock() mock_lastfm_obj.get_top_tags.return_value = [] # Seed the cache directly to avoid a real network call. client.genre_cache["track.artist-title"] = ["hip-hop"] result = client._last_lookup("track", Mock(), "artist", "title") assert result == [], ( "'hip-hop' must be normalized to 'hip hop' then filtered by ignorelist" ) beetbox-beets-00724b7/test/plugins/test_spotify.py0000664000175000017500000004615015253035401021627 0ustar pieterpieter"""Tests for the 'spotify' plugin""" import json from urllib.parse import parse_qs, urlparse import responses from beets.library import Item from beets.test import _common from beets.test.helper import PluginTestCase from beetsplug import spotify class ArgumentsMock: def __init__(self, mode, show_failures): self.mode = mode self.show_failures = show_failures self.verbose = 1 def _params(url): """Get the query parameters from a URL.""" return parse_qs(urlparse(url).query) class SpotifyPluginTest(PluginTestCase): plugin = "spotify" db_on_disk = True @responses.activate def setUp(self): responses.add( responses.POST, spotify.SpotifyPlugin.oauth_token_url, status=200, json={ "access_token": "3XyiC3raJySbIAV5LVYj1DaWbcocNi3LAJTNXRnYY" "GVUl6mbbqXNhW3YcZnQgYXNWHFkVGSMlc0tMuvq8CF", "token_type": "Bearer", "expires_in": 3600, "scope": "", }, ) super().setUp() self.spotify = spotify.SpotifyPlugin() opts = ArgumentsMock("list", False) self.spotify._parse_opts(opts) def test_args(self): opts = ArgumentsMock("fail", True) assert not self.spotify._parse_opts(opts) opts = ArgumentsMock("list", False) assert self.spotify._parse_opts(opts) def test_empty_query(self): assert self.spotify._match_library_tracks(self.lib, "1=2") is None @responses.activate def test_missing_request(self): json_file = _common.RSRC / "spotify" / "missing_request.json" response_body = json_file.read_bytes() responses.add( responses.GET, spotify.SpotifyPlugin.search_url, body=response_body, status=200, content_type="application/json", ) item = Item( mb_trackid="01234", album="lkajsdflakjsd", albumartist="ujydfsuihse", title="duifhjslkef", length=10, ) item.add(self.lib) assert [] == self.spotify._match_library_tracks(self.lib, "") params = _params(responses.calls[0].request.url) query = params["q"][0] assert "duifhjslkef" in query assert "artist:'ujydfsuihse'" in query assert "album:'lkajsdflakjsd'" in query assert params["type"] == ["track"] @responses.activate def test_track_request(self): json_file = _common.RSRC / "spotify" / "track_request.json" response_body = json_file.read_bytes() responses.add( responses.GET, spotify.SpotifyPlugin.search_url, body=response_body, status=200, content_type="application/json", ) item = Item( mb_trackid="01234", album="Despicable Me 2", albumartist="Pharrell Williams", title="Happy", length=10, ) item.add(self.lib) results = self.spotify._match_library_tracks(self.lib, "Happy") assert 1 == len(results) assert "6NPVjNh8Jhru9xOmyQigds" == results[0]["id"] self.spotify._output_match_results(results) params = _params(responses.calls[0].request.url) query = params["q"][0] assert "Happy" in query assert "artist:'Pharrell Williams'" in query assert "album:'Despicable Me 2'" in query assert params["type"] == ["track"] @responses.activate def test_track_for_id(self): """Tests if plugin is able to fetch a track by its Spotify ID""" # Mock the Spotify 'Get Track' call json_file = _common.RSRC / "spotify" / "track_info.json" response_body = json_file.read_bytes() responses.add( responses.GET, f"{spotify.SpotifyPlugin.track_url}/6NPVjNh8Jhru9xOmyQigds", body=response_body, status=200, content_type="application/json", ) # Mock the Spotify 'Get Album' call json_file = _common.RSRC / "spotify" / "album_info.json" response_body = json_file.read_bytes() responses.add( responses.GET, f"{spotify.SpotifyPlugin.album_url}5l3zEmMrOhOzG8d8s83GOL", body=response_body, status=200, content_type="application/json", ) # Mock the Spotify 'Search' call json_file = _common.RSRC / "spotify" / "track_request.json" response_body = json_file.read_bytes() responses.add( responses.GET, spotify.SpotifyPlugin.search_url, body=response_body, status=200, content_type="application/json", ) track_info = self.spotify.track_for_id("6NPVjNh8Jhru9xOmyQigds") item = Item( mb_trackid=track_info.track_id, albumartist=track_info.artist, title=track_info.title, length=track_info.length, ) item.add(self.lib) results = self.spotify._match_library_tracks(self.lib, "Happy") assert 1 == len(results) assert "6NPVjNh8Jhru9xOmyQigds" == results[0]["id"] @responses.activate def test_japanese_track(self): """Ensure non-ASCII characters remain unchanged in search queries""" # Path to the mock JSON file for the Japanese track json_file = _common.RSRC / "spotify" / "japanese_track_request.json" # Load the mock JSON response response_body = json_file.read_bytes() # Mock Spotify Search API response responses.add( responses.GET, spotify.SpotifyPlugin.search_url, body=response_body, status=200, content_type="application/json", ) # Create a mock item with Japanese metadata item = Item( mb_trackid="56789", album="盗作", albumartist="ヨルシカ", title="æ€�想犯", length=10, ) item.add(self.lib) # Search without ascii encoding with self.configure_plugin({"search_query_ascii": False}): assert self.spotify.config["search_query_ascii"].get() is False # Call the method to match library tracks results = self.spotify._match_library_tracks(self.lib, item.title) # Assertions to verify results assert results is not None assert 1 == len(results) assert results[0]["name"] == item.title assert results[0]["artists"][0]["name"] == item.albumartist assert results[0]["album"]["name"] == item.album # Verify search query parameters params = _params(responses.calls[0].request.url) query = params["q"][0] assert item.title in query assert f"artist:'{item.albumartist}'" in query assert f"album:'{item.album}'" in query assert not query.isascii() # Is not found in the library if ascii encoding is enabled with self.configure_plugin({"search_query_ascii": True}): assert self.spotify.config["search_query_ascii"].get() is True results = self.spotify._match_library_tracks(self.lib, item.title) params = _params(responses.calls[1].request.url) query = params["q"][0] assert query.isascii() @responses.activate def test_multiartist_album_and_track(self): """Tests if plugin is able to map multiple artists in an album and track info correctly""" # Mock the Spotify 'Get Album' call json_file = _common.RSRC / "spotify" / "multiartist_album.json" album_response_body = json_file.read_bytes() responses.add( responses.GET, f"{spotify.SpotifyPlugin.album_url}0yhKyyjyKXWUieJ4w1IAEa", body=album_response_body, status=200, content_type="application/json", ) # Mock the Spotify 'Get Track' call json_file = _common.RSRC / "spotify" / "multiartist_track.json" track_response_body = json_file.read_bytes() responses.add( responses.GET, f"{spotify.SpotifyPlugin.track_url}/6sjZfVJworBX6TqyjkxIJ1", body=track_response_body, status=200, content_type="application/json", ) album_info = self.spotify.album_for_id("0yhKyyjyKXWUieJ4w1IAEa") assert album_info is not None assert album_info.artist == "Project Skylate, Sugar Shrill" assert album_info.artists == ["Project Skylate", "Sugar Shrill"] assert album_info.artist_id == "6m8MRXIVKb6wQaPlBIDMr1" assert album_info.artists_ids == [ "6m8MRXIVKb6wQaPlBIDMr1", "4kkAIoQmNT5xEoNH5BuQLe", ] assert len(album_info.tracks) == 1 assert album_info.tracks[0].artist == "Foo, Bar" assert album_info.tracks[0].artists == ["Foo", "Bar"] assert album_info.tracks[0].artist_id == "12345" assert album_info.tracks[0].artists_ids == ["12345", "67890"] track_info = self.spotify.track_for_id("6sjZfVJworBX6TqyjkxIJ1") assert track_info is not None assert track_info.artist == "Foo, Bar" assert track_info.artists == ["Foo", "Bar"] assert track_info.artist_id == "12345" assert track_info.artists_ids == ["12345", "67890"] @responses.activate def test_get_track_details_by_id_chunks_requests(self): ids_per_request = [] def callback(request): ids = _params(request.url)["ids"][0].split(",") ids_per_request.append(len(ids)) return ( 200, {"Content-Type": "application/json"}, json.dumps( { "tracks": [ { "id": track_id, "popularity": 50, "external_ids": {}, } for track_id in ids ] } ), ) responses.add_callback( responses.GET, spotify.SpotifyPlugin.track_url, callback=callback, content_type="application/json", ) track_ids = [f"track-{idx}" for idx in range(51)] track_info = self.spotify.get_track_details_by_id(track_ids) assert len(track_info) == 51 assert ids_per_request == [50, 1] @responses.activate def test_fetch_info_uses_batch_endpoints(self): responses.add( responses.GET, spotify.SpotifyPlugin.track_url, status=200, json={ "tracks": [ { "id": "id-1", "popularity": 10, "external_ids": { "isrc": "isrc-1", "ean": "ean-1", "upc": "upc-1", }, }, { "id": "id-2", "popularity": 20, "external_ids": { "isrc": "isrc-2", "ean": "ean-2", "upc": "upc-2", }, }, { "id": "id-3", "popularity": 30, "external_ids": { "isrc": "isrc-3", "ean": "ean-3", "upc": "upc-3", }, }, ] }, content_type="application/json", ) responses.add( responses.GET, spotify.SpotifyPlugin.audio_features_url, status=200, json={ "audio_features": [ {"id": "id-1", "tempo": 100.1, "energy": 0.4}, {"id": "id-2", "tempo": 110.2, "energy": 0.5}, {"id": "id-3", "tempo": 120.3, "energy": 0.6}, ] }, content_type="application/json", ) items = [] for idx in range(1, 4): item = Item(title=f"Track {idx}", artist="Artist", length=10) item.add(self.lib) item["spotify_track_id"] = f"id-{idx}" items.append(item) self.spotify._fetch_info(self.lib, items, write=False, force=True) get_calls = [ call for call in responses.calls if call.request.method == "GET" ] batch_track_calls = [ call for call in get_calls if urlparse(call.request.url).path == "/v1/tracks" ] single_track_calls = [ call for call in get_calls if urlparse(call.request.url).path.startswith("/v1/tracks/") ] batch_audio_calls = [ call for call in get_calls if urlparse(call.request.url).path == "/v1/audio-features" ] single_audio_calls = [ call for call in get_calls if urlparse(call.request.url).path.startswith("/v1/audio-features/") ] assert len(batch_track_calls) == 1 assert len(single_track_calls) == 0 assert len(batch_audio_calls) == 1 assert len(single_audio_calls) == 0 assert items[0]["spotify_track_popularity"] == 10 assert items[1]["spotify_track_popularity"] == 20 assert items[2]["spotify_track_popularity"] == 30 assert items[0]["spotify_tempo"] == 100.1 assert items[1]["spotify_tempo"] == 110.2 assert items[2]["spotify_tempo"] == 120.3 @responses.activate def test_fetch_info_deduplicates_batch_ids(self): seen_track_ids = [] seen_audio_ids = [] def track_callback(request): ids = _params(request.url)["ids"][0].split(",") seen_track_ids.append(ids) return ( 200, {"Content-Type": "application/json"}, json.dumps( { "tracks": [ { "id": track_id, "popularity": 50, "external_ids": {}, } for track_id in ids ] } ), ) def audio_callback(request): ids = _params(request.url)["ids"][0].split(",") seen_audio_ids.append(ids) return ( 200, {"Content-Type": "application/json"}, json.dumps( { "audio_features": [ {"id": track_id, "tempo": 100.0} for track_id in ids ] } ), ) responses.add_callback( responses.GET, spotify.SpotifyPlugin.track_url, callback=track_callback, content_type="application/json", ) responses.add_callback( responses.GET, spotify.SpotifyPlugin.audio_features_url, callback=audio_callback, content_type="application/json", ) items = [] for idx in range(2): item = Item(title=f"Track {idx}", artist="Artist", length=10) item.add(self.lib) item["spotify_track_id"] = "shared-id" items.append(item) self.spotify._fetch_info(self.lib, items, write=False, force=True) assert seen_track_ids == [["shared-id"]] assert seen_audio_ids == [["shared-id"]] assert items[0]["spotify_track_popularity"] == 50 assert items[1]["spotify_track_popularity"] == 50 @responses.activate def test_fetch_info_writes_before_store(self): responses.add( responses.GET, spotify.SpotifyPlugin.track_url, status=200, json={ "tracks": [{"id": "id-1", "popularity": 10, "external_ids": {}}] }, content_type="application/json", ) responses.add( responses.GET, spotify.SpotifyPlugin.audio_features_url, status=200, json={"audio_features": [{"id": "id-1", "tempo": 100.1}]}, content_type="application/json", ) item = self.add_item_fixture(title="Track 1", artist="Artist") item["spotify_track_id"] = "id-1" with self.assertLogs("beets", level="DEBUG") as captured_logs: self.spotify._fetch_info(self.lib, [item], write=True, force=True) logs = captured_logs.output write_event_index = next( idx for idx, message in enumerate(logs) if message.endswith("Sending event: write") ) database_change_index = next( idx for idx, message in enumerate(logs) if message.endswith("Sending event: database_change") ) assert write_event_index < database_change_index @responses.activate def test_track_audio_features_batch_disables_on_403(self): responses.add( responses.GET, spotify.SpotifyPlugin.audio_features_url, status=403, json={"error": {"status": 403}}, content_type="application/json", ) assert self.spotify.track_audio_features_batch(["id-1"]) == {} assert self.spotify.audio_features_available is False assert self.spotify.track_audio_features_batch(["id-2"]) == {} assert len(responses.calls) == 1 @responses.activate def test_track_audio_features_batch_keeps_partial_results_on_api_error( self, ): def callback(request): ids = _params(request.url)["ids"][0].split(",") if "track-100" in ids: return ( 502, {"Content-Type": "application/json"}, json.dumps({"error": {"status": 502}}), ) return ( 200, {"Content-Type": "application/json"}, json.dumps( { "audio_features": [ {"id": track_id, "tempo": 100.0} for track_id in ids ] } ), ) responses.add_callback( responses.GET, spotify.SpotifyPlugin.audio_features_url, callback=callback, content_type="application/json", ) track_ids = [f"track-{idx}" for idx in range(201)] features = self.spotify.track_audio_features_batch(track_ids) assert "track-0" in features assert "track-99" in features assert "track-100" not in features assert "track-199" not in features assert "track-200" in features beetbox-beets-00724b7/test/plugins/test_replaygain.py0000664000175000017500000003344615253035401022271 0ustar pieterpieterfrom abc import ABC, abstractmethod from typing import Any, ClassVar import pytest from mediafile import MediaFile from beets.test.helper import ( AsIsImporterMixin, ImportHelper, PluginMixin, has_program, ) from beetsplug.replaygain import ( FatalGstreamerPluginReplayGainError, GStreamerBackend, MetaflacBackend, ) try: import gi gi.require_version("Gst", "1.0") GST_AVAILABLE = True except (ImportError, ValueError): GST_AVAILABLE = False GAIN_PROG = next( ( cmd for cmd in ["mp3gain", "mp3rgain", "aacgain"] if has_program(cmd, ["-v"]) ), None, ) FFMPEG_AVAILABLE = has_program("ffmpeg", ["-version"]) METAFLAC_AVAILABLE = has_program("metaflac", ["--version"]) def reset_replaygain(item): item["rg_track_peak"] = None item["rg_track_gain"] = None item["rg_album_gain"] = None item["rg_album_gain"] = None item["r128_track_gain"] = None item["r128_album_gain"] = None item.write() item.store() class ReplayGainPluginHelper(PluginMixin, ImportHelper): db_on_disk = True plugin = "replaygain" preload_plugin = False plugin_config: ClassVar[dict[str, Any]] @property def backend(self): return self.plugin_config["backend"] def setup_beets(self): # Implemented by Mixins, see above. This may decide to skip the test. self.test_backend() super().setup_beets() self.config["replaygain"].set(self.plugin_config) self.load_plugins() class ThreadedImportMixin: def setup_beets(self): super().setup_beets() self.config["threaded"] = True class BackendMixin(ABC): plugin_config: ClassVar[dict[str, Any]] has_r128_support: bool @abstractmethod def test_backend(self): """Check whether the backend actually has all required functionality.""" class GstBackendMixin(BackendMixin): plugin_config: ClassVar[dict[str, Any]] = {"backend": "gstreamer"} has_r128_support = True def test_backend(self): """Check whether the backend actually has all required functionality.""" try: # Check if required plugins can be loaded by instantiating a # GStreamerBackend (via its .__init__). self.config["replaygain"]["targetlevel"] = 89 GStreamerBackend(self.config["replaygain"], None) except FatalGstreamerPluginReplayGainError as e: # Skip the test if plugins could not be loaded. pytest.skip(str(e)) class CmdBackendMixin(BackendMixin): plugin_config: ClassVar[dict[str, Any]] = { "backend": "command", "command": GAIN_PROG, } has_r128_support = False class FfmpegBackendMixin(BackendMixin): plugin_config: ClassVar[dict[str, Any]] = {"backend": "ffmpeg"} has_r128_support = True class MetaflacBackendMixin(BackendMixin): plugin_config: ClassVar[dict[str, Any]] = {"backend": "metaflac"} has_r128_support = False def test_backend(self): """Skip the test when the metaflac tool is not installed.""" if not METAFLAC_AVAILABLE: pytest.skip("metaflac cannot be found") class ReplayGainCliTest: FNAME: str def _add_album(self, *args, **kwargs): # Use a file with non-zero volume (most test assets are total silence) album = self.add_album_fixture(*args, fname=self.FNAME, **kwargs) for item in album.items(): reset_replaygain(item) return album def test_cli_saves_track_gain(self): self._add_album(2) for item in self.lib.items(): assert item.rg_track_peak is None assert item.rg_track_gain is None mediafile = MediaFile(item.path) assert mediafile.rg_track_peak is None assert mediafile.rg_track_gain is None self.run_command("replaygain") # Skip the test if rg_track_peak and rg_track gain is None, assuming # that it could only happen if the decoder plugins are missing. if all( i.rg_track_peak is None and i.rg_track_gain is None for i in self.lib.items() ): pytest.skip("decoder plugins could not be loaded.") for item in self.lib.items(): assert item.rg_track_peak is not None assert item.rg_track_gain is not None mediafile = MediaFile(item.path) assert mediafile.rg_track_peak == pytest.approx( item.rg_track_peak, abs=1e-6 ) assert mediafile.rg_track_gain == pytest.approx( item.rg_track_gain, abs=1e-2 ) def test_cli_skips_calculated_tracks(self): album_rg = self._add_album(1) item_rg = album_rg.items()[0] if self.has_r128_support: album_r128 = self._add_album(1, ext="opus") item_r128 = album_r128.items()[0] self.run_command("replaygain") item_rg.load() assert item_rg.rg_track_gain is not None assert item_rg.rg_track_peak is not None assert item_rg.r128_track_gain is None item_rg.rg_track_gain += 1.0 item_rg.rg_track_peak += 1.0 item_rg.store() rg_track_gain = item_rg.rg_track_gain rg_track_peak = item_rg.rg_track_peak if self.has_r128_support: item_r128.load() assert item_r128.r128_track_gain is not None assert item_r128.rg_track_gain is None assert item_r128.rg_track_peak is None item_r128.r128_track_gain += 1.0 item_r128.store() r128_track_gain = item_r128.r128_track_gain self.run_command("replaygain") item_rg.load() assert item_rg.rg_track_gain == rg_track_gain assert item_rg.rg_track_peak == rg_track_peak if self.has_r128_support: item_r128.load() assert item_r128.r128_track_gain == r128_track_gain def test_cli_does_not_skip_wrong_tag_type(self): """Check that items that have tags of the wrong type won't be skipped.""" if not self.has_r128_support: # This test is a lot less interesting if the backend cannot write # both tag types. pytest.skip( f"r128 tags for opus not supported on backend {self.backend}" ) album_rg = self._add_album(1) item_rg = album_rg.items()[0] album_r128 = self._add_album(1, ext="opus") item_r128 = album_r128.items()[0] item_rg.r128_track_gain = 0.0 item_rg.store() item_r128.rg_track_gain = 0.0 item_r128.rg_track_peak = 42.0 item_r128.store() self.run_command("replaygain") item_rg.load() item_r128.load() assert item_rg.rg_track_gain is not None assert item_rg.rg_track_peak is not None # FIXME: Should the plugin null this field? # assert item_rg.r128_track_gain is None assert item_r128.r128_track_gain is not None # FIXME: Should the plugin null these fields? # assert item_r128.rg_track_gain is None # assert item_r128.rg_track_peak is None def test_cli_saves_album_gain_to_file(self): self._add_album(2) for item in self.lib.items(): mediafile = MediaFile(item.path) assert mediafile.rg_album_peak is None assert mediafile.rg_album_gain is None self.run_command("replaygain", "-a") peaks = [] gains = [] for item in self.lib.items(): mediafile = MediaFile(item.path) peaks.append(mediafile.rg_album_peak) gains.append(mediafile.rg_album_gain) # Make sure they are all the same assert max(peaks) == min(peaks) assert max(gains) == min(gains) assert max(gains) != 0.0 assert max(peaks) != 0.0 def test_cli_writes_only_r128_tags(self): if not self.has_r128_support: pytest.skip( f"r128 tags for opus not supported on backend {self.backend}" ) album = self._add_album(2, ext="opus") self.run_command("replaygain", "-a") for item in album.items(): mediafile = MediaFile(item.path) # does not write REPLAYGAIN_* tags assert mediafile.rg_track_gain is None assert mediafile.rg_album_gain is None # writes R128_* tags assert mediafile.r128_track_gain is not None assert mediafile.r128_album_gain is not None def test_targetlevel_has_effect(self): album = self._add_album(1) item = album.items()[0] def analyse(target_level): self.config["replaygain"]["targetlevel"] = target_level self.run_command("replaygain", "-f") item.load() return item.rg_track_gain gain_relative_to_84 = analyse(84) gain_relative_to_89 = analyse(89) assert gain_relative_to_84 != gain_relative_to_89 def test_r128_targetlevel_has_effect(self): if not self.has_r128_support: pytest.skip( f"r128 tags for opus not supported on backend {self.backend}" ) album = self._add_album(1, ext="opus") item = album.items()[0] def analyse(target_level): self.config["replaygain"]["r128_targetlevel"] = target_level self.run_command("replaygain", "-f") item.load() return item.r128_track_gain gain_relative_to_84 = analyse(84) gain_relative_to_89 = analyse(89) assert gain_relative_to_84 != gain_relative_to_89 def test_per_disc(self): # Use the per_disc option and add a little more concurrency. album = self._add_album(track_count=4, disc_count=3) self.config["replaygain"]["per_disc"] = True self.run_command("replaygain", "-a") # FIXME: Add fixtures with known track/album gain (within a suitable # tolerance) so that we can actually check per-disc operation here. for item in album.items(): assert item.rg_track_gain is not None assert item.rg_album_gain is not None def test_clears_wrong_tag_type(self): """Check that items that have tags of the wrong type won't be skipped.""" if not self.has_r128_support: pytest.skip( f"r128 tags for opus not supported on backend {self.backend}" ) album_rg = self._add_album(1) item_rg = album_rg.items()[0] album_r128 = self._add_album(1, ext="opus") item_r128 = album_r128.items()[0] item_r128.r128_track_gain = 0.0 item_r128.store() item_rg.rg_track_gain = 0.0 item_rg.rg_track_peak = 42.0 item_rg.store() self.run_command("replaygain") item_rg.load() item_r128.load() assert item_rg.rg_track_gain is not None assert item_rg.rg_track_peak is not None assert item_rg.r128_track_gain is None assert item_r128.r128_track_gain is not None assert item_r128.rg_track_gain is None assert item_r128.rg_track_peak is None @pytest.mark.skipif(not GST_AVAILABLE, reason="gstreamer cannot be found") class TestReplayGainGstCli( ReplayGainCliTest, ReplayGainPluginHelper, GstBackendMixin ): FNAME = "full" # file contains only silence @pytest.mark.skipif(not GAIN_PROG, reason="no *gain command found") class TestReplayGainCmdCli( ReplayGainCliTest, ReplayGainPluginHelper, CmdBackendMixin ): FNAME = "full" # file contains only silence @pytest.mark.skipif(not FFMPEG_AVAILABLE, reason="ffmpeg cannot be found") class TestReplayGainFfmpegCli( ReplayGainCliTest, ReplayGainPluginHelper, FfmpegBackendMixin ): FNAME = "full" # file contains only silence @pytest.mark.skipif(not FFMPEG_AVAILABLE, reason="ffmpeg cannot be found") class TestReplayGainFfmpegNoiseCli( ReplayGainCliTest, ReplayGainPluginHelper, FfmpegBackendMixin ): FNAME = "whitenoise" @pytest.mark.skipif(not METAFLAC_AVAILABLE, reason="metaflac cannot be found") class TestReplayGainMetaflacCli( ReplayGainCliTest, ReplayGainPluginHelper, MetaflacBackendMixin ): FNAME = "whitenoise" def _add_album(self, *args, **kwargs): kwargs.setdefault("ext", "flac") return super()._add_album(*args, **kwargs) def test_metaflac_backend_parses_replaygain_tags(): output = ( b"REPLAYGAIN_TRACK_GAIN=-11.55 dB\nREPLAYGAIN_TRACK_PEAK=0.99998772\n" ) tags = MetaflacBackend._parse_tags(output) assert MetaflacBackend._parse_gain(tags["REPLAYGAIN_TRACK_GAIN"]) == ( pytest.approx(-11.55) ) assert float(tags["REPLAYGAIN_TRACK_PEAK"]) == pytest.approx(0.99998772) assert MetaflacBackend._parse_gain("+4.56 dB") == pytest.approx(4.56) class ImportTest(AsIsImporterMixin): def test_import_converted(self): self.run_asis_importer() for item in self.lib.items(): # FIXME: Add fixtures with known track/album gain (within a # suitable tolerance) so that we can actually check correct # operation here. assert item.rg_track_gain is not None assert item.rg_album_gain is not None @pytest.mark.skipif(not GST_AVAILABLE, reason="gstreamer cannot be found") class TestReplayGainGstImport( ImportTest, ReplayGainPluginHelper, GstBackendMixin ): pass @pytest.mark.skipif(not GAIN_PROG, reason="no *gain command found") class TestReplayGainCmdImport( ImportTest, ReplayGainPluginHelper, CmdBackendMixin ): pass @pytest.mark.skipif(not FFMPEG_AVAILABLE, reason="ffmpeg cannot be found") class TestReplayGainFfmpegImport( ImportTest, ReplayGainPluginHelper, FfmpegBackendMixin ): pass @pytest.mark.skipif(not FFMPEG_AVAILABLE, reason="ffmpeg cannot be found") class TestReplayGainFfmpegThreadedImport( ThreadedImportMixin, ImportTest, ReplayGainPluginHelper, FfmpegBackendMixin ): pass beetbox-beets-00724b7/test/plugins/test_scrub.py0000664000175000017500000000246615253035401021252 0ustar pieterpieterfrom mediafile import MediaFile from beets.test.helper import AsIsImporterMixin, ImportHelper, PluginMixin class TestScrubbedImport(AsIsImporterMixin, PluginMixin, ImportHelper): db_on_disk = True plugin = "scrub" def test_tags_not_scrubbed(self): with self.configure_plugin({"auto": False}): self.run_asis_importer(write=True) for item in self.lib.items(): imported_file = MediaFile(item.filepath) assert imported_file.artist == "Tag Artist" assert imported_file.album == "Tag Album" def test_tags_restored(self): with self.configure_plugin({"auto": True}): self.run_asis_importer(write=True) for item in self.lib.items(): imported_file = MediaFile(item.filepath) assert imported_file.artist == "Tag Artist" assert imported_file.album == "Tag Album" def test_tags_not_scrubbed_when_nowrite(self): """When --nowrite is passed, scrubbing should be skipped entirely.""" with self.configure_plugin({"auto": True}): self.run_asis_importer(write=False) for item in self.lib.items(): imported_file = MediaFile(item.filepath) assert imported_file.artist == "Tag Artist" assert imported_file.album == "Tag Album" beetbox-beets-00724b7/test/plugins/utils/0000775000175000017500000000000015253035401017653 5ustar pieterpieterbeetbox-beets-00724b7/test/plugins/utils/test_vfs.py0000664000175000017500000000142615253035401022065 0ustar pieterpieter"""Tests for the virtual filesystem builder..""" from beets.test import _common from beets.test.helper import BeetsTestCase from beetsplug._utils import vfs class VFSTest(BeetsTestCase): def setUp(self): super().setUp() self.lib.path_formats = [ ("default", "albums/$album/$title"), ("singleton:true", "tracks/$artist/$title"), ] self.lib.add(_common.item()) self.lib.add_album([_common.item()]) self.tree = vfs.libtree(self.lib) def test_singleton_item(self): assert ( self.tree.dirs["tracks"].dirs["the artist"].files["the title"] == 1 ) def test_album_item(self): assert ( self.tree.dirs["albums"].dirs["the album"].files["the title"] == 2 ) beetbox-beets-00724b7/test/plugins/utils/test_playcount.py0000664000175000017500000001535615253035401023314 0ustar pieterpieterimport pytest from beets import logging from beets.library import Item from beets.test.helper import TestHelper from beetsplug._utils.playcount import ( get_items, process_track, update_play_counts, ) LOGGER_NAME = "beets.test_playcount" class TestPlayCount(TestHelper): @pytest.fixture def log(self): log = logging.getLogger(LOGGER_NAME) log.set_global_level(logging.DEBUG) return log def track(self, **overrides): return { "mbid": "", "artist": "Artist", "name": "Song", "playcount": 1, **overrides, } def get_playcount(self, item_id, source="lastfm"): field = f"{source}_play_count" return int(self.lib.get_item(item_id).get(field, 0)) def add_item( self, *, title="Song", artist="Artist", album="Album", mb_trackid="", play_count=None, source="lastfm", ): item = Item( title=title, artist=artist, album=album, mb_trackid=mb_trackid ) self.lib.add(item) if play_count is not None: item[f"{source}_play_count"] = play_count item.store() return item @pytest.mark.parametrize( "item_kwargs, track_kwargs", [ pytest.param( {"title": "Song", "artist": "Artist"}, {"playcount": 7}, id="artist-and-title", ), pytest.param( { "title": "Different Song", "artist": "Different Artist", "mb_trackid": "track-id", }, {"mbid": "track-id", "playcount": 5}, id="musicbrainz-track-id", ), pytest.param( { "title": "Song", "artist": "Different Artist", "album": "Album", }, {"album": "Album", "playcount": 3}, id="album-and-title", ), pytest.param( {"title": "Don\u2019t Stop", "artist": "Artist"}, {"name": "Don't Stop", "playcount": 11}, id="apostrophe-normalized", ), ], ) def test_get_items_matches_supported_query_paths( self, log, item_kwargs, track_kwargs ): item = self.add_item(**item_kwargs) matched_ids = [ matched.id for matched in get_items(self.lib, self.track(**track_kwargs), log) ] assert matched_ids == [item.id] def test_get_items_mbid_match_suppresses_title_match(self, log): by_mbid = self.add_item( title="Song", artist="Artist", mb_trackid="track-id" ) self.add_item(title="Song", artist="Artist", mb_trackid="other-id") matched_ids = [ matched.id for matched in get_items(self.lib, self.track(mbid="track-id"), log) ] assert matched_ids == [by_mbid.id] def test_get_items_prefers_exact_match(self, log): exact_match = self.add_item(title="Song", artist="Artist") self.add_item(title="Song (inst.)", artist="Artist") matched_ids = [ matched.id for matched in get_items(self.lib, self.track(), log) ] assert matched_ids == [exact_match.id] def test_get_items_falls_back_to_substring_match(self, log): substring_match = self.add_item( title="Song (feat. Artist)", artist="Artist" ) matched_ids = [ matched.id for matched in get_items(self.lib, self.track(), log) ] assert matched_ids == [substring_match.id] def test_process_track_updates_every_matching_song(self, log): first = self.add_item( title="Song", artist="Artist", album="First Album", play_count=1 ) second = self.add_item( title="Song", artist="Artist", album="Second Album", play_count=9 ) assert ( process_track(self.lib, self.track(playcount=0), log, "lastfm") is True ) assert self.get_playcount(first.id) == 0 assert self.get_playcount(second.id) == 0 def test_process_track_returns_false_when_nothing_matches(self, log): assert ( process_track( self.lib, self.track( artist="Missing Artist", name="Missing Song", album="Missing Album", playcount=4, ), log, "lastfm", ) is False ) def test_process_track_updates_requested_source_field(self, log): new_count = 6 item = self.add_item(play_count=1, source="lastfm") assert ( process_track( self.lib, self.track(playcount=new_count), log, "listenbrainz" ) is True ) assert self.get_playcount(item.id, "lastfm") == 1 assert self.get_playcount(item.id, "listenbrainz") == new_count @pytest.mark.parametrize( "tracks, expected_counts, expected_summary, expected_playcount", [ pytest.param([], (0, 0), None, None, id="empty-page"), pytest.param( [ {"artist": "Artist", "name": "Known Song", "playcount": 8}, { "artist": "Missing Artist", "name": "Missing Song", "playcount": 2, }, ], (1, 1), "Acquired 1/2 play-counts (1 unknown)", 8, id="mixed-results", ), ], ) def test_update_play_counts_counts_and_logs_summary( self, log, tracks, expected_counts, expected_summary, expected_playcount, caplog, ): item = self.add_item(title="Known Song", artist="Artist", play_count=1) with caplog.at_level("DEBUG", logger=LOGGER_NAME): assert ( update_play_counts( self.lib, [self.track(**track) for track in tracks], log, "lastfm", ) == expected_counts ) assert any( f"Received {len(tracks)} tracks in this page, processing..." in msg for msg in caplog.messages ) if expected_summary is None: assert not any("Acquired" in msg for msg in caplog.messages) else: assert expected_summary in caplog.text assert self.get_playcount(item.id) == expected_playcount beetbox-beets-00724b7/test/plugins/utils/test_requests.py0000664000175000017500000000233415253035401023141 0ustar pieterpieterfrom unittest.mock import MagicMock import pytest import requests from beetsplug._utils.requests import RateLimitAdapter def _prepared_request( url: str = "https://example.com", ) -> requests.PreparedRequest: req = requests.Request("GET", url) return req.prepare() class TestRateLimitAdapter: @pytest.mark.parametrize( "last_request_time, now, expected_sleep", [(100.0, 100.0, 0.25), (100.0, 100.1, 0.15)], ) def test_send_sleeps_for_remaining_time( self, monkeypatch, last_request_time, now, expected_sleep ): adapter = RateLimitAdapter(rate_limit=0.25) request = _prepared_request() send_mock = MagicMock(return_value="ok") monkeypatch.setattr( "beetsplug._utils.requests.HTTPAdapter.send", send_mock ) monkeypatch.setattr( "beetsplug._utils.requests.time.monotonic", lambda: now ) sleep_mock = MagicMock() monkeypatch.setattr("beetsplug._utils.requests.time.sleep", sleep_mock) adapter._last_request_time = last_request_time adapter.send(request) assert sleep_mock.call_count == 1 assert sleep_mock.call_args.args[0] == pytest.approx(expected_sleep) beetbox-beets-00724b7/test/plugins/utils/__init__.py0000664000175000017500000000000015253035401021752 0ustar pieterpieterbeetbox-beets-00724b7/test/plugins/utils/test_musicbrainz.py0000664000175000017500000001175315253035401023621 0ustar pieterpieterimport pytest from beetsplug._utils.musicbrainz import MusicBrainzAPI def test_normalize_data(): raw_release = { "id": "r1", "relations": [ { "target-type": "artist", "type": "vocal", "type-id": "0fdbe3c6-7700-4a31-ae54-b53f06ae1cfa", "name": "A", }, { "target-type": "url", "type": "streaming", "type-id": "b5f3058a-666c-406f-aafb-f9249fc7b122", "url": "http://s", }, { "target-type": "url", "type": "purchase for download", "type-id": "92777657-504c-4acb-bd33-51a201bd57e1", "url": "http://p", }, { "target-type": "work", "type": "performance", "type-id": "a3005666-a872-32c3-ad06-98af558e99b0", "work": { "relations": [ { "artist": {"name": "幾田りら"}, "target-type": "artist", "type": "composer", "type-id": "d59d99ea-23d4-4a80-b066-edca32ee158f", }, { "target-type": "url", "type": "lyrics", "type-id": "e38e65aa-75e0-42ba-ace0-072aeb91a538", "url": { "resource": "https://utaten.com/lyric/tt24121002/" }, }, { "artist": {"name": "幾田りら"}, "target-type": "artist", "type": "lyricist", "type-id": "3e48faba-ec01-47fd-8e89-30e81161661c", }, { "target-type": "url", "type": "lyrics", "type-id": "e38e65aa-75e0-42ba-ace0-072aeb91a538", "url": { "resource": "https://www.uta-net.com/song/366579/" }, }, ], "title": "百花繚乱", "type": "Song", }, }, ], } assert MusicBrainzAPI._normalize_data(raw_release) == { "id": "r1", "artist_relations": [ { "type": "vocal", "type_id": "0fdbe3c6-7700-4a31-ae54-b53f06ae1cfa", "name": "A", } ], "url_relations": [ { "type": "streaming", "type_id": "b5f3058a-666c-406f-aafb-f9249fc7b122", "url": "http://s", }, { "type": "purchase for download", "type_id": "92777657-504c-4acb-bd33-51a201bd57e1", "url": "http://p", }, ], "work_relations": [ { "type": "performance", "type_id": "a3005666-a872-32c3-ad06-98af558e99b0", "work": { "artist_relations": [ { "type": "composer", "type_id": "d59d99ea-23d4-4a80-b066-edca32ee158f", "artist": {"name": "幾田りら"}, }, { "type": "lyricist", "type_id": "3e48faba-ec01-47fd-8e89-30e81161661c", "artist": {"name": "幾田りら"}, }, ], "url_relations": [ { "type": "lyrics", "type_id": "e38e65aa-75e0-42ba-ace0-072aeb91a538", "url": { "resource": "https://utaten.com/lyric/tt24121002/" }, }, { "type": "lyrics", "type_id": "e38e65aa-75e0-42ba-ace0-072aeb91a538", "url": { "resource": "https://www.uta-net.com/song/366579/" }, }, ], "title": "百花繚乱", "type": "Song", }, } ], } @pytest.mark.parametrize( "field, term, expected", [ ("artist", ' AC/DC + "[Live]" ', r"artist:(ac\/dc \+ \"\[live\]\")"), ("", "Foo:Bar", r"foo\:bar"), ("artist", " ", ""), ], ) def test_format_search_term(field, term, expected): assert MusicBrainzAPI.format_search_term(field, term) == expected beetbox-beets-00724b7/test/plugins/test_convert.py0000664000175000017500000002546315253035401021616 0ustar pieterpieterfrom __future__ import annotations import fnmatch import os import shlex import sys from typing import TYPE_CHECKING import pytest from mediafile import MediaFile from beets import util from beets.library import Item from beets.test import _common from beets.test.helper import ( AsIsImporterMixin, ImportHelper, IOMixin, PluginTestHelper, ) from beetsplug import convert if TYPE_CHECKING: from pathlib import Path _p = pytest.param class ConvertPluginHelper(IOMixin, PluginTestHelper): db_on_disk = True plugin = "convert" def setup_beets(self): super().setup_beets() self.convert_dest = self.temp_path / "convert_dest" self.config["convert"] = {"dest": str(self.convert_dest)} def tagged_copy_cmd(self, tag): """Return a conversion command that copies files and appends `tag` to the copy. """ # A Python script that copies the file and appends a tag. stub = str(_common.RSRC / "convert_stub.py") return f"{shlex.quote(sys.executable)} {shlex.quote(stub)} $source $dest {tag}" def file_endswith(self, path: Path, tag: str): """Check the path is a file and if its content ends with `tag`.""" assert path.exists() assert path.is_file() return path.read_bytes().endswith(tag.encode("utf-8")) class TestImportConvert(AsIsImporterMixin, ImportHelper, ConvertPluginHelper): def setup_beets(self): super().setup_beets() self.config["convert"] = { "command": self.tagged_copy_cmd("convert"), # Enforce running convert "max_bitrate": 1, "auto": True, "quiet": False, } def test_import_converted(self): self.run_asis_importer() item = self.lib.items().get() assert self.file_endswith(item.filepath, "convert") # FIXME: fails on windows @pytest.mark.skipif(sys.platform == "win32", reason="win32") def test_import_original_on_convert_error(self): # `false` exits with non-zero code self.config["convert"]["command"] = "false" self.run_asis_importer() item = self.lib.items().get() assert item is not None assert item.filepath.is_file() def test_delete_originals(self): self.config["convert"]["delete_originals"] = True self.run_asis_importer() for path in self.importer.paths: for root, dirnames, filenames in os.walk(path): assert len(fnmatch.filter(filenames, "*.mp3")) == 0, ( f"Non-empty import directory {util.displayable_path(path)}" ) class ConvertCommand: """A mixin providing a utility method to run the `convert`command in tests. """ def run_convert_path(self, item, *args): """Run the `convert` command on a given path.""" return self.run_command("convert", *args, f"path:{item.filepath}") def run_convert(self, *args): """Run the `convert` command on `self.item`.""" return self.run_convert_path(self.item, *args) class TestConvertCli(ConvertPluginHelper, ConvertCommand): def setup_beets(self): super().setup_beets() self.album = self.add_album_fixture(ext="ogg") self.item = self.album.items()[0] self.converted_mp3 = self.convert_dest / "converted.mp3" self.config["convert"] = { "paths": {"default": "converted"}, "format": "mp3", "formats": { "mp3": self.tagged_copy_cmd("mp3"), "ogg": self.tagged_copy_cmd("ogg"), "opus": { "command": self.tagged_copy_cmd("opus"), "extension": "ops", }, }, } def test_convert(self): self.io.addinput("y") self.run_convert() assert self.file_endswith(self.converted_mp3, "mp3") def test_convert_with_auto_confirmation(self): self.run_convert("--yes") assert self.file_endswith(self.converted_mp3, "mp3") def test_reject_confirmation(self): self.io.addinput("n") self.run_convert() assert not self.converted_mp3.exists() def test_convert_keep_new(self): assert self.item.filepath.suffix == ".ogg" self.io.addinput("y") self.run_convert("--keep-new") self.item.load() assert self.item.filepath.suffix == ".mp3" def test_format_option(self): self.io.addinput("y") self.run_convert("--format", "opus") assert self.file_endswith(self.convert_dest / "converted.ops", "opus") def test_embed_album_art(self): self.config["convert"]["embed"] = True image_path = _common.RSRC / "image-2x3.jpg" self.album.artpath = image_path self.album.store() image_data = image_path.read_bytes() self.io.addinput("y") self.run_convert() mediafile = MediaFile(self.converted_mp3) assert mediafile.images[0].data == image_data def test_copy_album_art_missing_source(self, caplog): # A missing/stale art source should be skipped instead of crashing # the conversion (see #4692). self.config["convert"]["copy_album_art"] = True self.album.artpath = _common.RSRC / "nonexistent.jpg" self.album.store() with caplog.at_level("INFO", logger="beets.convert"): self.run_command("convert", "-a", "--yes") assert any( "source file not found" in message for message in caplog.messages ) assert self.file_endswith(self.converted_mp3, "mp3") def test_skip_existing(self): converted = self.converted_mp3 util.mkdirall(converted) converted.write_text("XXX") self.run_convert("--yes") assert converted.read_text() == "XXX" def test_pretend(self): self.run_convert("--pretend") assert not self.converted_mp3.exists() def test_empty_query(self, caplog): with caplog.at_level("INFO", logger="beets.convert"): self.run_convert("An impossible query") assert caplog.messages[0] == "Empty query result." @pytest.mark.parametrize( "max_bitrate,convert_format,args,should_transcode", [ _p(5000, "mp3", (), True, id="different-format-high-bitrate"), _p(5, "mp3", (), True, id="different-format-low-bitrate"), _p(None, "mp3", (), True, id="different-format-no-max-bitrate"), _p(5000, "ogg", (), False, id="same-format-high-bitrate"), _p(5000, "ogg", ("--force",), True, id="same-format-force"), _p(5, "ogg", (), True, id="same-format-low-bitrate"), _p(None, "ogg", (), False, id="same-format-no-max-bitrate"), ], ) def test_transcode_selection( self, max_bitrate, convert_format, args, should_transcode ): if max_bitrate is not None: self.config["convert"]["max_bitrate"] = max_bitrate self.config["convert"]["format"] = convert_format self.io.addinput("y") self.run_convert(*args) converted_path = self.convert_dest / f"converted.{convert_format}" assert ( self.file_endswith(converted_path, convert_format) is should_transcode ) def test_playlist(self): self.io.addinput("y") self.run_convert("--playlist", "playlist.m3u8") assert (self.convert_dest / "playlist.m3u8").exists() def test_playlist_pretend(self): self.run_convert("--playlist", "playlist.m3u8", "--pretend") assert not (self.convert_dest / "playlist.m3u8").exists() @pytest.mark.parametrize( "config_overrides", [ _p({"no_convert": "format:ogg"}, id="no-covert"), _p({"never_convert_lossy_files": True}, id="never-convert-lossy-files"), ], ) # fmt: skip def test_force_overrides(self, config_overrides): [item] = self.add_item_fixtures(ext="ogg") self.io.addinput("y") with self.configure_plugin(config_overrides): self.run_convert_path(item, "--format", "opus", "--force") converted = self.convert_dest / "converted.ops" assert self.file_endswith(converted, "opus") @pytest.mark.parametrize( "args,no_convert,expected_entry", [ _p((), None, "converted.mp3", id="config-format"), _p(("--format", "opus"), None, "converted.ops", id="cli-format"), _p((), "format:ogg", "converted.ogg", id="not-transcoded"), _p(("--keep-new",), None, "converted.ogg", id="keep-new"), ], ) def test_playlist_entry(self, args, no_convert, expected_entry): if no_convert: self.config["convert"]["no_convert"] = no_convert self.io.addinput("y") self.run_convert(*args, "--playlist", "playlist.m3u8") lines = (self.convert_dest / "playlist.m3u8").read_text().splitlines() assert lines[0] == "#EXTM3U" assert lines[1] == expected_entry class TestNeverConvertLossyFiles(ConvertPluginHelper, ConvertCommand): """Test the effect of the `never_convert_lossy_files` option.""" @pytest.mark.parametrize( "source_ext,never_convert_lossy_files,expected_ext,should_convert", [ _p("flac", True, "mp3", True, id="lossless-converts-flag-on"), _p("flac", False, "mp3", True, id="lossless-converts-flag-off"), _p("ogg", False, "mp3", True, id="lossy-converts-allowed"), _p("ogg", True, "ogg", False, id="lossy-kept-prevented"), ], ) def test_transcode( self, source_ext, never_convert_lossy_files, expected_ext, should_convert, ): [item] = self.add_item_fixtures(ext=source_ext) self.io.addinput("y") convert_fmt = "mp3" config = { "paths": {"default": "converted"}, "format": convert_fmt, "formats": {convert_fmt: self.tagged_copy_cmd(convert_fmt)}, "never_convert_lossy_files": never_convert_lossy_files, } with self.configure_plugin(config): self.run_convert_path(item) converted = self.convert_dest / f"converted.{expected_ext}" assert self.file_endswith(converted, convert_fmt) is should_convert class TestNoConvert(PluginTestHelper): """Test the effect of the `no_convert` option.""" plugin = "convert" @pytest.mark.parametrize( "config_value, should_skip", [ ("", False), ("bitrate:320", False), ("bitrate:320 format:ogg", False), ("bitrate:320 , format:ogg", True), ], ) def test_no_convert_skip(self, config, config_value, should_skip): item = Item(format="ogg", bitrate=256) config["convert"]["no_convert"] = config_value assert convert.ConvertPlugin().in_no_convert(item) == should_skip beetbox-beets-00724b7/test/plugins/test_rewrite.py0000664000175000017500000000503315253035401021606 0ustar pieterpieterimport pytest from beets.test.helper import PluginTestHelper from beets.ui import UserError from beetsplug.rewrite import RewritePlugin class TestRewritePlugin(PluginTestHelper): plugin = "rewrite" preload_plugin = False def test_artist_rewrite_applies_to_artist_albumartist_and_album_fields( self, ): with self.configure_plugin({"artist .*jimi hendrix.*": "Jimi Hendrix"}): item = self.add_item( artist="The Jimi Hendrix Experience", albumartist="The Jimi Hendrix Experience", ) album = self.lib.add_album([item]) assert item.artist == "Jimi Hendrix" assert item.albumartist == "Jimi Hendrix" assert album.evaluate_template("$albumartist") == "Jimi Hendrix" def test_rewrite_all_matching_rules(self): with self.configure_plugin( { "artist .*hendrix.*": "hendrix catalog", "artist .*catalog.*": "Experience catalog", } ): item = self.add_item( artist="The Jimi Hendrix Experience", albumartist="The Jimi Hendrix Experience", ) assert item.artist == "Experience catalog" def test_rewrite_is_case_insensitive_and_leaves_non_matches_unchanged(self): with self.configure_plugin( {"artist odd eye circle": "LOONA / ODD EYE CIRCLE"} ): matching_item = self.add_item( artist="ODD EYE CIRCLE", albumartist="ODD EYE CIRCLE" ) other_item = self.add_item(artist="ARTMS", albumartist="ARTMS") assert matching_item.artist == "LOONA / ODD EYE CIRCLE" assert other_item.artist == "ARTMS" def test_rewrite_applied_to_all_list_values(self): with self.configure_plugin( {"genres rock": "Classic Rock", "genres pop": "Pop"} ): item = self.add_item(genres=["rock", "pop", "techno"]) assert item.genres == ["Classic Rock", "Pop", "techno"] def test_invalid_rewrite_spec_raises_user_error(self): self.config[self.plugin].set({"artist": "Jimi Hendrix"}) with pytest.raises(UserError, match="invalid rewrite specification"): RewritePlugin() def test_invalid_field_name_raises_user_error(self): self.config[self.plugin].set({"not_a_field rock": "Classic Rock"}) with pytest.raises( UserError, match="invalid field name \\(not_a_field\\) in rewriter" ): RewritePlugin() beetbox-beets-00724b7/test/plugins/test_info.py0000664000175000017500000000620015253035401021055 0ustar pieterpieterimport os from mediafile import MediaFile from beets.test.helper import IOMixin, PluginTestCase class InfoTest(IOMixin, PluginTestCase): plugin = "info" def test_path(self): path = self.create_mediafile_fixture() mediafile = MediaFile(path) mediafile.albumartist = "AAA" mediafile.disctitle = "DDD" mediafile.genres = ["a", "b", "c"] mediafile.composer = None mediafile.save() out = self.run_with_output("info", str(path)) assert os.fsdecode(path) in out assert "albumartist: AAA" in out assert "disctitle: DDD" in out assert "genres: a; b; c" in out assert "composer:" not in out def test_item_query(self): item1, item2 = self.add_item_fixtures(count=2) item1.album = "xxxx" item1.write() item1.album = "yyyy" item1.store() out = self.run_with_output("info", "album:yyyy") assert str(item1.filepath) in out assert "album: xxxx" in out assert str(item2.filepath) not in out def test_item_library_query(self): (item,) = self.add_item_fixtures() item.album = "xxxx" item.store() out = self.run_with_output("info", "--library", "album:xxxx") assert str(item.filepath) in out assert "album: xxxx" in out def test_collect_item_and_path(self): path = self.create_mediafile_fixture() mediafile = MediaFile(path) (item,) = self.add_item_fixtures() item.album = mediafile.album = "AAA" item.tracktotal = mediafile.tracktotal = 5 item.title = "TTT" mediafile.title = "SSS" item.write() item.store() mediafile.save() out = self.run_with_output( "info", "--summarize", "album:AAA", str(path) ) assert "album: AAA" in out assert "tracktotal: 5" in out assert "title: [various]" in out def test_collect_item_and_path_with_multi_values(self): path = self.create_mediafile_fixture() mediafile = MediaFile(path) (item,) = self.add_item_fixtures() item.album = mediafile.album = "AAA" item.tracktotal = mediafile.tracktotal = 5 item.title = "TTT" mediafile.title = "SSS" item.albumartists = ["Artist A", "Artist B"] mediafile.albumartists = ["Artist C", "Artist D"] item.artists = ["Artist A", "Artist Z"] mediafile.artists = ["Artist A", "Artist Z"] item.write() item.store() mediafile.save() out = self.run_with_output( "info", "--summarize", "album:AAA", str(path) ) assert "album: AAA" in out assert "tracktotal: 5" in out assert "title: [various]" in out assert "albumartists: [various]" in out assert "artists: Artist A; Artist Z" in out def test_custom_format(self): self.add_item_fixtures() out = self.run_with_output( "info", "--library", "--format", "$track. $title - $artist ($length)", ) assert "02. tïtle 0 - the artist (0:01)\n" == out beetbox-beets-00724b7/test/plugins/test_limit.py0000664000175000017500000000621215253035401021243 0ustar pieterpieter"""Tests for the 'limit' plugin.""" from beets.test.helper import IOMixin, PluginTestCase class LimitPluginTest(IOMixin, PluginTestCase): """Unit tests for LimitPlugin Note: query prefix tests do not work correctly with `run_with_output`. """ plugin = "limit" def setUp(self): super().setUp() # we'll create an even number of tracks in the library self.num_test_items = 10 assert self.num_test_items % 2 == 0 for item_no, item in enumerate( self.add_item_fixtures(count=self.num_test_items) ): item.track = item_no + 1 item.store() # our limit tests will use half of this number self.num_limit = self.num_test_items // 2 self.num_limit_prefix = "".join(["'", "<", str(self.num_limit), "'"]) # a subset of tests has only `num_limit` results, identified by a # range filter on the track number self.track_head_range = f"track:..{self.num_limit}" self.track_tail_range = f"track:{self.num_limit + 1}{'..'}" def test_no_limit(self): """Returns all when there is no limit or filter.""" result = self.run_with_output("lslimit") assert result.count("\n") == self.num_test_items def test_lslimit_head(self): """Returns the expected number with `lslimit --head`.""" result = self.run_with_output("lslimit", "--head", str(self.num_limit)) assert result.count("\n") == self.num_limit def test_lslimit_tail(self): """Returns the expected number with `lslimit --tail`.""" result = self.run_with_output("lslimit", "--tail", str(self.num_limit)) assert result.count("\n") == self.num_limit def test_lslimit_head_invariant(self): """Returns the expected number with `lslimit --head` and a filter.""" result = self.run_with_output( "lslimit", "--head", str(self.num_limit), self.track_tail_range ) assert result.count("\n") == self.num_limit def test_lslimit_tail_invariant(self): """Returns the expected number with `lslimit --tail` and a filter.""" result = self.run_with_output( "lslimit", "--tail", str(self.num_limit), self.track_head_range ) assert result.count("\n") == self.num_limit def test_prefix(self): """Returns the expected number with the query prefix.""" result = self.lib.items(self.num_limit_prefix) assert len(result) == self.num_limit def test_prefix_when_correctly_ordered(self): """Returns the expected number with the query prefix and filter when the prefix portion (correctly) appears last.""" correct_order = f"{self.track_tail_range} {self.num_limit_prefix}" result = self.lib.items(correct_order) assert len(result) == self.num_limit def test_prefix_when_incorrectly_ordred(self): """Returns no results with the query prefix and filter when the prefix portion (incorrectly) appears first.""" incorrect_order = f"{self.num_limit_prefix} {self.track_tail_range}" result = self.lib.items(incorrect_order) assert len(result) == 0 beetbox-beets-00724b7/test/plugins/test_ipfs.py0000664000175000017500000000653115253035401021072 0ustar pieterpieterimport os from pathlib import Path from unittest.mock import Mock, patch from beets import library, util from beets.test import _common from beets.test.helper import PluginTestCase, PluginTestHelper from beetsplug.ipfs import IPFSPlugin @patch("beets.util.command_output", Mock()) class IPFSPluginTest(PluginTestCase): plugin = "ipfs" def test_stored_hashes(self): test_album = self.mk_test_album() ipfs = IPFSPlugin() added_albums = ipfs.ipfs_added_albums(self.lib, self.lib.path) with added_albums.music_dir_context(): added_album = added_albums.get_album(1) assert added_album.ipfs == test_album.ipfs found = False want_item = test_album.items()[2] for check_item in added_album.items(): if check_item.get("ipfs", with_album=False): ipfs_item = want_item.filepath.name want_path = ( Path("/ipfs").resolve() / test_album.ipfs / ipfs_item ) assert check_item.filepath == want_path assert ( check_item.get("ipfs", with_album=False) == want_item.ipfs ) assert check_item.title == want_item.title found = True assert found def test_get_remote_lib_accepts_library_path(self): self.lib.path = self.temp_path / "library.db" remote_dir = self.temp_path / "remotes" remote_dir.mkdir() remote_lib = library.Library(remote_dir / "joined.db") remote_lib._close() ipfs = IPFSPlugin() with ipfs.remote_lib(self.lib) as added_lib: assert added_lib.path == remote_dir / "joined.db" def mk_test_album(self): items = [_common.item() for _ in range(3)] items[0].title = "foo bar" items[0].artist = "1one" items[0].album = "baz" items[0].year = 2001 items[0].comp = True items[1].title = "baz qux" items[1].artist = "2two" items[1].album = "baz" items[1].year = 2002 items[1].comp = True items[2].title = "beets 4 eva" items[2].artist = "3three" items[2].album = "foo" items[2].year = 2003 items[2].comp = False items[2].ipfs = "QmfM9ic5LJj7V6ecozFx1MkSoaaiq3PXfhJoFvyqzpLXSk" for item in items: self.lib.add(item) album = self.lib.add_album(items) album.ipfs = "QmfM9ic5LJj7V6ecozFx1MkSoaaiq3PXfhJoFvyqzpLXSf" album.store(inherit=False) return album class TestIPFSPlay(PluginTestHelper): plugin = "ipfs" db_on_disk = True def test_ipfs_play(self, monkeypatch): """Test that ipfs successfully calls PlayPlugin's play method.""" # do not attempt to actually play the music monkeypatch.setattr("beetsplug.play.play", lambda *_: None) # we need some music to play self.add_album_fixture() # create remote lib in the expected place, # see IPFSPlugin._remote_libs_path remote_dir = Path(os.fsdecode(self.lib.path)).parent / "remotes" remote_dir.mkdir() util.copy(self.lib.path, remote_dir / "joined.db") # check that we can play without any errors IPFSPlugin().ipfs_play(self.lib, None, []) beetbox-beets-00724b7/test/plugins/test_export.py0000664000175000017500000000464615253035401021457 0ustar pieterpieter"""Test the beets.export utilities associated with the export plugin.""" import json import re # used to test csv format from xml.etree import ElementTree from xml.etree.ElementTree import Element from beets.test.helper import IOMixin, PluginTestCase class ExportPluginTest(IOMixin, PluginTestCase): plugin = "export" def setUp(self): super().setUp() self.test_values = {"title": "xtitle", "album": "xalbum"} def execute_command(self, format_type, artist): query = ",".join(self.test_values.keys()) return self.run_with_output( "export", "-f", format_type, "-i", query, artist ) def create_item(self): (item,) = self.add_item_fixtures() item.artist = "xartist" item.title = self.test_values["title"] item.album = self.test_values["album"] item.write() item.store() return item def test_json_output(self): item1 = self.create_item() out = self.execute_command(format_type="json", artist=item1.artist) json_data = json.loads(out)[0] for key, val in self.test_values.items(): assert key in json_data assert val == json_data[key] def test_jsonlines_output(self): item1 = self.create_item() out = self.execute_command(format_type="jsonlines", artist=item1.artist) json_data = json.loads(out) for key, val in self.test_values.items(): assert key in json_data assert val == json_data[key] def test_csv_output(self): item1 = self.create_item() out = self.execute_command(format_type="csv", artist=item1.artist) csv_list = re.split("\r", re.sub("\n", "", out)) head = re.split(",", csv_list[0]) vals = re.split(",|\r", csv_list[1]) for index, column in enumerate(head): assert self.test_values.get(column, None) is not None assert vals[index] == self.test_values[column] def test_xml_output(self): item1 = self.create_item() out = self.execute_command(format_type="xml", artist=item1.artist) library = ElementTree.fromstring(out) assert isinstance(library, Element) for track in library[0]: for details in track: tag = details.tag txt = details.text assert tag in self.test_values, tag assert self.test_values[tag] == txt, txt beetbox-beets-00724b7/test/plugins/test_missing.py0000664000175000017500000002021615253035401021576 0ustar pieterpieter"""Tests for the `missing` plugin.""" import re import uuid from unittest.mock import patch import pytest from beets.autotag import AlbumInfo, TrackInfo from beets.library import Album, Item from beets.test.helper import IOMixin, PluginTestHelper class MissingTestHelper(IOMixin, PluginTestHelper): plugin = "missing" class TestMissingAlbums(MissingTestHelper): """Tests for missing albums functionality.""" @pytest.mark.parametrize( "release_from_mb,expected_output", [ pytest.param( {"id": "other", "title": "Other Album"}, "Artist - Other Album\n", id="missing", ), pytest.param( {"id": "release_group_in_lib", "title": "Album"}, "", id="not missing", ), ], ) def test_missing_artist_albums( self, requests_mock, release_from_mb, expected_output ): artist_mbid = str(uuid.uuid4()) self.lib.add( Album( album="Album", albumartist="Artist", mb_albumartistid=artist_mbid, mb_albumid="album", mb_releasegroupid="release_group_in_lib", ) ) requests_mock.get( re.compile( rf"/ws/2/release-group\?artist={artist_mbid}&.*type=album" ), json={"release-groups": [release_from_mb]}, ) with self.configure_plugin({}): assert self.run_with_output("missing", "--album") == expected_output def test_missing_albums_custom_format(self, requests_mock): """Test -f/--format is honored when listing missing albums.""" artist_mbid = str(uuid.uuid4()) self.lib.add( Album( album="Album", albumartist="Artist", mb_albumartistid=artist_mbid, mb_albumid="album", mb_releasegroupid="release_group_in_lib", ) ) requests_mock.get( re.compile( rf"/ws/2/release-group\?artist={artist_mbid}&.*type=album" ), json={ "release-groups": [ { "id": "other", "title": "Other Album", "primary-type": "Album", } ] }, ) with self.configure_plugin({}): output = self.run_with_output( "missing", "-a", "-f", "$mb_releasegroupid | $albumtype | $album", ) assert output == "other | album | Other Album\n" def test_release_types_filters_results(self, requests_mock): """Test --release-types filters to only show specified type.""" artist_mbid = str(uuid.uuid4()) self.lib.add( Album( album="album", albumartist="artist", mb_albumartistid=artist_mbid, mb_albumid="album", mb_releasegroupid="album_id", ) ) requests_mock.get( re.compile(r"/ws/2/release-group.*type=compilation"), json={ "release-groups": [ {"id": "compilation_id", "title": "compilation"} ] }, ) with self.configure_plugin({}): output = self.run_with_output( "missing", "-a", "--release-types", "compilation" ) assert "artist - compilation" in output def test_release_types_comma_separated(self, requests_mock): """Test --release-types with comma-separated values.""" artist_mbid = str(uuid.uuid4()) self.lib.add( Album( album="album", albumartist="artist", mb_albumartistid=artist_mbid, mb_albumid="album", mb_releasegroupid="album_id", ) ) requests_mock.get( re.compile(r"/ws/2/release-group.*type=compilation%7Calbum"), json={ "release-groups": [ {"id": "album2_id", "title": "title 2"}, {"id": "compilation_id", "title": "compilation"}, ] }, ) with self.configure_plugin({}): output = self.run_with_output( "missing", "-a", "--release-types", "compilation,album" ) assert "artist - compilation" in output assert "artist - title 2" in output def test_empty_release_types_config_sends_empty_type(self, requests_mock): """Test that release_types: [] in config sends type="" to the API.""" artist_mbid = str(uuid.uuid4()) self.lib.add( Album( album="album", albumartist="artist", mb_albumartistid=artist_mbid, mb_albumid="album", mb_releasegroupid="album_id", ) ) adapter = requests_mock.get( re.compile(r"/ws/2/release-group"), json={"release-groups": []} ) with self.configure_plugin({"release_types": []}): self.run_with_output("missing", "-a") assert adapter.last_request.qs["type"] == [""] def test_missing_albums_total(self, requests_mock): """Test -t flag with --album shows total count of missing albums.""" artist_mbid = str(uuid.uuid4()) self.lib.add( Album( album="album", albumartist="artist", mb_albumartistid=artist_mbid, mb_albumid="album", mb_releasegroupid="album_id", ) ) requests_mock.get( re.compile( rf"/ws/2/release-group\?artist={artist_mbid}&.*type=album" ), json={ "release-groups": [ {"id": "album_id", "title": "album"}, {"id": "other_id", "title": "other"}, ] }, ) with self.configure_plugin({}): output = self.run_with_output("missing", "-a", "-t") assert output == "1\n" class TestMissingTracks(MissingTestHelper): """Tests for missing tracks functionality.""" @pytest.mark.parametrize( "total,count,expected", [(True, False, "1\n"), (False, True, "artist - album: 1")], ) @patch("beets.metadata_plugins.album_for_id") def test_missing_tracks(self, album_for_id, total, count, expected): """Test getting missing tracks works with expected output.""" artist_mbid = str(uuid.uuid4()) album_items = [ Item( album="album", mb_albumid="81ae60d4-5b75-38df-903a-db2cfa51c2c6", mb_releasegroupid="album_id", mb_trackid="track_1", mb_albumartistid=artist_mbid, albumartist="artist", tracktotal=3, ), Item( album="album", mb_albumid="81ae60d4-5b75-38df-903a-db2cfa51c2c6", mb_releasegroupid="album_id", mb_albumartistid=artist_mbid, albumartist="artist", tracktotal=3, ), Item( album="album", mb_albumid="81ae60d4-5b75-38df-903a-db2cfa51c2c6", mb_releasegroupid="album_id", mb_trackid="track_3", mb_albumartistid=artist_mbid, albumartist="artist", tracktotal=3, ), ] self.lib.add_album(album_items[:2]) album_for_id.return_value = AlbumInfo( album_id="album_id", album="album", tracks=[ TrackInfo(track_id=item.mb_trackid) for item in album_items ], ) command = ["missing"] if total: command.append("-t") if count: command.append("-c") with self.configure_plugin({}): assert expected in self.run_with_output(*command) beetbox-beets-00724b7/test/plugins/test_mbsync.py0000664000175000017500000000673515253035401021432 0ustar pieterpieterfrom unittest.mock import Mock, patch from beets.autotag import AlbumInfo, TrackInfo from beets.library import Item from beets.test.helper import PluginTestHelper class TestMbsyncCli(PluginTestHelper): plugin = "mbsync" @patch( "beets.metadata_plugins.album_for_id", Mock( side_effect=lambda *_: AlbumInfo( album_id="album id", album="new album", tracks=[TrackInfo(track_id="track id", title="new title")], ) ), ) @patch( "beets.metadata_plugins.track_for_id", Mock( side_effect=lambda *_: TrackInfo( track_id="singleton id", title="new title" ) ), ) def test_update_library(self): album_item = Item( album="old album", mb_albumid="album id", mb_trackid="track id", data_source="data_source", ) self.lib.add_album([album_item]) singleton = Item( title="old title", mb_trackid="singleton id", data_source="data_source", ) self.lib.add(singleton) self.run_command("mbsync") singleton.load() assert singleton.title == "new title" album_item.load() assert album_item.title == "new title" assert album_item.mb_trackid == "track id" assert album_item.get_album().album == "new album" def test_custom_format(self, caplog): for item in [ Item(artist="albumartist", album="no id"), Item( artist="albumartist", album="invalid id", mb_albumid="a1b2c3d4" ), ]: self.lib.add_album([item]) for item in [ Item(artist="artist", title="no id"), Item(artist="artist", title="invalid id", mb_trackid="a1b2c3d4"), ]: self.lib.add(item) with caplog.at_level("DEBUG", logger="beets.mbsync"): self.run_command("mbsync", "-f", "'%if{$album,$album,$title}'") assert "Skipping album with no mb_albumid: 'no id'" in caplog.messages assert ( "Skipping singleton with no mb_trackid: 'no id'" in caplog.messages ) @patch( "beets.metadata_plugins.album_for_id", Mock( side_effect=lambda *_: AlbumInfo( album_id="album id", album="new album", tracks=[TrackInfo(track_id="track id", title="new title")], ) ), ) @patch( "beets.metadata_plugins.track_for_id", Mock( side_effect=lambda *_: TrackInfo( track_id="singleton id", title="new title" ) ), ) def test_update_library_from_scratch_set(self): self.config["import"]["from_scratch"] = True test_lyrics = "Hello" album_item = Item( album="old album", mb_albumid="album id", mb_trackid="track id", data_source="data_source", lyrics=test_lyrics, ) self.lib.add_album([album_item]) singleton = Item( title="old title", mb_trackid="singleton id", data_source="data_source", lyrics=test_lyrics, ) self.lib.add(singleton) self.run_command("mbsync") singleton.load() assert singleton.lyrics == test_lyrics album_item.load() assert album_item.lyrics == test_lyrics beetbox-beets-00724b7/test/plugins/test_parentwork.py0000664000175000017500000001030115253035401022313 0ustar pieterpieter"""Tests for the 'parentwork' plugin.""" import pytest from beets.library import Item from beets.test.helper import PluginTestCase @pytest.mark.integration_test class ParentWorkIntegrationTest(PluginTestCase): plugin = "parentwork" # test how it works with real musicbrainz data def test_normal_case_real(self): item = Item( path="/file", mb_workid="e27bda6e-531e-36d3-9cd7-b8ebc18e8c53", parentwork_workid_current="e27bda6e-531e-36d3-9cd7-b8ebc18e8c53", ) item.add(self.lib) self.run_command("parentwork") item.load() assert item["mb_parentworkid"] == "32c8943f-1b27-3a23-8660-4567f4847c94" def test_force_real(self): self.config["parentwork"]["force"] = True item = Item( path="/file", mb_workid="e27bda6e-531e-36d3-9cd7-b8ebc18e8c53", mb_parentworkid="XXX", parentwork_workid_current="e27bda6e-531e-36d3-9cd7-b8ebc18e8c53", parentwork="whatever", ) item.add(self.lib) self.run_command("parentwork") item.load() assert item["mb_parentworkid"] == "32c8943f-1b27-3a23-8660-4567f4847c94" def test_no_force_real(self): self.config["parentwork"]["force"] = False item = Item( path="/file", mb_workid="e27bda6e-531e-36d3-9cd7-b8ebc18e8c53", mb_parentworkid="XXX", parentwork_workid_current="e27bda6e-531e-36d3-9cd7-b8ebc18e8c53", parentwork="whatever", ) item.add(self.lib) self.run_command("parentwork") item.load() assert item["mb_parentworkid"] == "XXX" class ParentWorkTest(PluginTestCase): plugin = "parentwork" @pytest.fixture(autouse=True) def patch_works(self, requests_mock): requests_mock.get( "/ws/2/work/1?inc=work-rels%2Bartist-rels", json={ "id": "1", "title": "work", "work-relations": [ { "type": "parts", "direction": "backward", "work": {"id": "2"}, } ], }, ) requests_mock.get( "/ws/2/work/2?inc=work-rels%2Bartist-rels", json={ "id": "2", "title": "directparentwork", "work-relations": [ { "type": "parts", "direction": "backward", "work": {"id": "3"}, } ], }, ) requests_mock.get( "/ws/2/work/3?inc=work-rels%2Bartist-rels", json={ "id": "3", "title": "parentwork", "artist-relations": [ { "type": "composer", "artist": { "name": "random composer", "sort-name": "composer, random", }, } ], }, ) def test_normal_case(self): item = Item(path="/file", mb_workid="1", parentwork_workid_current="1") item.add(self.lib) self.run_command("parentwork") item.load() assert item["mb_parentworkid"] == "3" def test_force(self): self.config["parentwork"]["force"] = True item = Item( path="/file", mb_workid="1", mb_parentworkid="XXX", parentwork_workid_current="1", parentwork="parentwork", ) item.add(self.lib) self.run_command("parentwork") item.load() assert item["mb_parentworkid"] == "3" def test_no_force(self): self.config["parentwork"]["force"] = False item = Item( path="/file", mb_workid="1", mb_parentworkid="XXX", parentwork_workid_current="1", parentwork="parentwork", ) item.add(self.lib) self.run_command("parentwork") item.load() assert item["mb_parentworkid"] == "XXX" beetbox-beets-00724b7/test/plugins/test_listenbrainz.py0000664000175000017500000002647515253035401022646 0ustar pieterpieterimport io import json import zipfile from unittest.mock import patch import pytest from beets import ui from beets.test.helper import ConfigMixin from beetsplug.listenbrainz import ListenBrainzPlugin def _make_zip(files: dict[str, str]) -> bytes: """Build an in-memory zip with the given {name: content} entries.""" buf = io.BytesIO() with zipfile.ZipFile(buf, "w") as zf: for name, content in files.items(): zf.writestr(name, content) return buf.getvalue() class TestListenBrainzPlugin(ConfigMixin): @pytest.fixture(scope="class") def plugin(self) -> ListenBrainzPlugin: self.config["listenbrainz"]["token"] = "test_token" self.config["listenbrainz"]["username"] = "test_user" return ListenBrainzPlugin() @pytest.mark.parametrize( "search_response, expected_id", [([{"id": "id1"}], "id1"), ([], None)], ids=["found", "not_found"], ) def test_get_mb_recording_id( self, plugin, requests_mock, search_response, expected_id ): requests_mock.get( "/ws/2/recording", json={"recordings": search_response} ) track = {"track_metadata": {"track_name": "S", "release_name": "A"}} assert plugin.get_mb_recording_id(track) == expected_id def test_get_track_info(self, plugin, requests_mock): requests_mock.get( "/ws/2/recording/id1?inc=releases", json={ "title": "T", "artist-credit": [], "releases": [{"title": "Al", "date": "2023-01"}], }, ) assert plugin.get_track_info([{"identifier": "id1"}]) == [ { "identifier": "id1", "title": "T", "artist": None, "album": "Al", "year": "2023", } ] def test_aggregate_listens_counts_by_mbid(self, plugin): tracks = [ { "mbid": "m1", "artist": "A", "name": "S", "album": "Al", "playcount": 1, }, { "mbid": "m1", "artist": "A", "name": "S", "album": "Al", "playcount": 1, }, { "mbid": "m1", "artist": "A", "name": "S", "album": "Al", "playcount": 1, }, { "mbid": "m2", "artist": "B", "name": "T", "album": "Bl", "playcount": 1, }, ] result = plugin._aggregate_listens(tracks) by_mbid = {t["mbid"]: t["playcount"] for t in result} assert by_mbid == {"m1": 3, "m2": 1} def test_aggregate_listens_falls_back_to_artist_title_album(self, plugin): tracks = [ { "mbid": None, "artist": "A", "name": "S", "album": "Al", "playcount": 1, }, { "mbid": "", "artist": "A", "name": "S", "album": "Al", "playcount": 1, }, { "mbid": None, "artist": "A", "name": "S", "album": "Al", "playcount": 1, }, ] result = plugin._aggregate_listens(tracks) assert len(result) == 1 assert result[0]["playcount"] == 3 def test_get_listens_paginates(self, plugin): page1 = [ { "listened_at": 100 - i, "track_metadata": { "track_name": f"T{i}", "artist_name": "A", "release_name": "R", }, } for i in range(5) ] page2 = [ { "listened_at": 50 - i, "track_metadata": { "track_name": f"T{5 + i}", "artist_name": "A", "release_name": "R", }, } for i in range(3) ] call_count = 0 def mock_request(url, params=None): nonlocal call_count call_count += 1 if call_count == 1: return {"payload": {"listens": page1}} return {"payload": {"listens": page2}} with patch.object(plugin, "_make_request", side_effect=mock_request): result = plugin.get_listens(count=5) assert len(result) == 8 assert call_count == 2 def test_get_listens_stops_on_empty_page(self, plugin): def mock_request(url, params=None): return {"payload": {"listens": []}} with patch.object(plugin, "_make_request", side_effect=mock_request): result = plugin.get_listens() assert result == [] def test_get_listens_returns_none_on_api_error(self, plugin): def mock_request(url, params=None): return None with patch.object(plugin, "_make_request", side_effect=mock_request): result = plugin.get_listens() assert result is None def test_get_listens_rejects_both_min_and_max_ts(self, plugin): with pytest.raises(ValueError, match="mutually exclusive"): plugin.get_listens(min_ts=1, max_ts=2) def test_get_listens_clamps_count_to_1000(self, plugin): calls = [] def mock_request(url, params=None): calls.append(params) return {"payload": {"listens": []}} with patch.object(plugin, "_make_request", side_effect=mock_request): plugin.get_listens(count=5000) assert calls[0]["count"] == 1000 def test_get_tracks_from_listens_uses_recording_mbid(self, plugin): listens = [ { "listened_at": 1000, "track_metadata": { "track_name": "Song", "artist_name": "Artist", "release_name": "Album", "mbid_mapping": { "recording_mbid": "rec-mbid-123", "release_mbid": "rel-mbid", }, }, } ] tracks = plugin.get_tracks_from_listens(listens) assert tracks[0]["mbid"] == "rec-mbid-123" assert tracks[0]["playcount"] == 1 def test_get_tracks_from_listens_no_mbid_mapping(self, plugin): listens = [ { "listened_at": 1000, "track_metadata": { "track_name": "Song", "artist_name": "Artist", "release_name": "Album", }, } ] tracks = plugin.get_tracks_from_listens(listens) assert tracks[0]["mbid"] is None def test_get_listens_respects_max_total(self, plugin): def mock_request(url, params=None): count = params.get("count", 5) return { "payload": { "listens": [ {"listened_at": 100 - i, "track_metadata": {}} for i in range(count) ] } } with patch.object(plugin, "_make_request", side_effect=mock_request): result = plugin.get_listens(max_total=7) assert len(result) == 7 def test_get_tracks_from_listens_flat_structure(self, plugin): listens = [ { "listened_at": 1000, "track_metadata": { "track_name": "Song", "artist_name": "Artist", "release_name": "Album", "mbid_mapping": {"recording_mbid": "m1"}, }, } ] tracks = plugin.get_tracks_from_listens(listens) t = tracks[0] assert isinstance(t["artist"], str) assert isinstance(t["name"], str) assert t["album"] == "Album" def test_get_tracks_from_listens_null_mbid_mapping(self, plugin): listens = [ { "listened_at": 1000, "track_metadata": { "track_name": "Song", "artist_name": "Artist", "release_name": "Album", "mbid_mapping": None, }, } ] tracks = plugin.get_tracks_from_listens(listens) # should not raise assert tracks[0]["mbid"] is None def test_get_tracks_from_listens_prefers_additional_info_recording_mbid( self, plugin ): listens = [ { "listened_at": 1000, "track_metadata": { "track_name": "Song", "artist_name": "Artist", "release_name": "Album", "additional_info": {"recording_mbid": "rec-mbid-123"}, "mbid_mapping": { "recording_mbid": "rec-mbid-456", "release_mbid": "rel-mbid", }, }, } ] tracks = plugin.get_tracks_from_listens(listens) assert tracks[0]["mbid"] == "rec-mbid-123" assert tracks[0]["playcount"] == 1 def test_import_file_returns_listens(self, plugin, tmp_path): listen = { "listened_at": 1778946700, "track_metadata": {"track_name": "S"}, } zip_path = tmp_path / "export.zip" zip_path.write_bytes( _make_zip({"listens/2026.jsonl": json.dumps(listen) + "\n"}) ) result = plugin.import_listenbrainz_data_export(zip_path) assert result == [listen] def test_import_file_ignores_non_listens_entries(self, plugin, tmp_path): listen = {"listened_at": 1778946700, "track_metadata": {}} zip_path = tmp_path / "export.zip" zip_path.write_bytes( _make_zip( { "listens/2026.jsonl": json.dumps(listen) + "\n", "other/data.jsonl": '{"should": "be ignored"}\n', "listens/readme.txt": "not a jsonl file\n", } ) ) result = plugin.import_listenbrainz_data_export(zip_path) assert result == [listen] def test_import_file_skips_empty_lines(self, plugin, tmp_path): listen = {"listened_at": 1778946700, "track_metadata": {}} content = "\n" + json.dumps(listen) + "\n\n" zip_path = tmp_path / "export.zip" zip_path.write_bytes(_make_zip({"listens/2026.jsonl": content})) result = plugin.import_listenbrainz_data_export(zip_path) assert result == [listen] def test_import_file_skips_invalid_json(self, plugin, tmp_path): listen = {"listened_at": 1778946700, "track_metadata": {}} content = "not valid json\n" + json.dumps(listen) + "\n" zip_path = tmp_path / "export.zip" zip_path.write_bytes(_make_zip({"listens/2026.jsonl": content})) result = plugin.import_listenbrainz_data_export(zip_path) assert result == [listen] def test_import_file_raises_on_missing_file(self, plugin, tmp_path): with pytest.raises(ui.UserError): plugin.import_listenbrainz_data_export(tmp_path / "nonexistent.zip") beetbox-beets-00724b7/test/plugins/test_acousticbrainz.py0000664000175000017500000000537115253035401023152 0ustar pieterpieter"""Tests for the 'acousticbrainz' plugin.""" import json from beets.test._common import RSRC from beetsplug.acousticbrainz import ABSCHEME, AcousticPlugin class TestMapDataToScheme: def test_basic(self): ab = AcousticPlugin() data = {"key 1": "value 1", "key 2": "value 2"} scheme = {"key 1": "attribute 1", "key 2": "attribute 2"} mapping = set(ab._map_data_to_scheme(data, scheme)) assert mapping == { ("attribute 1", "value 1"), ("attribute 2", "value 2"), } def test_recurse(self): ab = AcousticPlugin() data = { "key": "value", "group": { "subkey": "subvalue", "subgroup": {"subsubkey": "subsubvalue"}, }, } scheme = { "key": "attribute 1", "group": { "subkey": "attribute 2", "subgroup": {"subsubkey": "attribute 3"}, }, } mapping = set(ab._map_data_to_scheme(data, scheme)) assert mapping == { ("attribute 1", "value"), ("attribute 2", "subvalue"), ("attribute 3", "subsubvalue"), } def test_composite(self): ab = AcousticPlugin() data = {"key 1": "part 1", "key 2": "part 2"} scheme = {"key 1": ("attribute", 0), "key 2": ("attribute", 1)} mapping = set(ab._map_data_to_scheme(data, scheme)) assert mapping == {("attribute", "part 1 part 2")} def test_realistic(self): ab = AcousticPlugin() data_path = RSRC / "acousticbrainz/data.json" data = json.loads(data_path.read_text()) mapping = set(ab._map_data_to_scheme(data, ABSCHEME)) expected = { ("chords_key", "A"), ("average_loudness", 0.815025985241), ("mood_acoustic", 0.415711194277), ("chords_changes_rate", 0.0445116683841), ("tonal", 0.874250173569), ("mood_sad", 0.299694597721), ("bpm", 162.532119751), ("gender", "female"), ("initial_key", "A minor"), ("chords_number_rate", 0.00194468453992), ("mood_relaxed", 0.123632438481), ("chords_scale", "minor"), ("voice_instrumental", "instrumental"), ("key_strength", 0.636936545372), ("genre_rosamerica", "roc"), ("mood_party", 0.234383180737), ("mood_aggressive", 0.0779221653938), ("danceable", 0.143928021193), ("rhythm", "VienneseWaltz"), ("mood_electronic", 0.339881360531), ("mood_happy", 0.0894767045975), ("moods_mirex", "Cluster3"), ("timbre", "bright"), } assert mapping == expected beetbox-beets-00724b7/test/plugins/test_ihate.py0000664000175000017500000000272715253035401021226 0ustar pieterpieter"""Tests for the 'ihate' plugin""" from beets import importer from beets.library import Item from beetsplug.ihate import IHatePlugin class TestIHatePlugin: def test_hate(self): match_pattern = {} test_item = Item( genres=["TestGenre"], album="TestAlbum", artist="TestArtist" ) task = importer.SingletonImportTask(None, test_item) # Empty query should let it pass. assert not IHatePlugin.do_i_hate_this(task, match_pattern) # 1 query match. match_pattern = ["artist:bad_artist", "artist:TestArtist"] assert IHatePlugin.do_i_hate_this(task, match_pattern) # 2 query matches, either should trigger. match_pattern = ["album:test", "artist:testartist"] assert IHatePlugin.do_i_hate_this(task, match_pattern) # Query is blocked by AND clause. match_pattern = ["album:notthis genres:testgenre"] assert not IHatePlugin.do_i_hate_this(task, match_pattern) # Both queries are blocked by AND clause with unmatched condition. match_pattern = [ "album:notthis genres:testgenre", "artist:testartist album:notthis", ] assert not IHatePlugin.do_i_hate_this(task, match_pattern) # Only one query should fire. match_pattern = [ "album:testalbum genres:testgenre", "artist:testartist album:notthis", ] assert IHatePlugin.do_i_hate_this(task, match_pattern) beetbox-beets-00724b7/test/plugins/test_keyfinder.py0000664000175000017500000000350515253035401022107 0ustar pieterpieterfrom unittest.mock import patch from beets import util from beets.library import Item from beets.test.helper import AsIsImporterMixin, ImportHelper, PluginMixin @patch("beets.util.command_output") class TestKeyFinder(AsIsImporterMixin, PluginMixin, ImportHelper): plugin = "keyfinder" def test_add_key(self, command_output): item = Item(path="/file") item.add(self.lib) command_output.return_value = util.CommandOutput(b"dbm", b"") self.run_command("keyfinder") item.load() assert item["initial_key"] == "C#m" command_output.assert_called_with( ["KeyFinder", "-f", util.syspath(item.path)] ) def test_add_key_on_import(self, command_output): command_output.return_value = util.CommandOutput(b"dbm", b"") self.run_asis_importer() item = self.lib.items().get() assert item["initial_key"] == "C#m" def test_force_overwrite(self, command_output): self.config["keyfinder"]["overwrite"] = True item = Item(path="/file", initial_key="F") item.add(self.lib) command_output.return_value = util.CommandOutput(b"C#m", b"") self.run_command("keyfinder") item.load() assert item["initial_key"] == "C#m" def test_do_not_overwrite(self, command_output): item = Item(path="/file", initial_key="F") item.add(self.lib) command_output.return_value = util.CommandOutput(b"dbm", b"") self.run_command("keyfinder") item.load() assert item["initial_key"] == "F" def test_no_key(self, command_output): item = Item(path="/file") item.add(self.lib) command_output.return_value = util.CommandOutput(b"", b"") self.run_command("keyfinder") item.load() assert item["initial_key"] is None beetbox-beets-00724b7/test/plugins/test_discogs.py0000664000175000017500000007275715253035401021601 0ustar pieterpieter"""Tests for discogs plugin.""" from __future__ import annotations import json from typing import TYPE_CHECKING, Any from unittest.mock import MagicMock import pytest from discogs_client import Client, Release from beets import config from beets.library import Item from beets.metadata_plugins import SearchParams from beets.test.helper import TestHelper from beetsplug.discogs import ArtistState, DiscogsPlugin from .factories import discogs as factories if TYPE_CHECKING: from beetsplug.discogs import types _p = pytest.param def _artist(name: str, **kwargs): return { "id": 1, "name": name, "join": "", "role": "", "anv": "", "tracks": "", "resource_url": "", } | kwargs def audio_track( title: str, position: str = "", duration: str = "", **kwargs ) -> types.AudioTrack: kwargs.update(title=title, position=position, duration=duration) return factories.AudioTrackFactory.build(**kwargs) def index_track( title: str, sub_tracks: list[types.AudioTrack], **kwargs ) -> types.IndexTrack: kwargs.update(title=title, sub_tracks=sub_tracks) return factories.IndexTrackFactory.build(**kwargs) def heading_track(title: str, **kwargs) -> types.HeadingTrack: kwargs.update(title=title) return factories.HeadingTrackFactory.build(**kwargs) def get_release(data: dict[str, Any]) -> Release: return Release(Client("doesn't matter"), data) @pytest.fixture(autouse=True) def _patch_discogs_setup(monkeypatch): """Autouse fixture to patch DiscogsPlugin.setup for each test.""" monkeypatch.setattr( "beetsplug.discogs.DiscogsPlugin.setup", lambda *_: None ) class DiscogsTestMixin: @pytest.fixture def plugin_config(self): return {} @pytest.fixture def plugin(self, plugin_config): plugin = DiscogsPlugin() plugin.config.set(plugin_config) return plugin def _make_release(self, tracks=None): """Return discogs_client.Release. The returned object is incomplete, including just the fields required for tests in this module. """ data = { "id": 11111111, "uri": "https://www.discogs.com/release/111111111", "title": "ALBUM TITLE", "year": 3001, "artists": [_artist("ARTIST NAME", join=",")], "formats": [ { "descriptions": ["FORMAT DESC 1", "FORMAT DESC 2"], "name": "FORMAT", "qty": 1, } ], # genres and styles are reversed in Discogs "genres": ["STYLE1", "STYLE2"], "styles": ["GENRE1", "GENRE2"], "labels": [{"name": "LABEL NAME", "catno": "CATALOG NUMBER"}], "tracklist": tracks or [], } return get_release(data) def _make_release_from_positions(self, positions): """Return discogs_client.Release with tracks at the given positions.""" tracks = [ audio_track(f"TITLE{i}", position) for (i, position) in enumerate(positions, start=1) ] return self._make_release(tracks) class TestDGAlbumInfo(DiscogsTestMixin, TestHelper): def test_parse_media_for_tracks(self): tracks = [ audio_track("TITLE ONE", "1", "01:01"), audio_track("TITLE TWO", "2", "02:02"), ] release = self._make_release(tracks=tracks) d = DiscogsPlugin().get_album_info(release) t = d.tracks assert d.media == "FORMAT" assert t[0].media == d.media assert t[1].media == d.media def test_parse_medium_numbers_single_medium(self): release = self._make_release_from_positions(["1", "2"]) d = DiscogsPlugin().get_album_info(release) t = d.tracks assert d.mediums == 1 assert t[0].medium == 1 assert t[0].medium_total == 2 assert t[1].medium == 1 assert t[0].medium_total == 2 def test_parse_medium_numbers_two_mediums(self): release = self._make_release_from_positions(["1-1", "2-1"]) d = DiscogsPlugin().get_album_info(release) t = d.tracks assert d.mediums == 2 assert t[0].medium == 1 assert t[0].medium_total == 1 assert t[1].medium == 2 assert t[1].medium_total == 1 def test_parse_medium_numbers_two_mediums_two_sided(self): release = self._make_release_from_positions(["A1", "B1", "C1"]) d = DiscogsPlugin().get_album_info(release) t = d.tracks assert d.mediums == 2 assert t[0].medium == 1 assert t[0].medium_total == 2 assert t[0].medium_index == 1 assert t[1].medium == 1 assert t[1].medium_total == 2 assert t[1].medium_index == 2 assert t[2].medium == 2 assert t[2].medium_total == 1 assert t[2].medium_index == 1 def test_parse_track_indices(self): release = self._make_release_from_positions(["1", "2"]) d = DiscogsPlugin().get_album_info(release) t = d.tracks assert t[0].medium_index == 1 assert t[0].index == 1 assert t[0].medium_total == 2 assert t[1].medium_index == 2 assert t[1].index == 2 assert t[1].medium_total == 2 def test_parse_track_indices_several_media(self): release = self._make_release_from_positions( ["1-1", "1-2", "2-1", "3-1"] ) d = DiscogsPlugin().get_album_info(release) t = d.tracks assert d.mediums == 3 assert t[0].medium_index == 1 assert t[0].index == 1 assert t[0].medium_total == 2 assert t[1].medium_index == 2 assert t[1].index == 2 assert t[1].medium_total == 2 assert t[2].medium_index == 1 assert t[2].index == 3 assert t[2].medium_total == 1 assert t[3].medium_index == 1 assert t[3].index == 4 assert t[3].medium_total == 1 def test_parse_minimal_release(self): """Test parsing of a release with the minimal amount of information.""" data = { "id": 123, "uri": "https://www.discogs.com/release/123456-something", "tracklist": [audio_track("A", "1", "01:01")], "artists": [_artist("ARTIST NAME", id=321)], "title": "TITLE", } release = get_release(data) d = DiscogsPlugin().get_album_info(release) assert d.artist == "ARTIST NAME" assert d.album == "TITLE" assert len(d.tracks) == 1 def test_default_genre_style_settings(self): """Test genre default settings, genres to genre, styles to style""" release = self._make_release_from_positions(["1", "2"]) d = DiscogsPlugin().get_album_info(release) assert d.style == "STYLE1, STYLE2" assert d.genres == ["GENRE1", "GENRE2"] def test_append_style_to_genre(self): """Test appending style to genre if config enabled""" config["discogs"]["append_style_genre"] = True release = self._make_release_from_positions(["1", "2"]) d = DiscogsPlugin().get_album_info(release) assert d.style == "STYLE1, STYLE2" assert d.genres == ["GENRE1", "GENRE2", "STYLE1", "STYLE2"] def test_append_style_to_genre_no_styles(self): """Test nothing appended to genre if style is empty""" config["discogs"]["append_style_genre"] = True release = self._make_release_from_positions(["1", "2"]) release.data["genres"] = [] d = DiscogsPlugin().get_album_info(release) assert d.style is None assert d.genres == ["GENRE1", "GENRE2"] @pytest.mark.parametrize( "released, expected", [ _p("2000-08-13", (2000, 8, 13), id="full-date"), _p("2000-08", (2000, 8, None), id="year-and-month"), _p("2000", (2000, None, None), id="year-only"), _p("2000-00-00", (2000, None, None), id="zeroed-month-and-day"), _p("2000-08-00", (2000, 8, None), id="zeroed-day"), _p("2000-8-1", (2000, 8, 1), id="unpadded"), _p(" 2000-08-13 ", (2000, 8, 13), id="surrounding-whitespace"), # Fall back to the release's own `year` field. _p("", (3001, None, None), id="empty"), _p(None, (3001, None, None), id="missing"), _p("0000-00-00", (3001, None, None), id="zeroed-date"), _p("13 Aug 2000", (3001, None, None), id="unparseable"), ], ) def test_parse_release_date(self, released, expected): release = self._make_release_from_positions(["1"]) release.data["released"] = released d = DiscogsPlugin().get_album_info(release) assert (d.year, d.month, d.day) == expected def test_original_date_without_master(self): """A release without a master release is its own original.""" release = self._make_release_from_positions(["1"]) release.data["released"] = "2000-08-13" d = DiscogsPlugin().get_album_info(release) assert (d.original_year, d.original_month, d.original_day) == ( 2000, 8, 13, ) def test_original_date_with_master(self, monkeypatch): """Only the master release's year is known, so it alone is used.""" monkeypatch.setattr(DiscogsPlugin, "get_master_year", lambda *_: 1990) release = self._make_release_from_positions(["1"]) release.data["released"] = "2000-08-13" release.data["master_id"] = 22222222 d = DiscogsPlugin().get_album_info(release) assert (d.year, d.month, d.day) == (2000, 8, 13) assert (d.original_year, d.original_month, d.original_day) == ( 1990, None, None, ) class TestStripDisambiguation(DiscogsTestMixin): @pytest.fixture def album_info(self, plugin): data = { "id": 123, "uri": "https://www.discogs.com/release/123456-something", "tracklist": [ { "title": "track", "position": "A", "type_": "track", "duration": "5:44", "artists": [_artist("TEST ARTIST (5)", id=11146)], } ], "artists": [ _artist("ARTIST NAME (2)", id=321, join="&"), _artist("OTHER ARTIST (5)", id=322), ], "title": "title", "labels": [{"name": "LABEL NAME (5)", "catno": "catalog number"}], } return plugin.get_album_info(get_release(data)) @pytest.mark.parametrize("plugin_config", [{"strip_disambiguation": True}]) def test_strip_disambiguation(self, album_info): """Test removing disambiguation from all disambiguated fields.""" assert album_info.artist == "ARTIST NAME & OTHER ARTIST" assert album_info.artists == ["ARTIST NAME", "OTHER ARTIST"] assert album_info.artists_ids == ["321", "322"] assert album_info.tracks[0].artist == "TEST ARTIST" assert album_info.tracks[0].artists == ["TEST ARTIST"] assert album_info.tracks[0].artist_id == "11146" assert album_info.tracks[0].artists_ids == ["11146"] assert album_info.label == "LABEL NAME" @pytest.mark.parametrize("plugin_config", [{"strip_disambiguation": False}]) def test_dont_strip_disambiguation(self, album_info): """Test disabling disambiguation removal from all disambiguated fields.""" assert album_info.artist == "ARTIST NAME (2) & OTHER ARTIST (5)" assert album_info.artists == ["ARTIST NAME (2)", "OTHER ARTIST (5)"] assert album_info.tracks[0].artist == "TEST ARTIST (5)" assert album_info.tracks[0].artists == ["TEST ARTIST (5)"] assert album_info.label == "LABEL NAME (5)" class TestTracklist(DiscogsTestMixin): @pytest.mark.parametrize( "positions,expected_mediums,expected_tracks", [ _p(["1", "2", "3"], 1, 3, id="without-sides"), _p(["A1", "A2", "B1", "B2"], 1, 4, id="with-sides"), _p(["A1", "A2", "B1", "C1"], 2, 4, id="multiple-lp"), _p(["1-1", "1-2", "2-1", "3-1"], 3, 4, id="multiple-cd"), _p(["I", "II", "III", "IV"], 1, 4, id="non-standard"), _p(["1", "2.1", "2.2", "3"], 1, 3, id="subtracks-dot"), _p(["A1", "A2.1", "A2.2", "A3"], 1, 3, id="subtracks-dot-with-sides"), _p(["A1", "A2a", "A2b", "A3"], 1, 3, id="subtracks-letter"), _p(["A1", "A2.a", "A2.b", "A3"], 1, 3, id="subtracks-letter-with-dot"), _p(["1.1", "1.2", "2.1", "2.2"], 1, 2, id="multiple-subtrack-groups"), _p(["1", "2", "Video 1"], 2, 3, id="subtracks-extra-material"), ], ) # fmt: skip def test_parse_tracklist_positions( self, plugin, positions, expected_mediums, expected_tracks ): release = self._make_release_from_positions(positions) d = plugin.get_album_info(release) assert d.mediums == expected_mediums assert len(d.tracks) == expected_tracks @pytest.mark.parametrize( "plugin_config,tracks,expected_mediums,expected_tracks", [ _p( {"index_tracks": False}, [ heading_track("MEDIUM TITLE"), audio_track("TITLE ONE", "1.1"), audio_track("TITLE TWO", "1.2"), ], 1, [("TITLE ONE / TITLE TWO", "MEDIUM TITLE")], id="flat-logical-subtracks", ), _p( {"index_tracks": False}, [ audio_track("TITLE ONE", "1"), index_track( "TRACK GROUP TITLE", [ audio_track("SUBTITLE ONE", "2.1", "01:01"), audio_track("SUBTITLE TWO", "2.2", "02:02"), ], ), audio_track("TITLE THREE", "3"), ], 1, [ ("TITLE ONE", None), ("TRACK GROUP TITLE", None), ("TITLE THREE", None), ], id="nested-logical-subtracks", ), _p( {"index_tracks": False}, [ audio_track("TITLE ONE", "1"), index_track( "TRACK GROUP TITLE", [ audio_track("SUBTITLE ONE", "2", "01:01"), audio_track("SUBTITLE TWO", "3", "02:02"), ], ), audio_track("TITLE FOUR", "4"), ], 1, [ ("TITLE ONE", None), ("SUBTITLE ONE", None), ("SUBTITLE TWO", None), ("TITLE FOUR", None), ], id="nested-physical-subtracks", ), _p( {"index_tracks": True}, [ audio_track("TITLE ONE", "1"), index_track( "TRACK GROUP TITLE", [ audio_track("SUBTITLE ONE", "2", "01:01"), audio_track("SUBTITLE TWO", "3", "02:02"), ], ), audio_track("TITLE FOUR", "4"), ], 1, [ ("TITLE ONE", None), ("TRACK GROUP TITLE: SUBTITLE ONE", None), ("TRACK GROUP TITLE: SUBTITLE TWO", None), ("TITLE FOUR", None), ], id="nested-physical-subtracks-with-index-tracks", ), _p( {"index_tracks": False}, [ heading_track("MEDIUM TITLE CD1"), audio_track("TITLE ONE", "1-1"), audio_track("TITLE TWO", "1-2"), heading_track("MEDIUM TITLE CD2"), audio_track("TITLE THREE", "2-1"), ], 2, [ ("TITLE ONE", "MEDIUM TITLE CD1"), ("TITLE TWO", "MEDIUM TITLE CD1"), ("TITLE THREE", "MEDIUM TITLE CD2"), ], id="medium-titles", ), ], ) # fmt: skip def test_parse_tracklist_index_tracks( self, plugin, tracks, expected_mediums, expected_tracks ): release = self._make_release(tracks) album = plugin.get_album_info(release) assert album.mediums == expected_mediums assert [(t.title, t.disctitle) for t in album.tracks] == expected_tracks def test_parse_tracklist_inherited_artists(self, plugin): """Verify grouped tracks combine explicit and inherited artist credits. This covers releases where a track group provides the default artist for sub-tracks that do not declare one themselves. Note: this is based on the following release: https://www.discogs.com/release/3647530 """ track_artist = "TRACK ARTIST" group_artist = "GROUP ARTIST" tracks = [ index_track( "TRACK GROUP TITLE", [ audio_track( "TRACK ONE", "2", artists=[_artist(track_artist)] ), audio_track("SUBTITLE TWO", "3"), ], artists=[_artist(group_artist)], ) ] release = self._make_release(tracks) album = plugin.get_album_info(release) assert album.mediums == 1 assert {t.artist for t in album.tracks} == {track_artist, group_artist} def test_coalesce_logical_index_as_audio_track(self, plugin): index = index_track( "TRACK GROUP TITLE", [ audio_track("SUBTITLE ONE", "2.1"), audio_track("SUBTITLE TWO", "2.2"), ], duration="03:03", ) assert plugin._coalesce_tracks([index]) == [ audio_track("TRACK GROUP TITLE", "2", "03:03") ] class TestDGSearchQuery(TestHelper): def test_default_search_filters_without_extra_tags(self): """Discogs search uses only the type filter when no extra_tags are set.""" plugin = DiscogsPlugin() items = [Item()] query, filters = plugin.get_search_query_with_filters( "album", items, "Artist", "Album", False ) assert "Album" in query assert filters == {"type": "release"} def test_extra_tags_populate_discogs_filters(self): """Configured extra_tags should populate Discogs search filters.""" plugin = DiscogsPlugin() plugin.config["extra_tags"] = ["label", "catalognum"] items = [ Item(catalognum="ABC 123", label="abc"), Item(catalognum="ABC 123", label="abc"), Item(catalognum="ABC 123", label="def"), ] _query, filters = plugin.get_search_query_with_filters( "album", items, "Artist", "Album", False ) assert filters["type"] == "release" assert filters["label"] == "abc" # Catalog number should have whitespace removed. assert filters["catno"] == "ABC123" config["discogs"]["extra_tags"] = [] class TestDGSearchResponse(DiscogsTestMixin): @staticmethod def _decode_error(): return json.JSONDecodeError("Expecting value", "", 0) @pytest.fixture def params(self): return SearchParams("album", "Album", {"type": "release"}, 5) @pytest.fixture def client(self, plugin): plugin.discogs_client = MagicMock() return plugin.discogs_client def test_retries_invalid_json_response(self, plugin, client, params): result = MagicMock(data={"id": 123}) results = client.search.return_value results.page.side_effect = [self._decode_error(), [result]] assert plugin.get_search_response(params) == [{"id": 123}] assert client.search.call_count == 2 assert results.page.call_count == 2 assert results.per_page == params.limit def test_raises_after_invalid_json_retry(self, plugin, client, params): results = client.search.return_value results.page.side_effect = [self._decode_error(), self._decode_error()] with pytest.raises(json.JSONDecodeError): plugin.get_search_response(params) assert client.search.call_count == 2 assert results.page.call_count == 2 class TestAnv: @pytest.fixture def album_info(self, monkeypatch, anv_config): monkeypatch.setattr( "beetsplug.discogs.DiscogsPlugin.setup", lambda _: None ) data = { "id": 123, "uri": "https://www.discogs.com/release/123456-something", "tracklist": [ { "title": "track", "position": "A", "type_": "track", "duration": "5:44", "artists": [ _artist("ARTIST", id=11146, anv="ART", join="Feat."), _artist("PERFORMER", id=787), ], "extraartists": [ _artist("PERFORMER", id=787, role="Featuring") ], } ], "artists": [ _artist("DRUMMER", id=445, anv="DRUM", join=", "), _artist("ARTIST (4)", id=321, anv="ARTY", join="&"), _artist("SOLOIST", id=446, anv="SOLO"), ], "title": "title", } release = get_release(data) plugin = DiscogsPlugin() plugin.config["anv"].set( {"artist": False, "album_artist": False, "artist_credit": False} | anv_config ) return plugin.get_album_info(release) @staticmethod def _assert_fields(obj, expected): for field, value in expected.items(): assert getattr(obj, field) == value @pytest.mark.parametrize( "anv_config,expected_track_fields", [ ( {"artist": False}, { "artist": "ARTIST Feat. PERFORMER", "artists": ["ARTIST", "PERFORMER"], }, ), ( {"artist": True}, { "artist": "ART Feat. PERFORMER", "artists": ["ART", "PERFORMER"], }, ), ], ) def test_track_artist_fields(self, album_info, expected_track_fields): self._assert_fields(album_info.tracks[0], expected_track_fields) @pytest.mark.parametrize( "anv_config,expected_album_fields,expected_track_fields", [ ( {"artist_credit": False}, { "artist_credit": "DRUMMER, ARTIST & SOLOIST", "artists_credit": ["DRUMMER", "ARTIST", "SOLOIST"], }, { "artist_credit": "ARTIST Feat. PERFORMER", "artists_credit": ["ARTIST", "PERFORMER"], }, ), ( {"artist_credit": True}, { "artist_credit": "DRUM, ARTY & SOLO", "artists_credit": ["DRUM", "ARTY", "SOLO"], }, { "artist_credit": "ART Feat. PERFORMER", "artists_credit": ["ART", "PERFORMER"], }, ), ], ) def test_artist_credit_fields( self, album_info, expected_album_fields, expected_track_fields ): self._assert_fields(album_info, expected_album_fields) self._assert_fields(album_info.tracks[0], expected_track_fields) @pytest.mark.parametrize( "anv_config,expected_album_fields", [ ( {"album_artist": False}, { "artist": "DRUMMER, ARTIST & SOLOIST", "artists": ["DRUMMER", "ARTIST", "SOLOIST"], }, ), ( {"album_artist": True}, { "artist": "DRUM, ARTY & SOLO", "artists": ["DRUM", "ARTY", "SOLO"], }, ), ], ) def test_album_artist_fields(self, album_info, expected_album_fields): self._assert_fields(album_info, expected_album_fields) def test_anv_album_artist(): """Test using artist name variations when the album artist is the same as the track artist, but only the track artist should use the artist name variation.""" data = { "id": 123, "uri": "https://www.discogs.com/release/123456-something", "tracklist": [ { "title": "track", "position": "A", "type_": "track", "duration": "5:44", } ], "artists": [_artist("ARTIST (4)", id=321, anv="VARIATION")], "title": "title", } release = get_release(data) config["discogs"]["anv"]["album_artist"] = False config["discogs"]["anv"]["artist"] = True config["discogs"]["anv"]["artist_credit"] = False r = DiscogsPlugin().get_album_info(release) assert r.artist == "ARTIST" assert r.artists == ["ARTIST"] assert r.artist_credit == "ARTIST" assert r.artist_id == "321" assert r.artists_credit == ["ARTIST"] assert r.tracks[0].artist == "VARIATION" assert r.tracks[0].artists == ["VARIATION"] assert r.tracks[0].artist_credit == "ARTIST" assert r.tracks[0].artists_credit == ["ARTIST"] def test_parse_featured_artists(): """Tests the plugins ability to parse a featured artist. Ignores artists that are not listed as featured.""" track = { "type_": "track", "title": "track", "position": "1", "duration": "5:00", "artists": [ _artist("NEW ARTIST", id=11146, join="&"), _artist("VOCALIST", id=344, join="feat."), ], "extraartists": [ _artist("SOLOIST", id=3, role="Featuring"), _artist("PERFORMER (1)", id=5, role="Other Role, Featuring"), _artist("RANDOM", id=8, role="Written-By"), _artist("MUSICIAN", id=10, role="Featuring [Uncredited]"), ], } plugin = DiscogsPlugin() artistinfo = ArtistState.from_config(plugin.config, [_artist("ARTIST")]) t, _, _ = plugin.get_track_info(track, 1, 1, artistinfo) assert ( t.artist == "NEW ARTIST & VOCALIST feat. SOLOIST, PERFORMER, MUSICIAN" ) assert t.artists == [ "NEW ARTIST", "VOCALIST", "SOLOIST", "PERFORMER", "MUSICIAN", ] assert t.artists_ids == ["11146", "344", "3", "5", "10"] assert t.composers == ["RANDOM"] def test_parse_extraartist_roles(): plugin = DiscogsPlugin() artistinfo = ArtistState.from_config(plugin.config, [_artist("ARTIST")]) track = { "type_": "track", "title": "track", "position": "1", "duration": "5:00", "artists": [_artist("TRACK ARTIST", id=11)], "extraartists": [ _artist("LYRICIST", id=2, role="Lyrics By"), _artist("ARRANGER", id=3, role="Arranged By"), _artist("REMIXER", id=5, role="Remixed By"), _artist("COMPOSER", id=6, role="Written-By"), ], } t, _, _ = plugin.get_track_info(track, 1, 1, artistinfo) assert t.artist == "TRACK ARTIST" assert t.artists == ["TRACK ARTIST"] assert t.lyricists == ["LYRICIST"] assert t.arrangers == ["ARRANGER"] assert t.remixers == ["REMIXER"] assert t.composers == ["COMPOSER"] @pytest.mark.parametrize( "formats, expected_media, expected_albumtype", [ (None, None, None), ( [ { "descriptions": ['7"', "Single", "45 RPM"], "name": "Vinyl", "qty": 1, } ], "Vinyl", '7", Single, 45 RPM', ), ], ) def test_get_media_and_albumtype(formats, expected_media, expected_albumtype): result = DiscogsPlugin.get_media_and_albumtype(formats) assert result == (expected_media, expected_albumtype) def test_va_buildartistinfo(): config["va_name"] = "VARIOUS ARTISTS" expected_info = { "artist": "VARIOUS ARTISTS", "artist_id": "1", "artists": ["VARIOUS ARTISTS"], "artists_ids": ["1"], "artist_credit": "VARIOUS ARTISTS", "artists_credit": ["VARIOUS ARTISTS"], "arrangers": None, "composers": None, "remixers": None, "lyricists": None, } assert ( ArtistState.from_config( DiscogsPlugin().config, [_artist("Various")] ).info == expected_info ) @pytest.mark.parametrize( "position, medium, index, subindex", [ ("1", None, "1", None), ("A12", "A", "12", None), ("12-34", "12-", "34", None), ("CD1-1", "CD1-", "1", None), ("1.12", None, "1", "12"), ("12.a", None, "12", "A"), ("12.34", None, "12", "34"), ("1ab", None, "1", "AB"), # Non-standard ("IV", "IV", None, None), ], ) def test_get_track_index(position, medium, index, subindex): assert DiscogsPlugin.get_track_index(position) == (medium, index, subindex) beetbox-beets-00724b7/test/plugins/test_bareasc.py0000664000175000017500000000000015253035401021512 0ustar pieterpieterbeetbox-beets-00724b7/test/plugins/test_beatport.py0000664000175000017500000005230115253035401021745 0ustar pieterpieter"""Tests for the 'beatport' plugin.""" import unittest from datetime import timedelta from beets.test import _common from beets.test.helper import BeetsTestCase from beetsplug import beatport class BeatportTest(BeetsTestCase): def _make_release_response(self): """Returns a dict that mimics a response from the beatport API. The results were retrieved from: https://oauth-api.beatport.com/catalog/3/releases?id=1742984 The list of elements on the returned dict is incomplete, including just those required for the tests on this class. """ return { "id": 1742984, "type": "release", "name": "Charade", "slug": "charade", "releaseDate": "2016-04-11", "publishDate": "2016-04-11", "audioFormat": "", "category": "Release", "currentStatus": "General Content", "catalogNumber": "GR089", "description": "", "label": { "id": 24539, "name": "Gravitas Recordings", "type": "label", "slug": "gravitas-recordings", }, "artists": [ { "id": 326158, "name": "Supersillyus", "slug": "supersillyus", "type": "artist", } ], "genres": [ {"id": 9, "name": "Breaks", "slug": "breaks", "type": "genre"} ], } def _make_tracks_response(self): """Return a list that mimics a response from the beatport API. The results were retrieved from: https://oauth-api.beatport.com/catalog/3/tracks?releaseId=1742984 The list of elements on the returned list is incomplete, including just those required for the tests on this class. """ return [ { "id": 7817567, "type": "track", "sku": "track-7817567", "name": "Mirage a Trois", "trackNumber": 1, "mixName": "Original Mix", "title": "Mirage a Trois (Original Mix)", "slug": "mirage-a-trois-original-mix", "releaseDate": "2016-04-11", "publishDate": "2016-04-11", "currentStatus": "General Content", "length": "7:05", "lengthMs": 425421, "bpm": 90, "key": { "standard": { "letter": "G", "sharp": False, "flat": False, "chord": "minor", }, "shortName": "Gmin", }, "artists": [ { "id": 326158, "name": "Supersillyus", "slug": "supersillyus", "type": "artist", } ], "genres": [ { "id": 9, "name": "Breaks", "slug": "breaks", "type": "genre", } ], "subGenres": [ { "id": 209, "name": "Glitch Hop", "slug": "glitch-hop", "type": "subgenre", } ], "release": { "id": 1742984, "name": "Charade", "type": "release", "slug": "charade", }, "label": { "id": 24539, "name": "Gravitas Recordings", "type": "label", "slug": "gravitas-recordings", "status": True, }, }, { "id": 7817568, "type": "track", "sku": "track-7817568", "name": "Aeon Bahamut", "trackNumber": 2, "mixName": "Original Mix", "title": "Aeon Bahamut (Original Mix)", "slug": "aeon-bahamut-original-mix", "releaseDate": "2016-04-11", "publishDate": "2016-04-11", "currentStatus": "General Content", "length": "7:38", "lengthMs": 458000, "bpm": 100, "key": { "standard": { "letter": "G", "sharp": False, "flat": False, "chord": "major", }, "shortName": "Gmaj", }, "artists": [ { "id": 326158, "name": "Supersillyus", "slug": "supersillyus", "type": "artist", } ], "genres": [ { "id": 9, "name": "Breaks", "slug": "breaks", "type": "genre", } ], "subGenres": [ { "id": 209, "name": "Glitch Hop", "slug": "glitch-hop", "type": "subgenre", } ], "release": { "id": 1742984, "name": "Charade", "type": "release", "slug": "charade", }, "label": { "id": 24539, "name": "Gravitas Recordings", "type": "label", "slug": "gravitas-recordings", "status": True, }, }, { "id": 7817569, "type": "track", "sku": "track-7817569", "name": "Trancendental Medication", "trackNumber": 3, "mixName": "Original Mix", "title": "Trancendental Medication (Original Mix)", "slug": "trancendental-medication-original-mix", "releaseDate": "2016-04-11", "publishDate": "2016-04-11", "currentStatus": "General Content", "length": "1:08", "lengthMs": 68571, "bpm": 141, "key": { "standard": { "letter": "F", "sharp": False, "flat": False, "chord": "major", }, "shortName": "Fmaj", }, "artists": [ { "id": 326158, "name": "Supersillyus", "slug": "supersillyus", "type": "artist", } ], "genres": [ { "id": 9, "name": "Breaks", "slug": "breaks", "type": "genre", } ], "subGenres": [ { "id": 209, "name": "Glitch Hop", "slug": "glitch-hop", "type": "subgenre", } ], "release": { "id": 1742984, "name": "Charade", "type": "release", "slug": "charade", }, "label": { "id": 24539, "name": "Gravitas Recordings", "type": "label", "slug": "gravitas-recordings", "status": True, }, }, { "id": 7817570, "type": "track", "sku": "track-7817570", "name": "A List of Instructions for When I'm Human", "trackNumber": 4, "mixName": "Original Mix", "title": "A List of Instructions for When I'm Human (Original Mix)", "slug": "a-list-of-instructions-for-when-im-human-original-mix", "releaseDate": "2016-04-11", "publishDate": "2016-04-11", "currentStatus": "General Content", "length": "6:57", "lengthMs": 417913, "bpm": 88, "key": { "standard": { "letter": "A", "sharp": False, "flat": False, "chord": "minor", }, "shortName": "Amin", }, "artists": [ { "id": 326158, "name": "Supersillyus", "slug": "supersillyus", "type": "artist", } ], "genres": [ { "id": 9, "name": "Breaks", "slug": "breaks", "type": "genre", } ], "subGenres": [ { "id": 209, "name": "Glitch Hop", "slug": "glitch-hop", "type": "subgenre", } ], "release": { "id": 1742984, "name": "Charade", "type": "release", "slug": "charade", }, "label": { "id": 24539, "name": "Gravitas Recordings", "type": "label", "slug": "gravitas-recordings", "status": True, }, }, { "id": 7817571, "type": "track", "sku": "track-7817571", "name": "The Great Shenanigan", "trackNumber": 5, "mixName": "Original Mix", "title": "The Great Shenanigan (Original Mix)", "slug": "the-great-shenanigan-original-mix", "releaseDate": "2016-04-11", "publishDate": "2016-04-11", "currentStatus": "General Content", "length": "9:49", "lengthMs": 589875, "bpm": 123, "key": { "standard": { "letter": "E", "sharp": False, "flat": True, "chord": "major", }, "shortName": "E♭maj", }, "artists": [ { "id": 326158, "name": "Supersillyus", "slug": "supersillyus", "type": "artist", } ], "genres": [ { "id": 9, "name": "Breaks", "slug": "breaks", "type": "genre", } ], "subGenres": [ { "id": 209, "name": "Glitch Hop", "slug": "glitch-hop", "type": "subgenre", } ], "release": { "id": 1742984, "name": "Charade", "type": "release", "slug": "charade", }, "label": { "id": 24539, "name": "Gravitas Recordings", "type": "label", "slug": "gravitas-recordings", "status": True, }, }, { "id": 7817572, "type": "track", "sku": "track-7817572", "name": "Charade", "trackNumber": 6, "mixName": "Original Mix", "title": "Charade (Original Mix)", "slug": "charade-original-mix", "releaseDate": "2016-04-11", "publishDate": "2016-04-11", "currentStatus": "General Content", "length": "7:05", "lengthMs": 425423, "bpm": 123, "key": { "standard": { "letter": "A", "sharp": False, "flat": False, "chord": "major", }, "shortName": "Amaj", }, "artists": [ { "id": 326158, "name": "Supersillyus", "slug": "supersillyus", "type": "artist", } ], "genres": [ { "id": 9, "name": "Breaks", "slug": "breaks", "type": "genre", } ], "subGenres": [ { "id": 209, "name": "Glitch Hop", "slug": "glitch-hop", "type": "subgenre", } ], "release": { "id": 1742984, "name": "Charade", "type": "release", "slug": "charade", }, "label": { "id": 24539, "name": "Gravitas Recordings", "type": "label", "slug": "gravitas-recordings", "status": True, }, }, ] def setUp(self): super().setUp() # Set up 'album'. response_release = self._make_release_response() self.album = beatport.BeatportRelease(response_release) # Set up 'tracks'. response_tracks = self._make_tracks_response() self.tracks = [beatport.BeatportTrack(t) for t in response_tracks] # Set up 'test_album'. self.test_album = self.mk_test_album() # Set up 'test_tracks' self.test_tracks = self.test_album.items() def mk_test_album(self): items = [_common.item() for _ in range(6)] for item in items: item.album = "Charade" item.catalognum = "GR089" item.label = "Gravitas Recordings" item.artist = "Supersillyus" item.year = 2016 item.comp = False item.label_name = "Gravitas Recordings" item.genres = ["Glitch Hop", "Breaks"] item.year = 2016 item.month = 4 item.day = 11 item.mix_name = "Original Mix" items[0].title = "Mirage a Trois" items[1].title = "Aeon Bahamut" items[2].title = "Trancendental Medication" items[3].title = "A List of Instructions for When I'm Human" items[4].title = "The Great Shenanigan" items[5].title = "Charade" items[0].length = timedelta(minutes=7, seconds=5).total_seconds() items[1].length = timedelta(minutes=7, seconds=38).total_seconds() items[2].length = timedelta(minutes=1, seconds=8).total_seconds() items[3].length = timedelta(minutes=6, seconds=57).total_seconds() items[4].length = timedelta(minutes=9, seconds=49).total_seconds() items[5].length = timedelta(minutes=7, seconds=5).total_seconds() items[0].url = "mirage-a-trois-original-mix" items[1].url = "aeon-bahamut-original-mix" items[2].url = "trancendental-medication-original-mix" items[3].url = "a-list-of-instructions-for-when-im-human-original-mix" items[4].url = "the-great-shenanigan-original-mix" items[5].url = "charade-original-mix" counter = 0 for item in items: counter += 1 item.track_number = counter items[0].bpm = 90 items[1].bpm = 100 items[2].bpm = 141 items[3].bpm = 88 items[4].bpm = 123 items[5].bpm = 123 items[0].initial_key = "Gmin" items[1].initial_key = "Gmaj" items[2].initial_key = "Fmaj" items[3].initial_key = "Amin" items[4].initial_key = "E♭maj" items[5].initial_key = "Amaj" for item in items: self.lib.add(item) album = self.lib.add_album(items) album.store() return album # Test BeatportRelease. def test_album_name_applied(self): assert self.album.name == self.test_album["album"] def test_catalog_number_applied(self): assert self.album.catalog_number == self.test_album["catalognum"] def test_label_applied(self): assert self.album.label_name == self.test_album["label"] def test_category_applied(self): assert self.album.category == "Release" def test_album_url_applied(self): assert self.album.url == "https://beatport.com/release/charade/1742984" # Test BeatportTrack. def test_title_applied(self): for track, test_track in zip(self.tracks, self.test_tracks): assert track.name == test_track.title def test_mix_name_applied(self): for track, test_track in zip(self.tracks, self.test_tracks): assert track.mix_name == test_track.mix_name def test_length_applied(self): for track, test_track in zip(self.tracks, self.test_tracks): assert int(track.length.total_seconds()) == int(test_track.length) def test_track_url_applied(self): # Specify beatport ids here because an 'item.id' is beets-internal. ids = [7817567, 7817568, 7817569, 7817570, 7817571, 7817572] # Concatenate with 'id' to pass strict equality test. for track, test_track, id_ in zip(self.tracks, self.test_tracks, ids): assert ( track.url == f"https://beatport.com/track/{test_track.url}/{id_}" ) def test_bpm_applied(self): for track, test_track in zip(self.tracks, self.test_tracks): assert track.bpm == test_track.bpm def test_initial_key_applied(self): for track, test_track in zip(self.tracks, self.test_tracks): assert track.initial_key == test_track.initial_key def test_genre_applied(self): for track, test_track in zip(self.tracks, self.test_tracks): assert track.genres == test_track.genres class BeatportResponseEmptyTest(unittest.TestCase): def _make_tracks_response(self): return [ { "id": 7817567, "name": "Mirage a Trois", "genres": [ { "id": 9, "name": "Breaks", "slug": "breaks", "type": "genre", } ], "subGenres": [ { "id": 209, "name": "Glitch Hop", "slug": "glitch-hop", "type": "subgenre", } ], } ] def setUp(self): super().setUp() # Set up 'tracks'. self.response_tracks = self._make_tracks_response() self.tracks = [beatport.BeatportTrack(t) for t in self.response_tracks] # Make alias to be congruent with class `BeatportTest`. self.test_tracks = self.response_tracks def test_response_tracks_empty(self): response_tracks = [] tracks = [beatport.BeatportTrack(t) for t in response_tracks] assert tracks == [] def test_sub_genre_empty_fallback(self): """No 'sub_genre' is provided. Test if fallback to 'genre' works.""" self.response_tracks[0]["subGenres"] = [] tracks = [beatport.BeatportTrack(t) for t in self.response_tracks] self.test_tracks[0]["subGenres"] = [] assert tracks[0].genres == [self.test_tracks[0]["genres"][0]["name"]] def test_genre_empty(self): """No 'genre' is provided. Test if 'sub_genre' is applied.""" self.response_tracks[0]["genres"] = [] tracks = [beatport.BeatportTrack(t) for t in self.response_tracks] self.test_tracks[0]["genres"] = [] assert tracks[0].genres == [self.test_tracks[0]["subGenres"][0]["name"]] beetbox-beets-00724b7/test/plugins/test_permissions.py0000664000175000017500000000375015253035401022504 0ustar pieterpieter"""Tests for the 'permissions' plugin.""" import os import platform from unittest.mock import Mock, patch import pytest from beets.test.helper import AsIsImporterMixin, ImportHelper, PluginMixin from beetsplug.permissions import ( check_permissions, convert_perm, dirs_in_library, ) class TestPermissionsPlugin(AsIsImporterMixin, PluginMixin, ImportHelper): plugin = "permissions" def setup_beets(self): super().setup_beets() self.config["permissions"] = {"file": "777", "dir": "777"} def test_permissions_on_album_imported(self): self.import_and_check_permissions() def test_permissions_on_item_imported(self): self.config["import"]["singletons"] = True self.import_and_check_permissions() def import_and_check_permissions(self): if platform.system() == "Windows": pytest.skip("permissions not available on Windows") track_file = self.import_path / "album" / "track_1.mp3" assert track_file.stat().st_mode & 0o777 != 511 self.run_asis_importer() item = self.lib.items().get() paths = (item.path, *dirs_in_library(self.lib.directory, item.path)) for path in paths: assert os.stat(path).st_mode & 0o777 == 511 def test_convert_perm_from_string(self): assert convert_perm("10") == 8 def test_convert_perm_from_int(self): assert convert_perm(10) == 8 def test_permissions_on_set_art(self): self.do_set_art(True) @patch("os.chmod", Mock()) def test_failing_permissions_on_set_art(self): self.do_set_art(False) def do_set_art(self, expect_success): if platform.system() == "Windows": pytest.skip("permissions not available on Windows") self.run_asis_importer() album = self.lib.albums().get() artpath = self.temp_path / "cover.jpg" artpath.touch() album.set_art(artpath) assert expect_success == check_permissions(album.artpath, 0o777) beetbox-beets-00724b7/test/plugins/test_fuzzy.py0000664000175000017500000000154215253035401021315 0ustar pieterpieter"""Tests for the fuzzy query plugin.""" import pytest from beets.test.helper import PluginTestHelper class TestFuzzyPlugin(PluginTestHelper): plugin = "fuzzy" @pytest.mark.parametrize( "query,expected_titles", [ pytest.param("~foo", ["seafood"], id="all-fields-substring"), pytest.param("title:~foo", ["seafood"], id="field-substring"), pytest.param("~seafood", ["seafood"], id="all-fields-equal-length"), pytest.param("~zzz", [], id="all-fields-no-match"), ], ) def test_fuzzy_queries(self, query, expected_titles): self.add_item(title="seafood", artist="alpha") self.add_item(title="bread", artist="beta") with self.configure_plugin({}): items = self.lib.items(query) assert [item.title for item in items] == expected_titles beetbox-beets-00724b7/test/plugins/test_play.py0000664000175000017500000001537615253035401021105 0ustar pieterpieter"""Tests for the play plugin""" import os import sys import unittest from unittest.mock import ANY, patch import pytest from beets.test.helper import ( AutotagImportTestCase, BeetsTestCase, CleanupModulesMixin, IOMixin, PluginMixin, TerminalImportMixin, ) from beets.ui import UserError from beets.util import open_anything from beetsplug.play import PlayPlugin class PlayPluginMixin(CleanupModulesMixin, PluginMixin): modules = (PlayPlugin.__module__,) plugin = "play" def setUp(self): super().setUp() self.config["play"]["command"] = "echo" @patch("beetsplug.play.util.interactive_open") class PlayPluginTest(IOMixin, PlayPluginMixin, BeetsTestCase): def setUp(self): super().setUp() self.item = self.add_item(album="a nice älbum", title="aNiceTitle") self.lib.add_album([self.item]) def run_and_assert( self, open_mock, args=("title:aNiceTitle",), expected_cmd="echo", expected_playlist=None, ): self.run_command("play", *args) open_mock.assert_called_once_with(ANY, expected_cmd) expected_playlist = expected_playlist or self.item.path.decode("utf-8") exp_playlist = f"{expected_playlist}\n" with open(open_mock.call_args[0][0][0], "rb") as playlist: assert exp_playlist == playlist.read().decode("utf-8") def test_basic(self, open_mock): self.run_and_assert(open_mock) def test_album_option(self, open_mock): self.run_and_assert(open_mock, ["-a", "nice"]) def test_args_option(self, open_mock): self.run_and_assert( open_mock, ["-A", "foo", "title:aNiceTitle"], "echo foo" ) def test_args_option_in_middle(self, open_mock): self.config["play"]["command"] = "echo $args other" self.run_and_assert( open_mock, ["-A", "foo", "title:aNiceTitle"], "echo foo other" ) def test_unset_args_option_in_middle(self, open_mock): self.config["play"]["command"] = "echo $args other" self.run_and_assert(open_mock, ["title:aNiceTitle"], "echo other") # FIXME: fails on windows @unittest.skipIf(sys.platform == "win32", "win32") def test_relative_to(self, open_mock): self.config["play"]["command"] = "echo" self.config["play"]["relative_to"] = "/something" path = os.path.relpath(self.item.path, b"/something") playlist = path.decode("utf-8") self.run_and_assert( open_mock, expected_cmd="echo", expected_playlist=playlist ) def test_use_folders(self, open_mock): self.config["play"]["command"] = None self.config["play"]["use_folders"] = True self.run_command("play", "-a", "nice") open_mock.assert_called_once_with(ANY, open_anything()) with open(open_mock.call_args[0][0][0], "rb") as f: playlist = f.read().decode("utf-8") assert f"{self.item.filepath.parent}\n" == playlist def test_raw(self, open_mock): self.config["play"]["raw"] = True self.run_command("play", "nice") open_mock.assert_called_once_with([self.item.path], "echo") def test_pls_marker(self, open_mock): self.config["play"]["command"] = ( "echo --some params --playlist=$playlist --some-more params" ) self.run_command("play", "nice") open_mock.assert_called_once commandstr = open_mock.call_args_list[0][0][1] assert commandstr.startswith("echo --some params --playlist=") assert commandstr.endswith(" --some-more params") def test_not_found(self, open_mock): self.run_command("play", "not found") open_mock.assert_not_called() def test_warning_threshold(self, open_mock): self.config["play"]["warning_threshold"] = 1 self.add_item(title="another NiceTitle") self.io.addinput("a") self.run_command("play", "nice") open_mock.assert_not_called() def test_skip_warning_threshold_bypass(self, open_mock): self.config["play"]["warning_threshold"] = 1 self.other_item = self.add_item(title="another NiceTitle") expected_playlist = f"{self.item.filepath}\n{self.other_item.filepath}" self.io.addinput("a") self.run_and_assert( open_mock, ["-y", "NiceTitle"], expected_playlist=expected_playlist ) def _playlist_lines(self, open_mock): """Read the playlist file passed to interactive_open and return its lines.""" # interactive_open is called as: interactive_open([playlist_path], command) playlist_path = open_mock.call_args[0][0][0] with open(playlist_path, "rb") as playlist: return playlist.read().decode("utf-8").splitlines() def _add_many_ordered_items(self, *, count, album): items = [] for track in range(1, count + 1): items.append( self.add_item( album=album, artist="randomize artist", title=f"randomize {track:03d}", track=track, ) ) return items def test_randomize(self, open_mock): album = "randomize_test" items = self._add_many_ordered_items(count=100, album=album) baseline = [str(item.filepath) for item in items] self.run_command("play", "-R", f"album:{album}") lines = self._playlist_lines(open_mock) assert sorted(lines) == sorted(baseline), ( "playlist items are not the same" ) assert lines != baseline, "playlist order hasn't changed" def test_command_failed(self, open_mock): open_mock.side_effect = OSError("some reason") with pytest.raises(UserError): self.run_command("play", "title:aNiceTitle") class PlayOnImportTest( TerminalImportMixin, PlayPluginMixin, AutotagImportTestCase ): def setUp(self): super().setUp() self.prepare_album_for_import(1) self.importer = self.setup_importer() def test_play_on_import(self): self.importer.add_choice("y") self.importer.add_choice("1") playlist_path = self.temp_path / "beetsplug_play" / "playlist.m3u" playlist_path.parent.mkdir(parents=True) playlist_path.touch() playlist_path_bytes = os.fsencode(playlist_path) with ( patch( "beetsplug.play.get_temp_filename", side_effect=lambda *_, **__: playlist_path_bytes, ), patch("beetsplug.play.subprocess.call") as subprocess_call_mock, ): self.importer.run() # note that the call has mixed types (str and bytes) subprocess_call_mock.assert_called_once_with( ["echo", playlist_path_bytes] ) beetbox-beets-00724b7/test/plugins/test_fromfilename.py0000664000175000017500000000464115253035401022575 0ustar pieterpieter"""Tests for the fromfilename plugin.""" import pytest from beetsplug import fromfilename class Session: pass class Item: def __init__(self, path): self.path = path self.track = 0 self.artist = "" self.title = "" class Task: def __init__(self, items): self.items = items self.is_album = True @pytest.mark.parametrize( "song1, song2", [ ( ( "/tmp/01 - The Artist - Song One.m4a", 1, "The Artist", "Song One", ), ( "/tmp/02. - The Artist - Song Two.m4a", 2, "The Artist", "Song Two", ), ), ( ("/tmp/01-The_Artist-Song_One.m4a", 1, "The_Artist", "Song_One"), ("/tmp/02.-The_Artist-Song_Two.m4a", 2, "The_Artist", "Song_Two"), ), ( ("/tmp/01 - Song_One.m4a", 1, "", "Song_One"), ("/tmp/02. - Song_Two.m4a", 2, "", "Song_Two"), ), ( ("/tmp/Song One by The Artist.m4a", 0, "The Artist", "Song One"), ("/tmp/Song Two by The Artist.m4a", 0, "The Artist", "Song Two"), ), (("/tmp/01.m4a", 1, "", "01"), ("/tmp/02.m4a", 2, "", "02")), ( ("/tmp/Song One.m4a", 0, "", "Song One"), ("/tmp/Song Two.m4a", 0, "", "Song Two"), ), ( ("/tmp/track01.m4a", 1, "", "track01"), ("/tmp/track 2.m4a", 2, "", "track 2"), ), ], ) def test_fromfilename(song1, song2): """ Each "song" is a tuple of path, expected track number, expected artist, expected title. We use two songs for each test for two reasons: - The plugin needs more than one item to look for uniform strings in paths in order to guess if the string describes an artist or a title. - Sometimes we allow for an optional "." after the track number in paths. """ session = Session() item1 = Item(song1[0]) item2 = Item(song2[0]) task = Task([item1, item2]) f = fromfilename.FromFilenamePlugin() f.filename_task(task, session) assert task.items[0].track == song1[1] assert task.items[0].artist == song1[2] assert task.items[0].title == song1[3] assert task.items[1].track == song2[1] assert task.items[1].artist == song2[2] assert task.items[1].title == song2[3] beetbox-beets-00724b7/test/plugins/test_mbpseudo.py0000664000175000017500000002456015253035401021751 0ustar pieterpieterfrom __future__ import annotations import json from copy import deepcopy from typing import TYPE_CHECKING import pytest from beets.autotag import AlbumInfo, AlbumMatch, Distance, TrackInfo from beets.library import Item from beets.test.helper import PluginMixin from beetsplug.mbpseudo import ( _STATUS_PSEUDO, MusicBrainzPseudoReleasePlugin, PseudoAlbumInfo, ) if TYPE_CHECKING: import pathlib from beetsplug._typing import JSONDict from beetsplug._utils.musicbrainz import Release @pytest.fixture(scope="module") def rsrc_dir(pytestconfig: pytest.Config): return pytestconfig.rootpath / "test" / "rsrc" / "mbpseudo" @pytest.fixture def official_release(rsrc_dir: pathlib.Path) -> Release: info_json = (rsrc_dir / "official_release.json").read_text(encoding="utf-8") return json.loads(info_json) @pytest.fixture def pseudo_release(rsrc_dir: pathlib.Path) -> Release: info_json = (rsrc_dir / "pseudo_release.json").read_text(encoding="utf-8") return json.loads(info_json) @pytest.fixture def official_release_info() -> AlbumInfo: return AlbumInfo( tracks=[TrackInfo(title="百花繚乱")], album_id="official", album="百花繚乱", ) @pytest.fixture def pseudo_release_info() -> AlbumInfo: return AlbumInfo( tracks=[TrackInfo(title="In Bloom")], album_id="pseudo", album="In Bloom", ) @pytest.mark.usefixtures("config") class TestPseudoAlbumInfo: def test_album_id_always_from_pseudo( self, official_release_info: AlbumInfo, pseudo_release_info: AlbumInfo ): info = PseudoAlbumInfo(pseudo_release_info, official_release_info) info.use_official_as_ref() assert info.album_id == "pseudo" def test_get_attr_from_pseudo( self, official_release_info: AlbumInfo, pseudo_release_info: AlbumInfo ): info = PseudoAlbumInfo(pseudo_release_info, official_release_info) assert info.album == "In Bloom" def test_get_attr_from_official( self, official_release_info: AlbumInfo, pseudo_release_info: AlbumInfo ): info = PseudoAlbumInfo(pseudo_release_info, official_release_info) info.use_official_as_ref() assert info.album == info.get_official_release().album def test_determine_best_ref( self, official_release_info: AlbumInfo, pseudo_release_info: AlbumInfo ): info = PseudoAlbumInfo( pseudo_release_info, official_release_info, data_source="test" ) item = Item(title="百花繚乱") assert info.determine_best_ref([item]) == "official" info.use_pseudo_as_ref() assert info.data_source == "test" def test_raw_data( self, official_release_info: AlbumInfo, pseudo_release_info: AlbumInfo ): # raw_data calls self.__class__(**self.copy()), which failed for # PseudoAlbumInfo because its __init__ requires pseudo_release and # official_release args that are not present in the flat copy() dict. info = PseudoAlbumInfo(pseudo_release_info, official_release_info) data = info.raw_data assert data["album"] == "In Bloom" class TestMBPseudoMixin(PluginMixin): plugin = "mbpseudo" @pytest.fixture(autouse=True) def patch_get_release(self, monkeypatch, pseudo_release: JSONDict): monkeypatch.setattr( "beetsplug._utils.musicbrainz.MusicBrainzAPI.get_release", lambda _, album_id: deepcopy( {pseudo_release["id"]: pseudo_release}[album_id] ), ) @pytest.fixture(scope="class") def plugin_config(self): return {"scripts": ["Latn", "Dummy"]} @pytest.fixture def mbpseudo_plugin(self, plugin_config) -> MusicBrainzPseudoReleasePlugin: self.config[self.plugin].set(plugin_config) return MusicBrainzPseudoReleasePlugin() class TestMBPseudoPlugin(TestMBPseudoMixin): def test_scripts_init( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin ): assert mbpseudo_plugin._scripts == ["Latn", "Dummy"] @pytest.mark.parametrize( "album_id", [ "a5ce1d11-2e32-45a4-b37f-c1589d46b103", "-5ce1d11-2e32-45a4-b37f-c1589d46b103", ], ) def test_extract_id_uses_music_brainz_pattern( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, album_id: str ): if album_id.startswith("-"): assert mbpseudo_plugin._extract_id(album_id) is None else: assert mbpseudo_plugin._extract_id(album_id) == album_id def test_album_info_for_pseudo_release( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, pseudo_release: Release, ): album_info = mbpseudo_plugin.album_info(pseudo_release) assert not isinstance(album_info, PseudoAlbumInfo) assert album_info.data_source == "MusicBrainzPseudoRelease" assert album_info.albumstatus == _STATUS_PSEUDO @pytest.mark.parametrize("json_key", ["type", "direction", "release"]) def test_interception_skip_when_rel_values_dont_match( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, official_release: Release, json_key: str, ): del official_release["release_relations"][0][json_key] # type: ignore[misc] album_info = mbpseudo_plugin.album_info(official_release) assert not isinstance(album_info, PseudoAlbumInfo) assert album_info.data_source == "MusicBrainzPseudoRelease" def test_interception_skip_when_script_doesnt_match( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, official_release: Release, ): official_release["release_relations"][0]["release"][ "text_representation" ]["script"] = "Null" album_info = mbpseudo_plugin.album_info(official_release) assert not isinstance(album_info, PseudoAlbumInfo) assert album_info.data_source == "MusicBrainzPseudoRelease" def test_interception( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, official_release: Release, ): album_info = mbpseudo_plugin.album_info(official_release) assert isinstance(album_info, PseudoAlbumInfo) assert album_info.data_source == "MusicBrainzPseudoRelease" def test_final_adjustment_skip( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin ): match = AlbumMatch( distance=Distance(), info=AlbumInfo(tracks=[], data_source="mb"), mapping={}, extra_items=[], extra_tracks=[], ) mbpseudo_plugin._adjust_final_album_match(match) assert match.info.data_source == "mb" def test_final_adjustment( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, official_release_info: AlbumInfo, pseudo_release_info: AlbumInfo, ): pseudo_album_info = PseudoAlbumInfo( pseudo_release=pseudo_release_info, official_release=official_release_info, data_source=mbpseudo_plugin.data_source, ) pseudo_album_info.use_official_as_ref() item = Item() item["title"] = "百花繚乱" match = AlbumMatch( distance=Distance(), info=pseudo_album_info, mapping={item: pseudo_album_info.tracks[0]}, extra_items=[], extra_tracks=[], ) mbpseudo_plugin._adjust_final_album_match(match) assert match.info.data_source == "MusicBrainz" assert match.info.album_id == "pseudo" assert match.info.album == "In Bloom" def test_final_adjustment_updates_match_mapping( self, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, official_release_info: AlbumInfo, pseudo_release_info: AlbumInfo, ): # Regression test: _adjust_final_album_match must update match.mapping, # not album_info.mapping. Writing to album_info (an AttrDict/dict subclass) # stored a {Item: TrackInfo} dict under "mapping", which then leaked into # item_data and caused sqlite3.ProgrammingError on flex field storage. pseudo_album_info = PseudoAlbumInfo( pseudo_release=pseudo_release_info, official_release=official_release_info, data_source=mbpseudo_plugin.data_source, ) item = Item() item["title"] = "百花繚乱" original_track = pseudo_album_info.tracks[0] match = AlbumMatch( distance=Distance(), info=pseudo_album_info, mapping={item: original_track}, extra_items=[], extra_tracks=[], ) mbpseudo_plugin._adjust_final_album_match(match) # match.mapping must be reassigned; album_info must not store a dict value assert "mapping" not in pseudo_album_info assert not any(isinstance(v, dict) for v in pseudo_album_info.values()) class TestMBPseudoPluginCustomTagsOnly(TestMBPseudoMixin): @pytest.fixture(scope="class") def plugin_config(self): return {"scripts": ["Latn", "Dummy"], "custom_tags_only": True} def test_custom_tags( self, config, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, official_release: Release, ): config["import"]["languages"] = ["en", "jp"] album_info = mbpseudo_plugin.album_info(official_release) assert not isinstance(album_info, PseudoAlbumInfo) assert album_info.data_source == "MusicBrainzPseudoRelease" assert album_info["album_transl"] == "In Bloom" assert album_info["album_artist_transl"] == "Lilas Ikuta" assert album_info.tracks[0]["title_transl"] == "In Bloom" assert album_info.tracks[0]["artist_transl"] == "Lilas Ikuta" def test_custom_tags_with_import_languages( self, config, mbpseudo_plugin: MusicBrainzPseudoReleasePlugin, official_release: Release, ): config["import"]["languages"] = [] album_info = mbpseudo_plugin.album_info(official_release) assert not isinstance(album_info, PseudoAlbumInfo) assert album_info.data_source == "MusicBrainzPseudoRelease" assert album_info["album_transl"] == "In Bloom" assert album_info["album_artist_transl"] == "Lilas Ikuta" assert album_info.tracks[0]["title_transl"] == "In Bloom" assert album_info.tracks[0]["artist_transl"] == "Lilas Ikuta" beetbox-beets-00724b7/test/plugins/test_inline.py0000664000175000017500000000526115253035401021406 0ustar pieterpieterfrom typing import ClassVar from beets import config, plugins from beets.test.helper import PluginTestHelper from beetsplug.inline import InlinePlugin class TestInlineRecursion(PluginTestHelper): plugin: ClassVar[str] = "inline" def test_no_recursion_when_inline_shadows_fixed_field(self): config["item_fields"] = { "track_no": ( "f'{disc:02d}-{track:02d}' if disctotal > 1 else f'{track:02d}'" ) } plugins._instances.clear() plugins.load_plugins() item = self.add_item_fixture( artist="Artist", album="Album", title="Title", track=1, disc=1, disctotal=1, ) out = item.evaluate_template("$track_no") assert out == "01" def test_inline_function_body_item_field(self): plugin = InlinePlugin() func = plugin.compile_inline( "return track + 1", album=False, field_name="next_track" ) item = self.add_item_fixture(track=3) assert func(item) == 4 def test_inline_album_expression_uses_items(self): plugin = InlinePlugin() func = plugin.compile_inline( "len(items)", album=True, field_name="item_count" ) album = self.add_album_fixture() assert func(album) == len(list(album.items())) def test_inline_album_expression_uses_items_via_obj(self): plugin = InlinePlugin() func = plugin.compile_inline( "len(db_obj.items())", album=True, field_name="item_count" ) album = self.add_album_fixture() assert func(album) == len(list(album.items())) def test_inline_function_body_item_field_via_obj(self): plugin = InlinePlugin() func = plugin.compile_inline( "return db_obj.track + 1", album=False, field_name="next_track" ) item = self.add_item_fixture(track=3) assert func(item) == 4 def test_inline_obj_missing(self): config["plugins"] = ["inline", "missing"] config["album_fields"] = {"has_missing": ("bool(db_obj.missing)")} plugins._instances.clear() plugins.load_plugins() album = self.add_album_fixture(track_count=1) album.tracktotal = 3 for item in album.items(): item.tracktotal = 3 item.store() album.store() assert album._get("has_missing") def test_inline_function_body_obj(self): plugin = InlinePlugin() func = plugin.compile_inline( "return db_obj.title", album=False, field_name="title_value" ) item = self.add_item_fixture(track=3) assert func(item) beetbox-beets-00724b7/test/plugins/test_fetchart.py0000664000175000017500000001557715253035401021743 0ustar pieterpieterfrom __future__ import annotations import ctypes import sys from typing import TYPE_CHECKING, Any, ClassVar from unittest import mock from beets import importer from beets.test.helper import ( AutotagImportHelper, IOMixin, PluginMixin, PluginTestHelper, ) from beetsplug.fetchart import CoverArtArchive, FetchArtPlugin, FileSystem if TYPE_CHECKING: from pathlib import Path class TestFetchartImport(PluginMixin, AutotagImportHelper): plugin = "fetchart" preload_plugin = False plugin_defaults: ClassVar[Any] = {"sources": ["filesystem", "coverart"]} def setup_beets(self): super().setup_beets() self.prepare_album_for_import(1) self.setup_importer() self.local_art_patcher = mock.patch.object( FileSystem, "get", autospec=True, return_value=iter(()) ) self.local_art_mock = self.local_art_patcher.start() self.remote_art_patcher = mock.patch.object( CoverArtArchive, "get", autospec=True, return_value=iter(()) ) self.remote_art_mock = self.remote_art_patcher.start() def teardown_beets(self): super().teardown_beets() self.local_art_patcher.stop() self.remote_art_patcher.stop() def test_asis_skips_network_sources(self): self.importer.add_choice(importer.Action.ASIS) with self.configure_plugin(self.plugin_defaults): self.importer.run() self.local_art_mock.assert_called() self.remote_art_mock.assert_not_called() def test_apply_uses_network_sources(self): self.importer.add_choice(importer.Action.APPLY) with self.configure_plugin(self.plugin_defaults): self.importer.run() self.local_art_mock.assert_called() self.remote_art_mock.assert_called() def test_fetch_for_asis_uses_network_sources(self): self.importer.add_choice(importer.Action.ASIS) with self.configure_plugin( self.plugin_defaults | {"fetch_for_asis": True} ): self.importer.run() self.local_art_mock.assert_called() self.remote_art_mock.assert_called() class TestFetchartCli(IOMixin, PluginTestHelper): plugin = "fetchart" def setup_beets(self): super().setup_beets() self.config["fetchart"]["cover_names"] = "c\xc3\xb6ver.jpg" self.config["art_filename"] = "mycover" self.album = self.add_album() self.album.filepath.mkdir(parents=True) def cover_path(self, ext: str = "jpg"): return self.album.filepath / f"mycover.{ext}" def check_cover_is_stored(self, ext: str = "jpg"): cover_path = self.cover_path(ext) assert cover_path == self.album.art_filepath assert cover_path.read_text() == "IMAGE" def hide_file_windows(self, path: Path) -> None: if sys.platform == "win32": hidden_mask = 2 assert ctypes.windll.kernel32.SetFileAttributesW( str(path), hidden_mask ) def test_set_art_from_folder(self): (self.album.filepath / "c\xc3\xb6ver.jpg").write_text("IMAGE") self.run_command("fetchart") self.album.load() self.check_cover_is_stored() def test_filesystem_does_not_pick_up_folder(self): self.run_command("fetchart") self.album.load() assert self.album["artpath"] is None def test_filesystem_does_not_pick_up_ignored_file(self): (self.album.filepath / "co_ver.jpg").write_text("IMAGE") self.config["ignore"] = ["*_*"] self.run_command("fetchart") self.album.load() assert self.album["artpath"] is None def test_filesystem_picks_up_non_ignored_file(self): (self.album.filepath / "cover.jpg").write_text("IMAGE") self.config["ignore"] = ["*_*"] self.run_command("fetchart") self.album.load() self.check_cover_is_stored() def test_filesystem_does_not_pick_up_hidden_file(self): path = self.album.filepath / ".cover.jpg" path.write_text("IMAGE") self.hide_file_windows(path) self.config["ignore"] = [] # By default, ignore includes '.*'. self.config["ignore_hidden"] = True self.run_command("fetchart") self.album.load() assert self.album["artpath"] is None def test_filesystem_picks_up_non_hidden_file(self): (self.album.filepath / "cover.jpg").write_text("IMAGE") self.config["ignore_hidden"] = True self.run_command("fetchart") self.album.load() self.check_cover_is_stored() def test_filesystem_picks_up_hidden_file(self): path = self.album.filepath / ".cover.jpg" path.write_text("IMAGE") self.hide_file_windows(path) self.config["ignore"] = [] # By default, ignore includes '.*'. self.config["ignore_hidden"] = False self.run_command("fetchart") self.album.load() self.check_cover_is_stored() def test_filesystem_picks_up_webp_file(self): (self.album.filepath / "cover.webp").write_text("IMAGE") self.run_command("fetchart") self.album.load() self.check_cover_is_stored("webp") def test_filesystem_picks_up_png_file(self): (self.album.filepath / "cover.png").write_text("IMAGE") self.run_command("fetchart") self.album.load() self.check_cover_is_stored("png") def test_colorization(self): self.config["ui"]["color"] = True out = self.run_with_output("fetchart") assert " - the älbum: \x1b[1;31mno art found\x1b[39;49;00m\n" == out def test_set_art_oserror_is_handled_gracefully(self): """OSError (e.g. PermissionError) in set_art is logged as a warning, not an unhandled crash. Regression test for #6193. """ (self.album.filepath / "c\xc3\xb6ver.jpg").write_text("IMAGE") with mock.patch( "beets.library.Album.set_art", side_effect=PermissionError("[WinError 32] file in use"), ): out = self.run_with_output("fetchart") self.album.load() assert "error writing album art" in out assert self.album["artpath"] is None def test_sources_is_a_string(self): self.config["fetchart"].set({"sources": "filesystem"}) fa = FetchArtPlugin() assert len(fa.sources) == 1 assert isinstance(fa.sources[0], FileSystem) def test_sources_is_an_asterisk(self): self.config["fetchart"].set({"sources": "*"}) fa = FetchArtPlugin() assert len(fa.sources) == 10 def test_sources_is_a_string_list(self): self.config["fetchart"].set({"sources": ["filesystem", "coverart"]}) fa = FetchArtPlugin() assert len(fa.sources) == 3 def test_sources_is_a_mapping_list(self): self.config["fetchart"].set( {"sources": {"filesystem": "*", "coverart": "*"}} ) fa = FetchArtPlugin() assert len(fa.sources) == 3 beetbox-beets-00724b7/test/plugins/test_bucket.py0000664000175000017500000001437415253035401021412 0ustar pieterpieter"""Tests for the 'bucket' plugin.""" from datetime import datetime import pytest from beets import config from beets.exceptions import UserError from beets.test.helper import BeetsTestCase from beetsplug import bucket class BucketPluginTest(BeetsTestCase): def setUp(self): super().setUp() self.plugin = bucket.BucketPlugin() def _setup_config( self, bucket_year=[], bucket_alpha=[], bucket_alpha_regex={}, extrapolate=False, ): config["bucket"]["bucket_year"] = bucket_year config["bucket"]["bucket_alpha"] = bucket_alpha config["bucket"]["bucket_alpha_regex"] = bucket_alpha_regex config["bucket"]["extrapolate"] = extrapolate self.plugin.setup() def test_year_single_year(self): """If a single year is given, range starts from this year and stops at the year preceding the one of next bucket.""" self._setup_config(bucket_year=["1950s", "1970s"]) assert self.plugin._tmpl_bucket("1959") == "1950s" assert self.plugin._tmpl_bucket("1969") == "1950s" def test_year_single_year_last_folder(self): """If a single year is given for the last bucket, extend it to current year.""" self._setup_config(bucket_year=["1950", "1970"]) assert self.plugin._tmpl_bucket("2014") == "1970" next_year = datetime.now().year + 1 assert self.plugin._tmpl_bucket(str(next_year)) == str(next_year) def test_year_two_years(self): """Buckets can be named with the 'from-to' syntax.""" self._setup_config(bucket_year=["1950-59", "1960-1969"]) assert self.plugin._tmpl_bucket("1959") == "1950-59" assert self.plugin._tmpl_bucket("1969") == "1960-1969" def test_year_multiple_years(self): """Buckets can be named by listing all the years""" self._setup_config(bucket_year=["1950,51,52,53"]) assert self.plugin._tmpl_bucket("1953") == "1950,51,52,53" assert self.plugin._tmpl_bucket("1974") == "1974" def test_year_out_of_range(self): """If no range match, return the year""" self._setup_config(bucket_year=["1950-59", "1960-69"]) assert self.plugin._tmpl_bucket("1974") == "1974" self._setup_config(bucket_year=[]) assert self.plugin._tmpl_bucket("1974") == "1974" def test_year_out_of_range_extrapolate(self): """If no defined range match, extrapolate all ranges using the most common syntax amongst existing buckets and return the matching one.""" self._setup_config(bucket_year=["1950-59", "1960-69"], extrapolate=True) assert self.plugin._tmpl_bucket("1914") == "1910-19" # pick single year format self._setup_config( bucket_year=["1962-81", "2002", "2012"], extrapolate=True ) assert self.plugin._tmpl_bucket("1983") == "1982" # pick from-end format self._setup_config( bucket_year=["1962-81", "2002", "2012-14"], extrapolate=True ) assert self.plugin._tmpl_bucket("1983") == "1982-01" # extrapolate add ranges, but never modifies existing ones self._setup_config( bucket_year=["1932", "1942", "1952", "1962-81", "2002"], extrapolate=True, ) assert self.plugin._tmpl_bucket("1975") == "1962-81" def test_alpha_all_chars(self): """Alphabet buckets can be named by listing all their chars""" self._setup_config(bucket_alpha=["ABCD", "FGH", "IJKL"]) assert self.plugin._tmpl_bucket("garry") == "FGH" def test_alpha_first_last_chars(self): """Alphabet buckets can be named by listing the 'from-to' syntax""" self._setup_config(bucket_alpha=["0->9", "A->D", "F-H", "I->Z"]) assert self.plugin._tmpl_bucket("garry") == "F-H" assert self.plugin._tmpl_bucket("2pac") == "0->9" def test_alpha_out_of_range(self): """If no range match, return the initial""" self._setup_config(bucket_alpha=["ABCD", "FGH", "IJKL"]) assert self.plugin._tmpl_bucket("errol") == "E" self._setup_config(bucket_alpha=[]) assert self.plugin._tmpl_bucket("errol") == "E" def test_alpha_regex(self): """Check regex is used""" self._setup_config( bucket_alpha=["foo", "bar"], bucket_alpha_regex={"foo": "^[a-d]", "bar": "^[e-z]"}, ) assert self.plugin._tmpl_bucket("alpha") == "foo" assert self.plugin._tmpl_bucket("delta") == "foo" assert self.plugin._tmpl_bucket("zeta") == "bar" assert self.plugin._tmpl_bucket("Alpha") == "A" def test_alpha_regex_mix(self): """Check mixing regex and non-regex is possible""" self._setup_config( bucket_alpha=["A - D", "E - L"], bucket_alpha_regex={"A - D": "^[0-9a-dA-D…äÄ]"}, ) assert self.plugin._tmpl_bucket("alpha") == "A - D" assert self.plugin._tmpl_bucket("Ärzte") == "A - D" assert self.plugin._tmpl_bucket("112") == "A - D" assert self.plugin._tmpl_bucket("…and Oceans") == "A - D" assert self.plugin._tmpl_bucket("Eagles") == "E - L" def test_bad_alpha_range_def(self): """If bad alpha range definition, a UserError is raised.""" with pytest.raises(UserError): self._setup_config(bucket_alpha=["$%"]) def test_bad_year_range_def_no4digits(self): """If bad year range definition, a UserError is raised. Range origin must be expressed on 4 digits. """ with pytest.raises(UserError): self._setup_config(bucket_year=["62-64"]) def test_bad_year_range_def_nodigits(self): """If bad year range definition, a UserError is raised. At least the range origin must be declared. """ with pytest.raises(UserError): self._setup_config(bucket_year=["nodigits"]) def check_span_from_str(self, sstr, dfrom, dto): d = bucket.span_from_str(sstr) assert dfrom == d["from"] assert dto == d["to"] def test_span_from_str(self): self.check_span_from_str("1980 2000", 1980, 2000) self.check_span_from_str("1980 00", 1980, 2000) self.check_span_from_str("1930 00", 1930, 2000) self.check_span_from_str("1930 50", 1930, 1950) beetbox-beets-00724b7/test/plugins/test_web.py0000664000175000017500000006667615253035401020726 0ustar pieterpieter"""Tests for the 'web' plugin""" import json import platform import shutil from collections import Counter from pathlib import Path import pytest from beets.library import Album, Item from beets.test import _common from beets.test.helper import PluginMixin, PytestTestHelper from beetsplug import web class WebPluginMixin(PluginMixin): """Mixin to configure the web plugin for testing.""" plugin = "web" @pytest.fixture(autouse=True) def setup_web_app(self, setup): """Configure the web plugin's Flask app for testing. This fixture sets up the Flask test client and configures the app with the test library. It runs after the base setup fixture from PytestTestHelper. """ # Set up the web app config - we modify self.config["web"] for beets config # but also need to directly configure the Flask app for tests web.app.config["TESTING"] = True web.app.config["lib"] = self.lib web.app.config["INCLUDE_PATHS"] = False web.app.config["READONLY"] = True self.client = web.app.test_client() # Set platform-specific path prefix self.path_prefix = Path( "C:\\" if platform.system() == "Windows" else "/" ) # Add library elements. Note that self.lib.add overrides any "id=" # and assigns the next free id number. # The following adds will create items #1, #2 and #3 self.path1 = self.path_prefix / "path_1" self.lib.add( Item( title="title", path=self.path1, album_id=2, artist="AAA Singers" ) ) self.path2 = self.path_prefix / "somewhere" / "a" self.lib.add( Item(title="another title", path=self.path2, artist="AAA Singers") ) self.path3 = self.path_prefix / "somewhere" / "abc" self.lib.add( Item( title="and a third", testattr="ABC", path=self.path3, album_id=2 ) ) # The following adds will create albums #1 and #2 self.lib.add(Album(album="album", albumtest="xyz")) self.path4 = self.path_prefix / "somewhere2" / "art_path_2" self.lib.add(Album(album="other album", artpath=self.path4)) return class TestWebPlugin(WebPluginMixin, PytestTestHelper): """Tests for the web plugin.""" def test_config_include_paths_true(self): web.app.config["INCLUDE_PATHS"] = True response = self.client.get("/item/1") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["path"] == str(self.path1) web.app.config["INCLUDE_PATHS"] = False def test_config_include_artpaths_true(self): web.app.config["INCLUDE_PATHS"] = True response = self.client.get("/album/2") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["artpath"] == str(self.path4) web.app.config["INCLUDE_PATHS"] = False def test_config_include_paths_false(self): web.app.config["INCLUDE_PATHS"] = False response = self.client.get("/item/1") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert "path" not in res_json def test_config_include_artpaths_false(self): web.app.config["INCLUDE_PATHS"] = False response = self.client.get("/album/2") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert "artpath" not in res_json def test_get_all_items(self): response = self.client.get("/item/") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["items"]) == 3 def test_get_unique_item_artist(self): response = self.client.get("/item/values/artist") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["values"] == ["", "AAA Singers"] def test_get_single_item_by_id(self): response = self.client.get("/item/1") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == 1 assert res_json["title"] == "title" def test_get_multiple_items_by_id(self): response = self.client.get("/item/1,2") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["items"]) == 2 response_titles = {item["title"] for item in res_json["items"]} assert response_titles == {"title", "another title"} def test_get_single_item_not_found(self): response = self.client.get("/item/4") assert response.status_code == 404 def test_get_single_item_by_path(self): data_path = _common.RSRC / "full.mp3" self.lib.add(Item.from_path(data_path)) response = self.client.get(f"/item/path/{data_path}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["title"] == "full" def test_get_single_item_by_path_not_found_if_not_in_library(self): data_path = _common.RSRC / "full.mp3" # data_path points to a valid file, but we have not added the file # to the library. response = self.client.get(f"/item/path/{data_path}") assert response.status_code == 404 def test_get_item_empty_query(self): response = self.client.get("/item/query/") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["items"]) == 3 def test_get_simple_item_query(self): response = self.client.get("/item/query/another") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["title"] == "another title" def test_query_item_string(self): response = self.client.get("/item/query/testattr%3aABC") # testattr:ABC res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["title"] == "and a third" def test_query_item_regex(self): response = self.client.get( "/item/query/testattr%3a%3a[A-C]%2b" ) # testattr::[A-C]+ res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["title"] == "and a third" def test_query_item_regex_backslash(self): response = self.client.get( "/item/query/testattr%3a%3a%5cw%2b" ) # testattr::\w+ res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["title"] == "and a third" def test_query_item_path(self): """Note: path queries are special: the query item must match the path from the root all the way to a directory, so this matches 1 item""" """ Note: filesystem separators in the query must be '\' """ prefix = "C:" if platform.system() == "Windows" else "" response = self.client.get(f"/item/query/path:{prefix}\\somewhere\\a") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["title"] == "another title" def test_get_all_albums(self): response = self.client.get("/album/") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 response_albums = [album["album"] for album in res_json["albums"]] assert Counter(response_albums) == {"album": 1, "other album": 1} def test_get_single_album_by_id(self): response = self.client.get("/album/2") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == 2 assert res_json["album"] == "other album" def test_get_multiple_albums_by_id(self): response = self.client.get("/album/1,2") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 response_albums = [album["album"] for album in res_json["albums"]] assert Counter(response_albums) == {"album": 1, "other album": 1} def test_get_album_empty_query(self): response = self.client.get("/album/query/") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["albums"]) == 2 def test_get_simple_album_query(self): response = self.client.get("/album/query/other") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["album"] == "other album" assert res_json["results"][0]["id"] == 2 def test_get_album_details(self): response = self.client.get("/album/2?expand") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["items"]) == 2 assert res_json["items"][0]["album"] == "other album" assert res_json["items"][1]["album"] == "other album" response_track_titles = {item["title"] for item in res_json["items"]} assert response_track_titles == {"title", "and a third"} def test_query_album_string(self): response = self.client.get( "/album/query/albumtest%3axy" ) # albumtest:xy res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["album"] == "album" def test_query_album_artpath_regex(self): response = self.client.get( "/album/query/artpath%3a%3aart_" ) # artpath::art_ res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["album"] == "other album" def test_query_album_regex_backslash(self): response = self.client.get( "/album/query/albumtest%3a%3a%5cw%2b" ) # albumtest::\w+ res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 assert res_json["results"][0]["album"] == "album" def test_get_stats(self): response = self.client.get("/stats") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["items"] == 3 assert res_json["albums"] == 2 def test_delete_item_id(self): web.app.config["READONLY"] = False # Create a temporary item item_id = self.lib.add( Item(title="test_delete_item_id", test_delete_item_id=1) ) # Check we can find the temporary item we just created response = self.client.get(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id # Delete item by id response = self.client.delete(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 # Check the item has gone response = self.client.get(f"/item/{item_id}") assert response.status_code == 404 # Note: if this fails, the item may still be around # and may cause other tests to fail def test_delete_item_without_file(self): web.app.config["READONLY"] = False # Create an item with a file ipath = self.temp_path / "testfile1.mp3" shutil.copy(_common.RSRC / "full.mp3", ipath) assert ipath.exists() item_id = self.lib.add(Item.from_path(ipath)) # Check we can find the temporary item we just created response = self.client.get(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id # Delete item by id, without deleting file response = self.client.delete(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 # Check the item has gone response = self.client.get(f"/item/{item_id}") assert response.status_code == 404 # Check the file has not gone assert ipath.exists() ipath.unlink() def test_delete_item_with_file(self): web.app.config["READONLY"] = False # Create an item with a file ipath = self.temp_path / "testfile2.mp3" shutil.copy(_common.RSRC / "full.mp3", ipath) assert ipath.exists() item_id = self.lib.add(Item.from_path(ipath)) # Check we can find the temporary item we just created response = self.client.get(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id # Delete item by id, with file response = self.client.delete(f"/item/{item_id}?delete") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 # Check the item has gone response = self.client.get(f"/item/{item_id}") assert response.status_code == 404 # Check the file has gone assert not ipath.exists() def test_delete_item_query(self): web.app.config["READONLY"] = False # Create a temporary item self.lib.add( Item(title="test_delete_item_query", test_delete_item_query=1) ) # Check we can find the temporary item we just created response = self.client.get("/item/query/test_delete_item_query") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 # Delete item by query response = self.client.delete("/item/query/test_delete_item_query") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 # Check the item has gone response = self.client.get("/item/query/test_delete_item_query") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 0 def test_delete_item_all_fails(self): """DELETE is not supported for list all""" web.app.config["READONLY"] = False # Delete all items response = self.client.delete("/item/") assert response.status_code == 405 # Note: if this fails, all items have gone and rest of # tests will fail! def test_delete_item_id_readonly(self): web.app.config["READONLY"] = True # Create a temporary item item_id = self.lib.add( Item(title="test_delete_item_id_ro", test_delete_item_id_ro=1) ) # Check we can find the temporary item we just created response = self.client.get(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id # Try to delete item by id response = self.client.delete(f"/item/{item_id}") assert response.status_code == 405 # Check the item has not gone response = self.client.get(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id # Remove it self.lib.get_item(item_id).remove() def test_delete_item_query_readonly(self): web.app.config["READONLY"] = True # Create a temporary item item_id = self.lib.add( Item(title="test_delete_item_q_ro", test_delete_item_q_ro=1) ) # Check we can find the temporary item we just created response = self.client.get("/item/query/test_delete_item_q_ro") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 # Try to delete item by query response = self.client.delete("/item/query/test_delete_item_q_ro") assert response.status_code == 405 # Check the item has not gone response = self.client.get("/item/query/test_delete_item_q_ro") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 # Remove it self.lib.get_item(item_id).remove() def test_delete_album_id(self): web.app.config["READONLY"] = False # Create a temporary album album_id = self.lib.add( Album(album="test_delete_album_id", test_delete_album_id=1) ) # Check we can find the temporary album we just created response = self.client.get(f"/album/{album_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == album_id # Delete album by id response = self.client.delete(f"/album/{album_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 # Check the album has gone response = self.client.get(f"/album/{album_id}") assert response.status_code == 404 # Note: if this fails, the album may still be around # and may cause other tests to fail def test_delete_album_query(self): web.app.config["READONLY"] = False # Create a temporary album self.lib.add( Album(album="test_delete_album_query", test_delete_album_query=1) ) # Check we can find the temporary album we just created response = self.client.get("/album/query/test_delete_album_query") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 # Delete album response = self.client.delete("/album/query/test_delete_album_query") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 # Check the album has gone response = self.client.get("/album/query/test_delete_album_query") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 0 def test_delete_album_all_fails(self): """DELETE is not supported for list all""" web.app.config["READONLY"] = False # Delete all albums response = self.client.delete("/album/") assert response.status_code == 405 # Note: if this fails, all albums have gone and rest of # tests will fail! def test_delete_album_id_readonly(self): web.app.config["READONLY"] = True # Create a temporary album album_id = self.lib.add( Album(album="test_delete_album_id_ro", test_delete_album_id_ro=1) ) # Check we can find the temporary album we just created response = self.client.get(f"/album/{album_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == album_id # Try to delete album by id response = self.client.delete(f"/album/{album_id}") assert response.status_code == 405 # Check the item has not gone response = self.client.get(f"/album/{album_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == album_id # Remove it self.lib.get_album(album_id).remove() def test_delete_album_query_readonly(self): web.app.config["READONLY"] = True # Create a temporary album album_id = self.lib.add( Album( album="test_delete_album_query_ro", test_delete_album_query_ro=1 ) ) # Check we can find the temporary album we just created response = self.client.get("/album/query/test_delete_album_query_ro") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 # Try to delete album response = self.client.delete("/album/query/test_delete_album_query_ro") assert response.status_code == 405 # Check the album has not gone response = self.client.get("/album/query/test_delete_album_query_ro") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert len(res_json["results"]) == 1 # Remove it self.lib.get_album(album_id).remove() def test_patch_item_id(self): # Note: PATCH is currently only implemented for track items, not albums web.app.config["READONLY"] = False # Create a temporary item item_id = self.lib.add( Item( title="test_patch_item_id", test_patch_f1=1, test_patch_f2="Old" ) ) # Check we can find the temporary item we just created response = self.client.get(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id assert res_json["test_patch_f1"] == "1" assert res_json["test_patch_f2"] == "Old" # Patch item by id # patch_json = json.JSONEncoder().encode({"test_patch_f2": "New"}]}) response = self.client.patch( f"/item/{item_id}", json={"test_patch_f2": "New"} ) res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id assert res_json["test_patch_f1"] == "1" assert res_json["test_patch_f2"] == "New" # Check the update has really worked response = self.client.get(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id assert res_json["test_patch_f1"] == "1" assert res_json["test_patch_f2"] == "New" # Remove the item self.lib.get_item(item_id).remove() def test_patch_item_id_readonly(self): # Note: PATCH is currently only implemented for track items, not albums web.app.config["READONLY"] = True # Create a temporary item item_id = self.lib.add( Item( title="test_patch_item_id_ro", test_patch_f1=2, test_patch_f2="Old", ) ) # Check we can find the temporary item we just created response = self.client.get(f"/item/{item_id}") res_json = json.loads(response.data.decode("utf-8")) assert response.status_code == 200 assert res_json["id"] == item_id assert res_json["test_patch_f1"] == "2" assert res_json["test_patch_f2"] == "Old" # Patch item by id # patch_json = json.JSONEncoder().encode({"test_patch_f2": "New"}) response = self.client.patch( f"/item/{item_id}", json={"test_patch_f2": "New"} ) assert response.status_code == 405 # Remove the item self.lib.get_item(item_id).remove() def test_get_item_file(self): ipath = self.temp_path / "testfile2.mp3" shutil.copy(_common.RSRC / "full.mp3", ipath) assert ipath.exists() item_id = self.lib.add(Item.from_path(ipath)) response = self.client.get(f"/item/{item_id}/file") assert response.status_code == 200 class TestWebXSS(WebPluginMixin, PytestTestHelper): """Tests for XSS vulnerability in the web plugin templates. These tests verify that the Underscore.js templates in index.html use the escaping syntax (<%- %) instead of the non-escaping syntax (<%= %). In Underscore.js 1.2.2 (used by beets): - <%= variable %> does NOT escape HTML (vulnerable to XSS) - <%- variable %> DOES escape HTML (safe) This was reported in https://github.com/beetbox/beets/security/advisories/GHSA-3gxm-wfjx-m847 and remediated in https://github.com/beetbox/beets/commit/75f0d8f4899e61afb939adf02dcfb078aed23a6a """ def test_templates_use_escaping_syntax(self): """Verify that all Underscore.js templates use <%- %> for escaping. This test requests the index.html page and checks that all user data interpolations in the Underscore.js templates use the escaping syntax (<%- %) rather than the non-escaping syntax (<%= %). """ import re # Request the index.html page response = self.client.get("/") html = response.data.decode("utf-8") # Extract the template scripts from the HTML # The templates are in ' templates = re.findall(template_pattern, html, re.DOTALL) # Combine all template content for checking all_template_content = "\n".join(templates) # Check that no <%= %> (non-escaping) tags exist for user data # We look for <%= followed by a variable name (word characters) non_escaping_pattern = r"<%=\s*(\w+)\s*%>" non_escaping_matches = re.findall( non_escaping_pattern, all_template_content ) # List of fields that should be escaped (user-controlled data) user_data_fields = [ "title", "artist", "album", "year", "track", "tracktotal", "disc", "disctotal", "length", "format", "bitrate", "mb_trackid", "id", "lyrics", "comments", ] # Check if any user data fields are using non-escaping <%= %> vulnerable_fields = [ field for field in non_escaping_matches if field in user_data_fields ] # If we found any user data fields using <%= %>, the templates are vulnerable assert len(vulnerable_fields) == 0, ( "Found non-escaping <%= %> tags for user data fields: " f"{vulnerable_fields}. " "These should use <%- %> for HTML escaping to prevent XSS." ) # Also verify that escaping tags (<%- %>) are present for user data escaping_pattern = r"<%-\s*(\w+)\s*%>" escaping_matches = re.findall(escaping_pattern, all_template_content) # At least some user data fields should use escaping safe_fields = [ field for field in escaping_matches if field in user_data_fields ] assert len(safe_fields) > 0, ( "No escaping <%- %> tags found for user data fields. " "Templates should use <%- %> for HTML escaping." ) beetbox-beets-00724b7/test/plugins/test_importadded.py0000664000175000017500000001244715253035401022430 0ustar pieterpieter"""Tests for the `importadded` plugin.""" from __future__ import annotations import os from pathlib import Path from typing import TYPE_CHECKING import pytest from beets import importer from beets.test.helper import AutotagImportTestCase, PluginMixin if TYPE_CHECKING: from collections.abc import Iterable def modify_mtimes(paths: Iterable[Path], offset=-60000): for i, path in enumerate(paths, start=1): mstat = path.stat() os.utime(path, (mstat.st_atime, mstat.st_mtime + offset * i)) class ImportAddedTest(PluginMixin, AutotagImportTestCase): # The minimum mtime of the files to be imported plugin = "importadded" min_mtime = None def setUp(self): super().setUp() self.prepare_album_for_import(2) # Different mtimes on the files to be imported in order to test the # plugin paths = [Path(mfile.path) for mfile in self.import_media] modify_mtimes(paths) self.min_mtime = min(p.stat().st_mtime for p in paths) self.importer = self.setup_importer() self.importer.add_choice(importer.Action.APPLY) def find_media_file_mtime(self, item) -> float: """Find the pre-import MediaFile for an Item""" for m in self.import_media: if m.title.replace("Tag", "Applied") == item.title: return Path(m.path).stat().st_mtime raise AssertionError(f"No MediaFile found for Item {item.filepath}") def test_import_album_with_added_dates(self): self.importer.run() album = self.lib.albums().get() assert album.added == self.min_mtime for item in album.items(): assert item.added == self.min_mtime def test_import_album_inplace_with_added_dates(self): self.config["import"]["copy"] = False self.importer.run() album = self.lib.albums().get() assert album.added == self.min_mtime for item in album.items(): assert item.added == self.min_mtime def test_import_album_with_preserved_mtimes(self): self.config["importadded"]["preserve_mtimes"] = True self.importer.run() album = self.lib.albums().get() assert album.added == self.min_mtime for item in album.items(): assert item.added == pytest.approx(self.min_mtime, rel=1e-4) mediafile_mtime = self.find_media_file_mtime(item) assert item.mtime == pytest.approx(mediafile_mtime, rel=1e-4) assert item.filepath.stat().st_mtime == pytest.approx( mediafile_mtime, rel=1e-4 ) def test_reimported_album_skipped(self): # Import and record the original added dates self.importer.run() album = self.lib.albums().get() album_added_before = album.added items_added_before = { item.filepath: item.added for item in album.items() } # Newer Item path mtimes as if Beets had modified them modify_mtimes(items_added_before.keys(), offset=10000) # Reimport self.setup_importer(import_dir=self.lib_path) self.importer.run() # Verify the reimported items album = self.lib.albums().get() assert album.added == pytest.approx(album_added_before, rel=1e-4) items_added_after = { item.filepath: item.added for item in album.items() } for item_path, added_after in items_added_after.items(): assert items_added_before[item_path] == pytest.approx( added_after, rel=1e-4 ), f"reimport modified Item.added for {item_path}" def test_import_singletons_with_added_dates(self): self.config["import"]["singletons"] = True self.importer.run() for item in self.lib.items(): assert item.added == pytest.approx( self.find_media_file_mtime(item), rel=1e-4 ) def test_import_singletons_with_preserved_mtimes(self): self.config["import"]["singletons"] = True self.config["importadded"]["preserve_mtimes"] = True self.importer.run() for item in self.lib.items(): mediafile_mtime = self.find_media_file_mtime(item) assert item.added == pytest.approx(mediafile_mtime, rel=1e-4) assert item.mtime == pytest.approx(mediafile_mtime, rel=1e-4) assert item.filepath.stat().st_mtime == pytest.approx( mediafile_mtime, rel=1e-4 ) def test_reimported_singletons_skipped(self): self.config["import"]["singletons"] = True # Import and record the original added dates self.importer.run() items_added_before = { item.filepath: item.added for item in self.lib.items() } # Newer Item path mtimes as if Beets had modified them modify_mtimes(items_added_before.keys(), offset=10000) # Reimport self.setup_importer(import_dir=self.lib_path, singletons=True) self.importer.run() # Verify the reimported items items_added_after = { item.filepath: item.added for item in self.lib.items() } for item_path, added_after in items_added_after.items(): assert items_added_before[item_path] == pytest.approx( added_after, rel=1e-4 ), f"reimport modified Item.added for {item_path}" beetbox-beets-00724b7/test/plugins/test_importsource.py0000664000175000017500000000732715253035401022670 0ustar pieterpieter"""Tests for the `importsource` plugin.""" import os import time from beets import importer, plugins from beets.test.helper import AutotagImportTestCase, IOMixin, PluginMixin class ImportSourceTest(IOMixin, PluginMixin, AutotagImportTestCase): plugin = "importsource" preload_plugin = False def setUp(self): super().setUp() self.config[self.plugin]["suggest_removal"] = True self.load_plugins() self.prepare_album_for_import(2) self.importer = self.setup_importer() self.importer.add_choice(importer.Action.APPLY) self.importer.run() self.all_items = self.lib.albums().get().items() self.item_to_remove = self.all_items[0] def interact(self, stdin: list[str]): for char in stdin: self.io.addinput(char) self.run_command("remove", f"path:{self.item_to_remove.filepath}") def test_do_nothing(self): self.interact(["N"]) assert os.path.exists(self.item_to_remove.source_path) def test_remove_single(self): self.interact(["y", "D"]) assert not os.path.exists(self.item_to_remove.source_path) def test_remove_all_from_single(self): self.interact(["y", "R", "y"]) for item in self.all_items: assert not os.path.exists(item.source_path) def test_stop_suggesting(self): self.interact(["y", "S"]) for item in self.all_items: assert os.path.exists(item.source_path) def test_source_path_attribute_written(self): """Test that source_path attribute is correctly written to imported items. The items should already have source_path from the setUp import """ for item in self.all_items: assert "source_path" in item assert item.source_path # Should not be empty def test_source_files_not_modified_during_import(self): """Test that source files timestamps are not changed during import.""" # Prepare fresh files and record timestamps test_album_path = self.import_path / "test_album" import_paths = self.prepare_album_for_import( 2, album_path=test_album_path ) original_mtimes = {p: p.stat().st_mtime for p in import_paths} # Small delay to detect timestamp changes time.sleep(0.1) # Run a fresh import importer_session = self.setup_importer() importer_session.add_choice(importer.Action.APPLY) importer_session.run() # Verify timestamps haven't changed for path, original_mtime in original_mtimes.items(): current_mtime = path.stat().st_mtime assert current_mtime == original_mtime, ( f"Source file timestamp changed: {path}" ) def test_prevent_suggest_removal_on_reimport(self): """Test that removal suggestions are prevented during reimport.""" album = self.lib.albums().get() mb_albumid = album.mb_albumid # Reimport from library reimporter = self.setup_importer(import_dir=self.lib_path) reimporter.add_choice(importer.Action.APPLY) reimporter.run() plugin = plugins._instances[0] assert mb_albumid in plugin.stop_suggestions_for_albums # Calling suggest_removal should exit early without prompting item = self.lib.items().get() plugin.suggest_removal(item) assert os.path.exists(item.source_path) def test_prevent_suggest_removal_handles_skipped_task(self): """Test that skipped tasks don't crash prevent_suggest_removal.""" class MockTask: skip = True plugin = plugins._instances[0] mock_task = MockTask() plugin.prevent_suggest_removal(None, mock_task) beetbox-beets-00724b7/test/plugins/test_mbsubmit.py0000664000175000017500000000253615253035401021754 0ustar pieterpieterfrom beets.test.helper import ( AutotagImportTestCase, PluginMixin, TerminalImportMixin, ) class MBSubmitPluginTest( PluginMixin, TerminalImportMixin, AutotagImportTestCase ): plugin = "mbsubmit" def setUp(self): super().setUp() self.prepare_album_for_import(2) self.setup_importer() def test_print_tracks_output(self): """Test the output of the "print tracks" choice.""" self.io.addinput("p") self.io.addinput("s") # Print tracks; Skip self.importer.run() # Manually build the string for comparing the output. tracklist = ( "Open files with Picard? " "01. Tag Track 1 - Tag Artist (0:01)\n" "02. Tag Track 2 - Tag Artist (0:01)" ) assert tracklist in self.io.getoutput() def test_print_tracks_output_as_tracks(self): """Test the output of the "print tracks" choice, as singletons.""" self.io.addinput("t") self.io.addinput("s") self.io.addinput("p") self.io.addinput("s") # as Tracks; Skip; Print tracks; Skip self.importer.run() # Manually build the string for comparing the output. tracklist = ( "Open files with Picard? 02. Tag Track 2 - Tag Artist (0:01)" ) assert tracklist in self.io.getoutput() beetbox-beets-00724b7/test/plugins/__init__.py0000664000175000017500000000000015253035401020612 0ustar pieterpieterbeetbox-beets-00724b7/test/plugins/test_musicbrainz.py0000664000175000017500000007740015253035401022462 0ustar pieterpieter"""Tests for MusicBrainz API wrapper.""" from __future__ import annotations import uuid from typing import TYPE_CHECKING, ClassVar import pytest import requests from beets.library import Item from beets.test.helper import PluginMixin from beetsplug import musicbrainz from beetsplug.musicbrainz import MusicBrainzPlugin from .factories import musicbrainz as factories if TYPE_CHECKING: from beetsplug._utils import musicbrainz as mb _p = pytest.param def alias_factory(**kwargs) -> mb.Alias: return factories.AliasFactory.build(**kwargs) def artist_credit_factory(**kwargs) -> mb.ArtistCredit: return factories.ArtistCreditFactory.build(**kwargs) def artist_relation_factory(**kwargs) -> mb.ArtistRelation: return factories.ArtistRelationFactory.build(**kwargs) def label_info_factory(**kwargs) -> mb.LabelInfo: return factories.LabelInfoFactory.build(**kwargs) def recording_factory(**kwargs) -> mb.Recording: return factories.RecordingFactory.build(**kwargs) def track_factory(**kwargs) -> mb.Track: return factories.TrackFactory.build(**kwargs) def url_relation_factory(**kwargs) -> mb.UrlRelation: return factories.UrlRelationFactory.build(**kwargs) def medium_factory(**kwargs) -> mb.Medium: return factories.MediumFactory.build(**kwargs) def release_factory(**kwargs) -> mb.Release: return factories.ReleaseFactory.build(**kwargs) class TestUtils: @pytest.mark.parametrize( "date, expected_parts", [ ("1987-03-01", (1987, 3, 1)), ("1987-03", (1987, 3, None)), ("1987", (1987, None, None)), ], ) def test_get_date(self, date, expected_parts): assert musicbrainz._get_date(date) == expected_parts def test_single_artist(self): credit = [artist_credit_factory(artist__name="Artist")] assert MusicBrainzPlugin()._parse_artist_credits(credit) == { "artist": "Artist", "artist_id": "00000000-0000-0000-0000-000000000001", "artist_sort": "Artist, The", "artist_credit": "Artist Credit", "artists": ["Artist"], "artists_ids": ["00000000-0000-0000-0000-000000000001"], "artists_sort": ["Artist, The"], "artists_credit": ["Artist Credit"], } def test_two_artists(self): credit = [ artist_credit_factory(artist__name="Artist", joinphrase=" AND "), artist_credit_factory(artist__name="Other Artist", artist__index=2), ] assert MusicBrainzPlugin()._parse_artist_credits(credit) == { "artist": "Artist AND Other Artist", "artist_id": "00000000-0000-0000-0000-000000000001", "artist_sort": "Artist, The AND Other Artist, The", "artist_credit": "Artist Credit AND Other Artist Credit", "artists": ["Artist", "Other Artist"], "artists_ids": [ "00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002", ], "artists_sort": ["Artist, The", "Other Artist, The"], "artists_credit": ["Artist Credit", "Other Artist Credit"], } @pytest.mark.parametrize( "languages_config, expected_alias_name", [ _p([], None, id="no alias without languages"), _p(["en"], "Alias en", id="en primary"), _p(["en_GB", "en"], "Alias en_GB", id="en_GB primary"), _p(["en", "en_GB"], "Alias en", id="en primary over en_GB"), _p(["fr"], "Alias fr_P", id="fr primary"), _p(["pt_BR", "fr"], "Alias fr_P", id="non-primary ignored"), ], ) def test_preferred_alias( self, config, languages_config, expected_alias_name ): aliases = [ alias_factory(locale="en"), alias_factory(locale="en_GB"), alias_factory(locale="fr", primary=False), alias_factory(suffix="fr_P", locale="fr"), alias_factory(locale="pt_BR", primary=False), ] config["import"]["languages"] = languages_config alias = musicbrainz._preferred_alias(aliases) if expected_alias_name is None: assert not alias else: assert alias["name"] == expected_alias_name @pytest.mark.parametrize( "label_infos, expected", [ _p([], {"catalognum": None, "label": None}, id="no label"), _p( [label_info_factory(label=None)], {"catalognum": "LAB123", "label": None}, id="no label", ), _p( [label_info_factory(label__name="[no label]")], {"catalognum": "LAB123", "label": None}, id="label with ignored [no label] name", ), _p( [label_info_factory()], {"catalognum": "LAB123", "label": "Label"}, id="normal case", ), ], ) def test_parse_label_info(self, label_infos, expected): assert MusicBrainzPlugin._parse_label_infos(label_infos) == expected class MusicBrainzPluginTestMixin(PluginMixin): plugin = "musicbrainz" @pytest.fixture def plugin_config(self): return {} @pytest.fixture def mb(self, plugin_config): self.config[self.plugin].set(plugin_config) return musicbrainz.MusicBrainzPlugin() class TestParseRecording(MusicBrainzPluginTestMixin): def test_parse_recording(self, mb): recording = recording_factory( length=None, disambiguation="Recording Disambiguation", artist_relations=[ artist_relation_factory( type="remixer", artist__index=1, artist__name="Recording Remixer", ), artist_relation_factory( type="arranger", artist__index=2, artist__name="Recording Arranger", ), artist_relation_factory( type="arranger", artist__index=3, artist__name="Another Recording Arranger", ), artist_relation_factory(type="engineer"), ], work_relations=[ { "type": "performance", "work": { "id": "WORK ID", "title": "WORK TITLE", "artist_relations": [ artist_relation_factory( type="lyricist", artist__index=4, artist__name="Recording Lyricist", ), artist_relation_factory( type="lyricist", artist__index=5, artist__name="Another Recording Lyricist", ), artist_relation_factory( type="composer", artist__index=6, artist__name="Recording Composer", ), artist_relation_factory( type="composer", artist__index=7, artist__name="Another Recording Composer", ), artist_relation_factory(type="mastering"), ], }, } ], ) assert mb.track_info(recording) == { "album": None, "arrangers": ["Recording Arranger", "Another Recording Arranger"], "arrangers_ids": [ "00000000-0000-0000-0000-000000000002", "00000000-0000-0000-0000-000000000003", ], "artist": "Recording Artist", "artist_credit": "Recording Artist Credit", "artist_id": "00000000-0000-0000-0000-000000000001", "artist_sort": "Recording Artist, The", "artists": ["Recording Artist"], "artists_credit": ["Recording Artist Credit"], "artists_ids": ["00000000-0000-0000-0000-000000000001"], "artists_sort": ["Recording Artist, The"], "bpm": None, "composer_sort": "Recording Composer, The, Another Recording Composer, The", "composers": ["Recording Composer", "Another Recording Composer"], "composers_ids": [ "00000000-0000-0000-0000-000000000006", "00000000-0000-0000-0000-000000000007", ], "data_source": "MusicBrainz", "data_url": "https://musicbrainz.org/recording/00000000-0000-0000-0000-000000001001", "disctitle": None, "genres": None, "index": None, "initial_key": None, "isrc": None, "length": None, "lyricists": ["Recording Lyricist", "Another Recording Lyricist"], "lyricists_ids": [ "00000000-0000-0000-0000-000000000004", "00000000-0000-0000-0000-000000000005", ], "mb_workid": "WORK ID", "media": None, "medium": None, "medium_index": None, "medium_total": None, "release_track_id": None, "remixers": ["Recording Remixer"], "remixers_ids": ["00000000-0000-0000-0000-000000000001"], "title": "Recording", "track_alt": None, "track_id": "00000000-0000-0000-0000-000000001001", "trackdisambig": "Recording Disambiguation", "work": "WORK TITLE", "work_disambig": None, } class TestParseMedia(MusicBrainzPluginTestMixin): def test_multiple_mediums(self, mb): first_medium = medium_factory( title="First Medium", position=1, tracks=[ track_factory(recording__length=100000), track_factory( position=2, recording__index=2, recording__length=200000, recording__title="Other Recording", ), ], ) second_medium = medium_factory( title="Second Medium", position=2, pregap=track_factory(recording__title="Pregap", position=0), tracks=[track_factory()], ) release = release_factory(media=[first_medium, second_medium]) d = mb.album_info(release) assert d.mediums == 2 t = d.tracks assert len(t) == 4 assert t[0].title == "Recording" assert t[0].track_id == "00000000-0000-0000-0000-000000001001" assert t[0].length == 100.0 assert t[0].medium == 1 assert t[0].medium_index == 1 assert t[0].index == 1 assert t[0].disctitle == "First Medium" assert t[1].title == "Other Recording" assert t[1].track_id == "00000000-0000-0000-0000-000000001002" assert t[1].length == 200.0 assert t[1].medium == 1 assert t[1].medium_index == 2 assert t[1].index == 2 assert t[1].disctitle == "First Medium" assert t[2].title == "Pregap" assert t[2].medium == 2 assert t[2].medium_index == 0 assert t[2].index == 3 assert t[2].disctitle == "Second Medium" assert t[3].medium == 2 assert t[3].medium_index == 1 assert t[3].index == 4 assert t[3].disctitle == "Second Medium" def test_track_overrides_recording(self, mb): release = release_factory( media__0__tracks=[ track_factory( length=1000.0, artist_credit=[ artist_credit_factory( artist__name="Track Artist", joinphrase=" & " ), artist_credit_factory( artist__name="Other Track Artist", artist__index=2 ), ], recording__length=2000.0, recording__artist_credit=[ artist_credit_factory( artist__name="Recording Artist", joinphrase=" & " ), artist_credit_factory( artist__name="Other Recording Artist", artist__index=2, ), ], ) ] ) track = mb.album_info(release).tracks[0] assert track.length == 1.0 assert track.artist == "Track Artist & Other Track Artist" assert track.artist_id == "00000000-0000-0000-0000-000000000001" assert ( track.artist_sort == "Track Artist, The & Other Track Artist, The" ) assert ( track.artist_credit == "Track Artist Credit & Other Track Artist Credit" ) assert track.artists == ["Track Artist", "Other Track Artist"] assert track.artists_ids == [ "00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002", ] assert track.artists_sort == [ "Track Artist, The", "Other Track Artist, The", ] assert track.artists_credit == [ "Track Artist Credit", "Other Track Artist Credit", ] def test_missing_tracks(self, mb): release = release_factory( media=[ medium_factory(), medium_factory( tracks=[ track_factory(), track_factory( recording__title="Other Recording", recording__disambiguation="SECOND TRACK", ), ] ), ] ) assert mb.album_info(release).mediums == 2 @pytest.mark.parametrize( "beets_match_config, expected_titles", [ _p({}, ("Audio",), id="only audio tracks by default"), _p( {"ignore_data_tracks": False}, ("Audio", "Data"), id="include data tracks", ), _p( {"ignore_data_tracks": False, "ignore_video_tracks": False}, ("Audio", "Video: Video", "Data"), id="include data and video tracks", ), _p({"ignored_media": "Vinyl"}, (), id="ignore all tracks"), ], ) def test_data_tracks(self, config, beets_match_config, mb, expected_titles): medium = medium_factory( format="Vinyl", tracks=[ track_factory(recording__title="Audio"), track_factory(recording__title="[data track]"), track_factory(recording__title="Video", recording__video=True), ], data_tracks=[track_factory(recording__title="Data")], ) release = release_factory(media=[medium]) config.set({"match": beets_match_config}) actual_titles = tuple(t.title for t in mb.album_info(release).tracks) assert actual_titles == expected_titles class TestParseRelease(MusicBrainzPluginTestMixin): def test_parse_release(self, config, mb): config["match"]["preferred"]["countries"] = ["US"] mb.config.set( { "external_ids": { "discogs": True, "bandcamp": True, "spotify": False, } } ) release = release_factory( url_relations=[ url_relation_factory( url__resource="https://discogs.com/release/123456" ), url_relation_factory( url__resource="https://open.spotify.com/album/ABCDab2ImQyHZ9sXCXFyZ8" ), url_relation_factory( url__resource="https://somemusic.bandcamp.com/album/somealbum" ), ] ) d = mb.album_info(release) assert d == { "album": "Album", "album_id": "00000000-0000-0000-0000-000001000001", "albumdisambig": "Album Disambiguation", "albumstatus": "Official", "albumtype": "album", "albumtypes": ["album"], "artist": "Artist", "artist_credit": "Artist Credit", "artist_id": "00000000-0000-0000-0000-000000000011", "artist_sort": "Artist, The", "artists": ["Artist"], "artists_credit": ["Artist Credit"], "artists_ids": ["00000000-0000-0000-0000-000000000011"], "artists_sort": ["Artist, The"], "asin": "Album Asin", "bandcamp_album_id": "https://somemusic.bandcamp.com/album/somealbum", "barcode": "0000000000000", "catalognum": "LAB123", "country": "US", "data_source": "MusicBrainz", "data_url": "https://musicbrainz.org/release/00000000-0000-0000-0000-000001000001", "day": 1, "discogs_album_id": "123456", "discogs_albumid": None, "discogs_artistid": None, "discogs_labelid": None, "genres": None, "label": "Label", "language": "eng", "media": "Digital Media", "mediums": 1, "month": 1, "original_day": 3, "original_month": 2, "original_year": 2001, "release_group_title": "Release Group", "releasegroup_id": "00000000-0000-0000-0000-000000000101", "releasegroupdisambig": "Release Group Disambiguation", "script": "Latn", "style": None, "tracks": [ { "album": None, "arrangers": None, "arrangers_ids": [], "artist": "Recording Artist", "artist_credit": "Recording Artist Credit", "artist_id": "00000000-0000-0000-0000-000000000001", "artist_sort": "Recording Artist, The", "artists": ["Recording Artist"], "artists_credit": ["Recording Artist Credit"], "artists_ids": ["00000000-0000-0000-0000-000000000001"], "artists_sort": ["Recording Artist, The"], "bpm": None, "composer_sort": None, "composers": None, "composers_ids": [], "data_source": "MusicBrainz", "data_url": "https://musicbrainz.org/recording/00000000-0000-0000-0000-000000001001", "disctitle": "Medium", "genres": None, "index": 1, "initial_key": None, "isrc": None, "length": 0.36, "lyricists": None, "lyricists_ids": [], "mb_workid": None, "media": "Digital Media", "medium": 1, "medium_index": 1, "medium_total": 1, "release_track_id": "00000000-0000-0000-0000-000000010001", "remixers": None, "remixers_ids": [], "title": "Recording", "track_alt": "A1", "track_id": "00000000-0000-0000-0000-000000001001", "trackdisambig": None, "work": None, "work_disambig": None, } ], "va": False, "year": 2020, } def test_detect_various_artists(self, mb): release = release_factory( artist_credit=[ artist_credit_factory(artist__id=musicbrainz.VARIOUS_ARTISTS_ID) ] ) assert mb.album_info(release).va def test_missing_language(self, mb): release = release_factory(text_representation__language=None) assert mb.album_info(release).language is None @pytest.mark.parametrize( "plugin_config, expected_genres", [ _p({"genres": False}, None, id="genres disabled"), _p({"genres": True, "genres_tag": "genre"}, ["Genre"], id="use genres"), _p({"genres": True, "genres_tag": "tag"}, ["Tag"], id="use tags"), ], ) # fmt: skip def test_genres(self, mb, expected_genres): assert mb.album_info(release_factory()).genres == expected_genres @pytest.mark.parametrize( "plugin_config", [_p({"aliases_as_credits": True})] ) def test_parse_aliased_titles(self, config, mb: MusicBrainzPlugin): release = release_factory() config["import"]["languages"] = ["en"] d = mb.album_info(release) assert d.album == "Album Alias en" assert d.release_group_title == "Release Group Alias en" assert d.tracks[0].title == "Recording Alias en" album_artist = "Artist Alias en" assert d.artist == album_artist assert d.artists == [album_artist] # There is no artist credit specific alias assert d.artist_credit == album_artist assert d.artists_credit == [album_artist] album_artist_sort = "Artist Alias en, The" assert d.artist_sort == album_artist_sort assert d.artists_sort == [album_artist_sort] first_track = d.tracks[0] track_artist = "Recording Artist Alias en" assert first_track.artist == track_artist assert first_track.artists == [track_artist] # There is no artist credit specific alias assert first_track.artist_credit == track_artist assert first_track.artists_credit == [track_artist] track_artist_sort = "Recording Artist Alias en, The" assert first_track.artist_sort == track_artist_sort assert first_track.artists_sort == [track_artist_sort] @pytest.mark.parametrize( "plugin_config, expected_artist_credit", [ _p( {"aliases_as_credits": False}, { "track_artist_credit": "Recording Artist Credit", "track_artists_credit": ["Recording Artist Credit"], "artist_credit": "Artist Credit", "artists_credit": ["Artist Credit"], }, id="no aliases", ), _p( {"aliases_as_credits": True}, { "artist_credit": "Artist Alias en", "artists_credit": ["Artist Alias en"], "track_artist_credit": "Recording Artist Alias en", "track_artists_credit": ["Recording Artist Alias en"], }, id="aliases", ), ], ) def test_aliases_as_credits( self, config, mb: MusicBrainzPlugin, expected_artist_credit ): config["import"]["languages"] = ["en"] release = release_factory() d = mb.album_info(release) assert d.artist_credit == expected_artist_credit["artist_credit"] assert d.artists_credit == expected_artist_credit["artists_credit"] first_track = d.tracks[0] assert ( first_track.artist_credit == expected_artist_credit["track_artist_credit"] ) assert ( first_track.artists_credit == expected_artist_credit["track_artists_credit"] ) def test_ensure_complete_recordings(self, monkeypatch, mb): titles = ["Recording", "Other Recording"] initial_recordings = [ recording_factory(index=idx, title=t) for idx, t in enumerate(titles) ] complete_recordings = [ {**r, "url_relations": [url_relation_factory()]} for r in initial_recordings ] monkeypatch.setattr("beetsplug.musicbrainz.BROWSE_CHUNKSIZE", 1) monkeypatch.setattr("beetsplug.musicbrainz.BROWSE_MAXTRACKS", 1) monkeypatch.setattr( mb.mb_api, "browse_recordings", lambda offset=0, **__: [complete_recordings[offset]], ) release = release_factory( media__0__tracks=[ track_factory(recording=r) for r in initial_recordings ] ) mb._ensure_complete_recordings(release) new_recordings = [ t["recording"] for m in release["media"] for t in m["tracks"] ] assert new_recordings == complete_recordings def test_album_info_browse_recordings_prefers_alias_over_track_title( self, config, monkeypatch, mb ): config["import"]["languages"] = ["en"] recording = recording_factory( title="Recording Title", aliases=[alias_factory(type="Recording name", locale="en")], ) browsed_recording = { **recording, "url_relations": [url_relation_factory()], } monkeypatch.setattr("beetsplug.musicbrainz.BROWSE_CHUNKSIZE", 1) monkeypatch.setattr("beetsplug.musicbrainz.BROWSE_MAXTRACKS", 0) monkeypatch.setattr( mb.mb_api, "browse_recordings", lambda offset=0, **__: [browsed_recording] if offset == 0 else [], ) release = release_factory( media__0__tracks=[ track_factory(recording=recording, title="Track Title") ] ) album = mb.album_info(release) assert album.tracks[0].title == "Alias en" class TestPseudoRelease(MusicBrainzPluginTestMixin): ACTUAL_RELEASE = release_factory(index=1, country="US") PSEUDO_WITHOUT_LINKS = release_factory( index=2, status="Pseudo-Release", country=None ) PSEUDO_INVALID_LINK = release_factory( index=3, status="Pseudo-Release", country=None, release_relations=[ { "type": "remaster", "direction": "backward", "release": {"id": "d2a6f856-b553-40a0-ac54-a321e8e2da01"}, } ], ) PSEUDO_VALID_LINK = release_factory( index=4, status="Pseudo-Release", country=None, release_relations=[ { "type": "transl-tracklisting", "direction": "backward", "release": {"id": ACTUAL_RELEASE["id"]}, } ], ) @pytest.fixture(autouse=True) def setup_album_lookup(self, monkeypatch, mb): releases = [ self.ACTUAL_RELEASE, self.PSEUDO_WITHOUT_LINKS, self.PSEUDO_INVALID_LINK, self.PSEUDO_VALID_LINK, ] release_by_id = {r["id"]: r for r in releases} monkeypatch.setattr( mb.mb_api, "get_release", lambda id_: release_by_id[id_] ) @pytest.mark.parametrize( "release_id, expected_country", [ _p(ACTUAL_RELEASE["id"], "US", id="actual release"), _p(PSEUDO_WITHOUT_LINKS["id"], None, id="pseudo without links"), _p(PSEUDO_INVALID_LINK["id"], None, id="pseudo with invalid link"), _p(PSEUDO_VALID_LINK["id"], "US", id="pseudo with valid link"), ], ) def test_follow_pseudo_release(self, mb, release_id, expected_country): album = mb.album_for_id(release_id) assert album assert album.country == expected_country class TestMusicBrainzPlugin(MusicBrainzPluginTestMixin): mbid = "d2a6f856-b553-40a0-ac54-a321e8e2da99" RECORDING: ClassVar[mb.Recording] = recording_factory() @pytest.mark.parametrize( "plugin_config,va_likely,expected_additional_criteria", [ _p({}, False, {"artist": "Artist "}, id="default"), _p( {}, True, {"arid": "89ad4ac3-39f7-470e-963a-56509c546377"}, id="va likely", ), _p( {"extra_tags": ["label", "catalognum"]}, False, {"artist": "Artist ", "label": "abc", "catno": "ABC123"}, id="value-based extra_tags", ), _p( {"extra_tags": ["alias", "tracks"]}, False, {"artist": "Artist ", "alias": " Album", "tracks": "3"}, id="non-value-based extra_tags", ), ], ) def test_get_album_criteria( self, mb, va_likely, expected_additional_criteria ): items = [ Item(catalognum="ABC 123", label="abc"), Item(catalognum="ABC 123", label="abc"), Item(catalognum="ABC 123", label="def"), ] assert mb.get_album_criteria(items, "Artist ", " Album", va_likely) == { "release": " Album", **expected_additional_criteria, } def test_item_candidates(self, monkeypatch, mb): monkeypatch.setattr( "beetsplug._utils.musicbrainz.MusicBrainzAPI.get_json", lambda *_, **__: {"recordings": [self.RECORDING]}, ) monkeypatch.setattr( "beetsplug._utils.musicbrainz.MusicBrainzAPI.get_recording", lambda *_, **__: self.RECORDING, ) candidates = list(mb.item_candidates(Item(), "hello", "there")) assert len(candidates) == 1 assert candidates[0].track_id == self.RECORDING["id"] def test_candidates(self, monkeypatch, mb): monkeypatch.setattr( "beetsplug._utils.musicbrainz.MusicBrainzAPI.get_json", lambda *_, **__: {"releases": [{"id": self.mbid}]}, ) monkeypatch.setattr( "beetsplug._utils.musicbrainz.MusicBrainzAPI.get_release", lambda *_, **__: release_factory( id=self.mbid, media=[medium_factory()] ), ) candidates = list(mb.candidates([], "hello", "there", False)) assert len(candidates) == 1 assert ( candidates[0].tracks[0].track_id == "00000000-0000-0000-0000-000000001001" ) assert candidates[0].album == "Album" def test_import_handles_404_gracefully(self, mb, requests_mock): id_ = uuid.uuid4() response = requests.Response() response.status_code = 404 requests_mock.get( f"/ws/2/release/{id_}", exc=requests.exceptions.HTTPError(response=response), ) res = mb.album_for_id(str(id_)) assert res is None def test_import_propagates_non_404_errors(self, mb): class DummyResponse: status_code = 500 error = requests.exceptions.HTTPError(response=DummyResponse()) def raise_error(*args, **kwargs): raise error # Simulate mb.mb_api.get_release raising a non-404 HTTP error mb.mb_api.get_release = raise_error with pytest.raises(requests.exceptions.HTTPError) as excinfo: mb.album_for_id(str(uuid.uuid4())) # Ensure the exact error is propagated, not swallowed assert excinfo.value is error @pytest.mark.parametrize( "input_,expected", [ ("??-??-??", (None, None, None)), ("??-01-??", (None, 1, None)), ("??-??-02", (None, None, 2)), ("??-01-02", (None, 1, 2)), ("2010-??-01", (2010, None, 1)), ("2010-01-not_an_int", (2010, 1, None)), ("2010", (2010, None, None)), ("2010-01", (2010, 1, None)), ("2010-01-02", (2010, 1, 2)), ], ) def test_get_date(self, input_, expected): assert musicbrainz._get_date(input_) == expected beetbox-beets-00724b7/test/plugins/test_bpd.py0000664000175000017500000011670615253035401020704 0ustar pieterpieter"""Tests for BPD's implementation of the MPD protocol.""" import asyncio import multiprocessing as mp import os import socket import tempfile import threading import time import unittest from contextlib import contextmanager from typing import ClassVar from unittest.mock import MagicMock, patch import confuse import pytest import yaml from beets.test.helper import PluginTestCase bpd = pytest.importorskip("beetsplug.bpd", exc_type=ImportError) if hasattr(mp, "set_start_method"): try: mp.set_start_method("fork", force=True) except RuntimeError: # Already set, which is fine pass class CommandParseTest(unittest.TestCase): def test_no_args(self): s = r"command" c = bpd.Command(s) assert c.name == "command" assert c.args == [] def test_one_unquoted_arg(self): s = r"command hello" c = bpd.Command(s) assert c.name == "command" assert c.args == ["hello"] def test_two_unquoted_args(self): s = r"command hello there" c = bpd.Command(s) assert c.name == "command" assert c.args == ["hello", "there"] def test_one_quoted_arg(self): s = r'command "hello there"' c = bpd.Command(s) assert c.name == "command" assert c.args == ["hello there"] def test_heterogenous_args(self): s = r'command "hello there" sir' c = bpd.Command(s) assert c.name == "command" assert c.args == ["hello there", "sir"] def test_quote_in_arg(self): s = r'command "hello \" there"' c = bpd.Command(s) assert c.args == ['hello " there'] def test_backslash_in_arg(self): s = r'command "hello \\ there"' c = bpd.Command(s) assert c.args == ["hello \\ there"] class MPCResponse: def __init__(self, raw_response): body = b"\n".join(raw_response.split(b"\n")[:-2]).decode("utf-8") self.data = self._parse_body(body) status = raw_response.split(b"\n")[-2].decode("utf-8") self.ok, self.err_data = self._parse_status(status) def _parse_status(self, status): """Parses the first response line, which contains the status.""" if status.startswith(("OK", "list_OK")): return True, None if status.startswith("ACK"): code, rest = status[5:].split("@", 1) pos, rest = rest.split("]", 1) cmd, rest = rest[2:].split("}") return False, (int(code), int(pos), cmd, rest[1:]) raise RuntimeError(f"Unexpected status: {status!r}") def _parse_body(self, body): """Messages are generally in the format "header: content". Convert them into a dict, storing the values for repeated headers as lists of strings, and non-repeated ones as string. """ data = {} repeated_headers = set() for line in body.split("\n"): if not line: continue if ":" not in line: raise RuntimeError(f"Unexpected line: {line!r}") header, content = line.split(":", 1) content = content.lstrip() if header in repeated_headers: data[header].append(content) elif header in data: data[header] = [data[header], content] repeated_headers.add(header) else: data[header] = content return data class MPCClient: def __init__(self, sock, do_hello=True): self.sock = sock self.buf = b"" if do_hello: hello = self.get_response() if not hello.ok: raise RuntimeError("Bad hello") def get_response(self, force_multi=None): """Wait for a full server response and wrap it in a helper class. If the request was a batch request then this will return a list of `MPCResponse`s, one for each processed subcommand. """ response = b"" responses = [] while True: line = self.readline() response += line if line.startswith((b"OK", b"ACK")): if force_multi or any(responses): if line.startswith(b"ACK"): responses.append(MPCResponse(response)) n_remaining = force_multi - len(responses) responses.extend([None] * n_remaining) return responses return MPCResponse(response) if line.startswith(b"list_OK"): responses.append(MPCResponse(response)) response = b"" elif not line: raise RuntimeError(f"Unexpected response: {line!r}") def serialise_command(self, command, *args): cmd = [command.encode("utf-8")] for arg in [a.encode("utf-8") for a in args]: if b" " in arg: cmd.append(b'"' + arg + b'"') else: cmd.append(arg) return b" ".join(cmd) + b"\n" def send_command(self, command, *args): request = self.serialise_command(command, *args) self.sock.sendall(request) return self.get_response() def send_commands(self, *commands): """Use MPD command batching to send multiple commands at once. Each item of commands is a tuple containing a command followed by any arguments. """ requests = [] for command_and_args in commands: command = command_and_args[0] args = command_and_args[1:] requests.append(self.serialise_command(command, *args)) requests.insert(0, b"command_list_ok_begin\n") requests.append(b"command_list_end\n") request = b"".join(requests) self.sock.sendall(request) return self.get_response(force_multi=len(commands)) def readline(self, terminator=b"\n", bufsize=1024): """Reads a line of data from the socket.""" while True: if terminator in self.buf: line, self.buf = self.buf.split(terminator, 1) line += terminator return line self.sock.settimeout(1) data = self.sock.recv(bufsize) if data: self.buf += data else: line = self.buf self.buf = b"" return line def implements(commands, fail=False): def _test(self): with self.run_bpd() as client: response = client.send_command("commands") self._assert_ok(response) implemented = response.data["command"] assert commands.intersection(implemented) == commands return unittest.expectedFailure(_test) if fail else _test class MemoryStreamWriter: """Capture writes and optionally hold them at the drain boundary.""" def __init__(self, block_drain=False): self.data = bytearray() self.drain_started = asyncio.Event() self.can_drain = asyncio.Event() if not block_drain: self.can_drain.set() def get_extra_info(self, name): return ("localhost", 6600) if name == "peername" else None def write(self, data): self.data.extend(data) async def drain(self): self.drain_started.set() await self.can_drain.wait() class AsyncServerTest(unittest.TestCase): def test_dispatch_events_sends_one_notification_at_a_time(self): async def exercise(): server = bpd.BaseServer("localhost", 0, None, 0, MagicMock()) writer = MemoryStreamWriter(block_drain=True) conn = bpd.MPDConnection(server, asyncio.StreamReader(), writer) conn.notifications.add("player") conn.idle_subscriptions.add("player") server.connect(conn) server.dispatch_events() await writer.drain_started.wait() server.dispatch_events() await asyncio.sleep(0) tasks = tuple(server._notification_tasks.values()) writer.can_drain.set() await asyncio.gather(*tasks) assert bytes(writer.data) == b"changed: player\nOK\n" asyncio.run(exercise()) def test_dispatch_events_sends_event_queued_while_task_finishes(self): async def exercise(): server = bpd.BaseServer("localhost", 0, None, 0, MagicMock()) writer = MemoryStreamWriter() conn = bpd.MPDConnection(server, asyncio.StreamReader(), writer) conn.idle_subscriptions.add("player") server.connect(conn) server.dispatch_events() await asyncio.sleep(0) conn.notify("player") server.dispatch_events() await asyncio.sleep(0) await asyncio.gather(*server._notification_tasks.values()) assert bytes(writer.data) == b"changed: player\nOK\n" asyncio.run(exercise()) def test_idle_error_disconnects_client(self): async def exercise(): server = bpd.BaseServer("localhost", 0, None, 0, MagicMock()) reader = asyncio.StreamReader() reader.feed_data(b"idle\nnotacommand\n") reader.feed_eof() conn = bpd.MPDConnection(server, reader, MemoryStreamWriter()) await conn.run() assert conn not in server.connections asyncio.run(exercise()) asyncio_start_server = asyncio.start_server @patch("beetsplug.bpd.asyncio.start_server") def start_server(args, assigned_port, start_server_patch): """Start the bpd server, writing the port to `assigned_port`.""" async def start_server_wrap(callback, host, port, **kwargs): """Start an asyncio server and report its assigned port.""" # `asyncio.start_server` has previously been saved because this # function replaces it at its original location. server = await asyncio_start_server(callback, host, port, **kwargs) # Read the port assigned by the OS. assigned_port.put_nowait(server.sockets[0].getsockname()[1]) return server start_server_patch.side_effect = start_server_wrap import beets.ui beets.ui.main(args) class BPDTestHelper(PluginTestCase): db_on_disk = True plugin = "bpd" def setUp(self): super().setUp() self.item1 = self.add_item( title="Track One Title", track=1, album="Album Title", artist="Artist Name", ) self.item2 = self.add_item( title="Track Two Title", track=2, album="Album Title", artist="Artist Name", ) self.lib.add_album([self.item1, self.item2]) @contextmanager def run_bpd( self, host="localhost", password=None, do_hello=True, second_client=False, ): """Runs BPD in another process, configured with the same library database as we created in the setUp method. Exposes a client that is connected to the server, and kills the server at the end. """ # Create a config file: config = { "pluginpath": [str(self.temp_path)], "plugins": "bpd", # use port 0 to let the OS choose a free port "bpd": {"host": host, "port": 0, "control_port": 0}, } if password: config["bpd"]["password"] = password config_file = tempfile.NamedTemporaryFile( mode="wb", dir=str(self.temp_path), suffix=".yaml", delete=False ) config_file.write( yaml.dump(config, Dumper=confuse.Dumper, encoding="utf-8") ) config_file.close() # Fork and launch BPD in the new process: assigned_port = mp.Queue(2) # 2 slots, `control_port` and `port` server = mp.Process( target=start_server, args=( [ "--library", self.config["library"].as_filename(), "--directory", str(self.lib_path), "--config", os.fsdecode(config_file.name), "bpd", ], assigned_port, ), ) server.start() try: assigned_port.get(timeout=1) # skip control_port port = assigned_port.get(timeout=0.5) # read port sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((host, port)) if second_client: sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock2.connect((host, port)) yield ( MPCClient(sock, do_hello), MPCClient(sock2, do_hello), ) finally: sock2.close() else: yield MPCClient(sock, do_hello) finally: sock.close() finally: server.terminate() server.join(timeout=2) # give coverage time to write data if server.is_alive(): server.kill() # force kill if still stuck (SIGKILL on POSIX) server.join(timeout=2) def _assert_ok(self, *responses): for response in responses: assert response is not None assert response.ok, f"Response failed: {response.err_data}" def _assert_failed(self, response, code, pos=None): """Check that a command failed with a specific error code. If this is a list of responses, first check all preceding commands were OK. """ if pos is not None: previous_commands = response[0:pos] self._assert_ok(*previous_commands) response = response[pos] assert not response.ok if pos is not None: assert pos == response.err_data[1] if code is not None: assert code == response.err_data[0] def _bpd_add(self, client, *items, **kwargs): """Add the given item to the BPD playlist or queue.""" paths = [ os.fsdecode(item.destination(relative_to_libdir=True)) for item in items ] playlist = kwargs.get("playlist") if playlist: commands = [("playlistadd", playlist, path) for path in paths] else: commands = [("add", path) for path in paths] responses = client.send_commands(*commands) self._assert_ok(*responses) class BPDTest(BPDTestHelper): def test_server_hello(self): with self.run_bpd(do_hello=False) as client: assert client.readline() == b"OK MPD 0.16.0\n" def test_unknown_cmd(self): with self.run_bpd() as client: response = client.send_command("notacommand") self._assert_failed(response, bpd.ERROR_UNKNOWN) def test_unexpected_argument(self): with self.run_bpd() as client: response = client.send_command("ping", "extra argument") self._assert_failed(response, bpd.ERROR_ARG) def test_missing_argument(self): with self.run_bpd() as client: response = client.send_command("add") self._assert_failed(response, bpd.ERROR_ARG) def test_system_error(self): with self.run_bpd() as client: response = client.send_command("crash") self._assert_failed(response, bpd.ERROR_SYSTEM) def test_empty_request(self): with self.run_bpd() as client: response = client.send_command("") self._assert_failed(response, bpd.ERROR_UNKNOWN) class BPDQueryTest(BPDTestHelper): test_implements_query = implements({"clearerror"}) def test_cmd_currentsong(self): with self.run_bpd() as client: self._bpd_add(client, self.item1) responses = client.send_commands( ("play",), ("currentsong",), ("stop",), ("currentsong",) ) self._assert_ok(*responses) assert "1" == responses[1].data["Id"] assert "Id" not in responses[3].data def test_cmd_currentsong_tagtypes(self): with self.run_bpd() as client: self._bpd_add(client, self.item1) responses = client.send_commands(("play",), ("currentsong",)) self._assert_ok(*responses) assert BPDConnectionTest.TAGTYPES.union(BPDQueueTest.METADATA) == set( responses[1].data.keys() ) def test_cmd_status(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("status",), ("play",), ("status",) ) self._assert_ok(*responses) fields_not_playing = { "repeat", "random", "single", "consume", "playlist", "playlistlength", "mixrampdb", "state", "volume", } assert fields_not_playing == set(responses[0].data.keys()) fields_playing = fields_not_playing | { "song", "songid", "time", "elapsed", "bitrate", "duration", "audio", "nextsong", "nextsongid", } assert fields_playing == set(responses[2].data.keys()) def test_cmd_stats(self): with self.run_bpd() as client: response = client.send_command("stats") self._assert_ok(response) details = { "artists", "albums", "songs", "uptime", "db_playtime", "db_update", "playtime", } assert details == set(response.data.keys()) def test_cmd_idle(self): def _toggle(c): for _ in range(3): rs = c.send_commands(("play",), ("pause",)) # time.sleep(0.05) # uncomment if test is flaky if any(not r.ok for r in rs): raise RuntimeError("Toggler failed") with self.run_bpd(second_client=True) as (client, client2): self._bpd_add(client, self.item1, self.item2) toggler = threading.Thread(target=_toggle, args=(client2,)) toggler.start() # Idling will hang until the toggler thread changes the play state. # Since the client sockets have a 1s timeout set at worst this will # raise a socket.timeout and fail the test if the toggler thread # manages to finish before the idle command is sent here. response = client.send_command("idle", "player") toggler.join() self._assert_ok(response) def test_cmd_idle_with_pending(self): with self.run_bpd(second_client=True) as (client, client2): response1 = client.send_command("random", "1") response2 = client2.send_command("idle") self._assert_ok(response1, response2) assert "options" == response2.data["changed"] def test_cmd_noidle(self): with self.run_bpd() as client: # Manually send a command without reading a response. request = client.serialise_command("idle") client.sock.sendall(request) time.sleep(0.01) response = client.send_command("noidle") self._assert_ok(response) def test_cmd_noidle_when_not_idle(self): with self.run_bpd() as client: # Manually send a command without reading a response. request = client.serialise_command("noidle") client.sock.sendall(request) response = client.send_command("notacommand") self._assert_failed(response, bpd.ERROR_UNKNOWN) class BPDPlaybackTest(BPDTestHelper): test_implements_playback = implements({"random"}) def test_cmd_consume(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("consume", "0"), ("playlistinfo",), ("next",), ("playlistinfo",), ("consume", "1"), ("playlistinfo",), ("play", "0"), ("next",), ("playlistinfo",), ("status",), ) self._assert_ok(*responses) assert responses[1].data["Id"] == responses[3].data["Id"] assert ["1", "2"] == responses[5].data["Id"] assert "2" == responses[8].data["Id"] assert "1" == responses[9].data["consume"] assert "play" == responses[9].data["state"] def test_cmd_consume_in_reverse(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("consume", "1"), ("play", "1"), ("playlistinfo",), ("previous",), ("playlistinfo",), ("status",), ) self._assert_ok(*responses) assert ["1", "2"] == responses[2].data["Id"] assert "1" == responses[4].data["Id"] assert "play" == responses[5].data["state"] def test_cmd_single(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("status",), ("single", "1"), ("play",), ("status",), ("next",), ("status",), ) self._assert_ok(*responses) assert "0" == responses[0].data["single"] assert "1" == responses[3].data["single"] assert "play" == responses[3].data["state"] assert "stop" == responses[5].data["state"] def test_cmd_repeat(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("repeat", "1"), ("play",), ("currentsong",), ("next",), ("currentsong",), ("next",), ("currentsong",), ) self._assert_ok(*responses) assert "1" == responses[2].data["Id"] assert "2" == responses[4].data["Id"] assert "1" == responses[6].data["Id"] def test_cmd_repeat_with_single(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("repeat", "1"), ("single", "1"), ("play",), ("currentsong",), ("next",), ("status",), ("currentsong",), ) self._assert_ok(*responses) assert "1" == responses[3].data["Id"] assert "play" == responses[5].data["state"] assert "1" == responses[6].data["Id"] def test_cmd_repeat_in_reverse(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("repeat", "1"), ("play",), ("currentsong",), ("previous",), ("currentsong",), ) self._assert_ok(*responses) assert "1" == responses[2].data["Id"] assert "2" == responses[4].data["Id"] def test_cmd_repeat_with_single_in_reverse(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("repeat", "1"), ("single", "1"), ("play",), ("currentsong",), ("previous",), ("status",), ("currentsong",), ) self._assert_ok(*responses) assert "1" == responses[3].data["Id"] assert "play" == responses[5].data["state"] assert "1" == responses[6].data["Id"] def test_cmd_crossfade(self): with self.run_bpd() as client: responses = client.send_commands( ("status",), ("crossfade", "123"), ("status",), ("crossfade", "-2"), ) response = client.send_command("crossfade", "0.5") self._assert_failed(responses, bpd.ERROR_ARG, pos=3) self._assert_failed(response, bpd.ERROR_ARG) assert "xfade" not in responses[0].data assert 123 == pytest.approx(int(responses[2].data["xfade"])) def test_cmd_mixrampdb(self): with self.run_bpd() as client: responses = client.send_commands(("mixrampdb", "-17"), ("status",)) self._assert_ok(*responses) assert -17 == pytest.approx(float(responses[1].data["mixrampdb"])) def test_cmd_mixrampdelay(self): with self.run_bpd() as client: responses = client.send_commands( ("mixrampdelay", "2"), ("status",), ("mixrampdelay", "nan"), ("status",), ("mixrampdelay", "-2"), ) self._assert_failed(responses, bpd.ERROR_ARG, pos=4) assert 2 == pytest.approx(float(responses[1].data["mixrampdelay"])) assert "mixrampdelay" not in responses[3].data def test_cmd_setvol(self): with self.run_bpd() as client: responses = client.send_commands( ("setvol", "67"), ("status",), ("setvol", "32"), ("status",), ("setvol", "101"), ) self._assert_failed(responses, bpd.ERROR_ARG, pos=4) assert "67" == responses[1].data["volume"] assert "32" == responses[3].data["volume"] def test_cmd_volume(self): with self.run_bpd() as client: responses = client.send_commands( ("setvol", "10"), ("volume", "5"), ("volume", "-2"), ("status",) ) self._assert_ok(*responses) assert "13" == responses[3].data["volume"] def test_cmd_replay_gain(self): with self.run_bpd() as client: responses = client.send_commands( ("replay_gain_mode", "track"), ("replay_gain_status",), ("replay_gain_mode", "notanoption"), ) self._assert_failed(responses, bpd.ERROR_ARG, pos=2) assert "track" == responses[1].data["replay_gain_mode"] class BPDControlTest(BPDTestHelper): test_implements_control = implements( {"seek", "seekid", "seekcur"}, fail=True ) def test_cmd_play(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("status",), ("play",), ("status",), ("play", "1"), ("currentsong",), ) self._assert_ok(*responses) assert "stop" == responses[0].data["state"] assert "play" == responses[2].data["state"] assert "2" == responses[4].data["Id"] def test_cmd_playid(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("playid", "2"), ("currentsong",), ("clear",) ) self._bpd_add(client, self.item2, self.item1) responses.extend( client.send_commands(("playid", "2"), ("currentsong",)) ) self._assert_ok(*responses) assert "2" == responses[1].data["Id"] assert "2" == responses[4].data["Id"] def test_cmd_pause(self): with self.run_bpd() as client: self._bpd_add(client, self.item1) responses = client.send_commands( ("play",), ("pause",), ("status",), ("currentsong",) ) self._assert_ok(*responses) assert "pause" == responses[2].data["state"] assert "1" == responses[3].data["Id"] def test_cmd_stop(self): with self.run_bpd() as client: self._bpd_add(client, self.item1) responses = client.send_commands( ("play",), ("stop",), ("status",), ("currentsong",) ) self._assert_ok(*responses) assert "stop" == responses[2].data["state"] assert "Id" not in responses[3].data def test_cmd_next(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("play",), ("currentsong",), ("next",), ("currentsong",), ("next",), ("status",), ) self._assert_ok(*responses) assert "1" == responses[1].data["Id"] assert "2" == responses[3].data["Id"] assert "stop" == responses[5].data["state"] def test_cmd_previous(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("play", "1"), ("currentsong",), ("previous",), ("currentsong",), ("previous",), ("status",), ("currentsong",), ) self._assert_ok(*responses) assert "2" == responses[1].data["Id"] assert "1" == responses[3].data["Id"] assert "play" == responses[5].data["state"] assert "1" == responses[6].data["Id"] class BPDQueueTest(BPDTestHelper): test_implements_queue = implements( { "addid", "clear", "delete", "deleteid", "move", "moveid", "playlist", "playlistfind", "playlistsearch", "plchanges", "plchangesposid", "prio", "prioid", "rangeid", "shuffle", "swap", "swapid", "addtagid", "cleartagid", }, fail=True, ) METADATA: ClassVar[set[str]] = {"Pos", "Time", "Id", "file", "duration"} def test_cmd_add(self): with self.run_bpd() as client: self._bpd_add(client, self.item1) def test_cmd_playlistinfo(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("playlistinfo",), ("playlistinfo", "0"), ("playlistinfo", "0:2"), ("playlistinfo", "200"), ) self._assert_failed(responses, bpd.ERROR_ARG, pos=3) assert "1" == responses[1].data["Id"] assert ["1", "2"] == responses[2].data["Id"] def test_cmd_playlistinfo_tagtypes(self): with self.run_bpd() as client: self._bpd_add(client, self.item1) response = client.send_command("playlistinfo", "0") self._assert_ok(response) assert BPDConnectionTest.TAGTYPES.union(BPDQueueTest.METADATA) == set( response.data.keys() ) def test_cmd_playlistid(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ("playlistid", "2"), ("playlistid",) ) self._assert_ok(*responses) assert "Track Two Title" == responses[0].data["Title"] assert ["1", "2"] == responses[1].data["Track"] class BPDPlaylistsTest(BPDTestHelper): test_implements_playlists = implements({"playlistadd"}) def test_cmd_listplaylist(self): with self.run_bpd() as client: response = client.send_command("listplaylist", "anything") self._assert_failed(response, bpd.ERROR_NO_EXIST) def test_cmd_listplaylistinfo(self): with self.run_bpd() as client: response = client.send_command("listplaylistinfo", "anything") self._assert_failed(response, bpd.ERROR_NO_EXIST) def test_cmd_listplaylists(self): with self.run_bpd() as client: response = client.send_command("listplaylists") self._assert_failed(response, bpd.ERROR_UNKNOWN) def test_cmd_load(self): with self.run_bpd() as client: response = client.send_command("load", "anything") self._assert_failed(response, bpd.ERROR_NO_EXIST) @unittest.expectedFailure def test_cmd_playlistadd(self): with self.run_bpd() as client: self._bpd_add(client, self.item1, playlist="anything") def test_cmd_playlistclear(self): with self.run_bpd() as client: response = client.send_command("playlistclear", "anything") self._assert_failed(response, bpd.ERROR_UNKNOWN) def test_cmd_playlistdelete(self): with self.run_bpd() as client: response = client.send_command("playlistdelete", "anything", "0") self._assert_failed(response, bpd.ERROR_UNKNOWN) def test_cmd_playlistmove(self): with self.run_bpd() as client: response = client.send_command("playlistmove", "anything", "0", "1") self._assert_failed(response, bpd.ERROR_UNKNOWN) def test_cmd_rename(self): with self.run_bpd() as client: response = client.send_command("rename", "anything", "newname") self._assert_failed(response, bpd.ERROR_UNKNOWN) def test_cmd_rm(self): with self.run_bpd() as client: response = client.send_command("rm", "anything") self._assert_failed(response, bpd.ERROR_UNKNOWN) def test_cmd_save(self): with self.run_bpd() as client: self._bpd_add(client, self.item1) response = client.send_command("save", "newplaylist") self._assert_failed(response, bpd.ERROR_UNKNOWN) class BPDDatabaseTest(BPDTestHelper): test_implements_database = implements( { "albumart", "find", "findadd", "listall", "listallinfo", "listfiles", "readcomments", "searchadd", "searchaddpl", "update", "rescan", }, fail=True, ) def test_cmd_search(self): with self.run_bpd() as client: response = client.send_command("search", "track", "1") self._assert_ok(response) assert self.item1.title == response.data["Title"] def test_cmd_search_any(self): with self.run_bpd() as client: response = client.send_command("search", "any", "1") self._assert_ok(response) assert self.item1.title == response.data["Title"] def test_cmd_list(self): with self.run_bpd() as client: responses = client.send_commands( ("list", "album"), ("list", "track"), ("list", "album", "artist", "Artist Name", "track"), ) self._assert_failed(responses, bpd.ERROR_ARG, pos=2) assert "Album Title" == responses[0].data["Album"] assert ["1", "2"] == responses[1].data["Track"] def test_cmd_list_three_arg_form(self): with self.run_bpd() as client: responses = client.send_commands( ("list", "album", "artist", "Artist Name"), ("list", "album", "Artist Name"), ("list", "track", "Artist Name"), ) self._assert_failed(responses, bpd.ERROR_ARG, pos=2) assert responses[0].data == responses[1].data def test_cmd_lsinfo(self): with self.run_bpd() as client: response1 = client.send_command("lsinfo") self._assert_ok(response1) response2 = client.send_command( "lsinfo", response1.data["directory"] ) self._assert_ok(response2) response3 = client.send_command( "lsinfo", response2.data["directory"] ) self._assert_ok(response3) assert self.item1.title in response3.data["Title"] def test_cmd_count(self): with self.run_bpd() as client: response = client.send_command("count", "track", "1") self._assert_ok(response) assert "1" == response.data["songs"] assert "0" == response.data["playtime"] class BPDMountsTest(BPDTestHelper): test_implements_mounts = implements( {"mount", "unmount", "listmounts", "listneighbors"}, fail=True ) class BPDStickerTest(BPDTestHelper): test_implements_stickers = implements({"sticker"}, fail=True) class BPDConnectionTest(BPDTestHelper): test_implements_connection = implements({"close", "kill"}) ALL_MPD_TAGTYPES: ClassVar[set[str]] = { "Artist", "ArtistSort", "Album", "AlbumSort", "AlbumArtist", "AlbumArtistSort", "Title", "Track", "Name", "Genre", "Date", "Composer", "Performer", "Comment", "Disc", "Label", "OriginalDate", "MUSICBRAINZ_ARTISTID", "MUSICBRAINZ_ALBUMID", "MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ_TRACKID", "MUSICBRAINZ_RELEASETRACKID", "MUSICBRAINZ_WORKID", } UNSUPPORTED_TAGTYPES: ClassVar[set[str]] = { "MUSICBRAINZ_WORKID", # not tracked by beets "Performer", # not tracked by beets "AlbumSort", # not tracked by beets "Name", # junk field for internet radio } TAGTYPES = ALL_MPD_TAGTYPES.difference(UNSUPPORTED_TAGTYPES) def test_cmd_password(self): with self.run_bpd(password="abc123") as client: response = client.send_command("status") self._assert_failed(response, bpd.ERROR_PERMISSION) response = client.send_command("password", "wrong") self._assert_failed(response, bpd.ERROR_PASSWORD) responses = client.send_commands( ("password", "abc123"), ("status",) ) self._assert_ok(*responses) def test_cmd_ping(self): with self.run_bpd() as client: response = client.send_command("ping") self._assert_ok(response) def test_cmd_tagtypes(self): with self.run_bpd() as client: response = client.send_command("tagtypes") self._assert_ok(response) assert self.TAGTYPES == set(response.data["tagtype"]) @unittest.expectedFailure def test_tagtypes_mask(self): with self.run_bpd() as client: response = client.send_command("tagtypes", "clear") self._assert_ok(response) class BPDPartitionTest(BPDTestHelper): test_implements_partitions = implements( {"partition", "listpartitions", "newpartition"}, fail=True ) class BPDDeviceTest(BPDTestHelper): test_implements_devices = implements( {"disableoutput", "enableoutput", "toggleoutput", "outputs"}, fail=True ) class BPDReflectionTest(BPDTestHelper): test_implements_reflection = implements( {"config", "commands", "notcommands", "urlhandlers"}, fail=True ) @patch( "beetsplug.bpd.gstplayer.GstPlayer.get_decoders", MagicMock(return_value={"default": ({"audio/mpeg"}, {"mp3"})}), ) def test_cmd_decoders(self): with self.run_bpd() as client: response = client.send_command("decoders") self._assert_ok(response) assert "default" == response.data["plugin"] assert "mp3" == response.data["suffix"] assert "audio/mpeg" == response.data["mime_type"] class BPDPeersTest(BPDTestHelper): test_implements_peers = implements( {"subscribe", "unsubscribe", "channels", "readmessages", "sendmessage"}, fail=True, ) beetbox-beets-00724b7/test/plugins/test_the.py0000664000175000017500000000430215253035401020703 0ustar pieterpieter"""Tests for the 'the' plugin""" from typing import ClassVar from beets import config from beets.test.helper import PluginTestHelper from beetsplug.the import FORMAT, PATTERN_A, PATTERN_THE, ThePlugin class TestThePlugin(PluginTestHelper): plugin: ClassVar[str] = "the" def test_unthe_with_default_patterns(self): assert ThePlugin().unthe("", PATTERN_THE) == "" assert ( ThePlugin().unthe("The Something", PATTERN_THE) == "Something, The" ) assert ThePlugin().unthe("The The", PATTERN_THE) == "The, The" assert ThePlugin().unthe("The The", PATTERN_THE) == "The, The" assert ThePlugin().unthe("The The X", PATTERN_THE) == "The X, The" assert ThePlugin().unthe("the The", PATTERN_THE) == "The, the" assert ( ThePlugin().unthe("Protected The", PATTERN_THE) == "Protected The" ) assert ThePlugin().unthe("A Boy", PATTERN_A) == "Boy, A" assert ThePlugin().unthe("a girl", PATTERN_A) == "girl, a" assert ThePlugin().unthe("An Apple", PATTERN_A) == "Apple, An" assert ThePlugin().unthe("An A Thing", PATTERN_A) == "A Thing, An" assert ThePlugin().unthe("the An Arse", PATTERN_A) == "the An Arse" assert ( ThePlugin().unthe("TET - Travailleur", PATTERN_THE) == "TET - Travailleur" ) def test_unthe_with_strip(self): config["the"]["strip"] = True assert ThePlugin().unthe("The Something", PATTERN_THE) == "Something" assert ThePlugin().unthe("An A", PATTERN_A) == "A" def test_template_function_with_defaults(self): ThePlugin().patterns = [PATTERN_THE, PATTERN_A] assert ThePlugin().the_template_func("The The") == "The, The" assert ThePlugin().the_template_func("An A") == "A, An" def test_custom_pattern(self): config["the"]["patterns"] = ["^test\\s"] config["the"]["format"] = FORMAT assert ThePlugin().the_template_func("test passed") == "passed, test" def test_custom_format(self): config["the"]["patterns"] = [PATTERN_THE, PATTERN_A] config["the"]["format"] = "{1} ({0})" assert ThePlugin().the_template_func("The A") == "The (A)" beetbox-beets-00724b7/test/plugins/test_badfiles.py0000664000175000017500000000341215253035401021675 0ustar pieterpieter"""Tests for the 'badfiles' plugin.""" from types import SimpleNamespace from unittest.mock import patch from beets import importer from beets.test.helper import ( AutotagImportTestCase, PluginMixin, PluginTestCase, TerminalImportMixin, ) from beetsplug.badfiles import BadFiles class BadFilesPluginTest(PluginTestCase): plugin = "badfiles" def test_quiet_import_skips_prompt(self): plugin = BadFiles() task = SimpleNamespace(_badfiles_checks_failed=[["bad: error"]]) self.config["import"]["quiet"] = True with patch("beetsplug.badfiles.ui.input_options", return_value="s"): result = plugin.on_import_task_before_choice(task, session=None) assert result is None def test_non_quiet_import_calls_prompt(self): plugin = BadFiles() task = SimpleNamespace(_badfiles_checks_failed=[["bad: error"]]) self.config["import"]["quiet"] = False with patch("beetsplug.badfiles.ui.input_options", return_value="s"): result = plugin.on_import_task_before_choice(task, session=None) assert result == importer.Action.SKIP class BadfilesOnImportTest( TerminalImportMixin, PluginMixin, AutotagImportTestCase ): plugin = "badfiles" def setUp(self): super().setUp() self.prepare_album_for_import(1) self.importer = self.setup_importer() def test_play_on_import(self): BadFiles() self.importer.add_choice("b") checker = self.temp_path / "checker" checker.write_text("#!/bin/sh\nexit 1") checker.chmod(0o755) with self.configure_plugin( {"check_on_import": True, "commands": {"mp3": str(checker)}} ): self.importer.run() assert not self.lib.items() beetbox-beets-00724b7/test/plugins/test_advancedrewrite.py0000664000175000017500000000760015253035401023276 0ustar pieterpieter"""Test the advancedrewrite plugin for various configurations.""" import pytest from beets.test.helper import PluginTestHelper from beets.ui import UserError class TestAdvancedRewritePlugin(PluginTestHelper): plugin = "advancedrewrite" preload_plugin = False def test_simple_rewrite_example(self): with self.configure_plugin( [{"artist ODD EYE CIRCLE": "ì�´ë‹¬ì�˜ 소녀 오드아ì�´ì�¨í�´"}] ): item = self.add_item( artist="ODD EYE CIRCLE", albumartist="ODD EYE CIRCLE" ) assert item.artist == "ì�´ë‹¬ì�˜ 소녀 오드아ì�´ì�¨í�´" def test_list_field(self): with self.configure_plugin([{"genres rock": "techno"}]): item = self.add_item(genres=["rock", "pop"]) assert item.genres == ["techno", "pop"] def test_advanced_rewrite_example(self): with self.configure_plugin( [ { "match": "mb_artistid:dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c year:..2022", # noqa: E501 "replacements": { "artist": "ì�´ë‹¬ì�˜ 소녀 오드아ì�´ì�¨í�´", "artist_sort": "LOONA / ODD EYE CIRCLE", }, } ] ): item_a = self.add_item( artist="ODD EYE CIRCLE", artist_sort="ODD EYE CIRCLE", mb_artistid="dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c", year=2017, ) item_b = self.add_item( artist="ODD EYE CIRCLE", artist_sort="ODD EYE CIRCLE", mb_artistid="dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c", year=2023, ) # Assert that all replacements were applied to item_a assert "ì�´ë‹¬ì�˜ 소녀 오드아ì�´ì�¨í�´" == item_a.artist assert "LOONA / ODD EYE CIRCLE" == item_a.artist_sort assert "LOONA / ODD EYE CIRCLE" == item_a.albumartist_sort # Assert that no replacements were applied to item_b assert "ODD EYE CIRCLE" == item_b.artist def test_advanced_rewrite_example_with_multi_valued_field(self): with self.configure_plugin( [ { "match": "artist:배유빈 feat. 김미현", "replacements": {"artists": ["유빈", "미미"]}, } ] ): item = self.add_item( artist="배유빈 feat. 김미현", artists=["배유빈", "김미현"] ) assert item.artists == ["유빈", "미미"] def test_fail_when_replacements_empty(self): with ( pytest.raises( UserError, match="Advanced rewrites must have at least one replacement", ), self.configure_plugin([{"match": "artist:A", "replacements": {}}]), ): pass def test_fail_when_rewriting_single_valued_field_with_list(self): with ( pytest.raises( UserError, match="Field artist is not a multi-valued field but a list was given: C, D", # noqa: E501 ), self.configure_plugin( [ { "match": "artist:'A & B'", "replacements": {"artist": ["C", "D"]}, } ] ), ): pass def test_combined_rewrite_example(self): with self.configure_plugin( [ {"artist A": "B"}, {"match": "album:'C'", "replacements": {"artist": "D"}}, ] ): item = self.add_item(artist="A", albumartist="A") assert item.artist == "B" item = self.add_item(artist="C", albumartist="C", album="C") assert item.artist == "D" beetbox-beets-00724b7/test/plugins/factories/0000775000175000017500000000000015253035401020472 5ustar pieterpieterbeetbox-beets-00724b7/test/plugins/factories/discogs.py0000664000175000017500000000073515253035401022504 0ustar pieterpieterimport factory class AudioTrackFactory(factory.DictFactory): type_ = "track" position = "1" title = "Track" duration = "" class IndexTrackFactory(factory.DictFactory): type_ = "index" title = "Index Track" position = "" duration = "" sub_tracks = factory.List([factory.SubFactory(AudioTrackFactory)]) class HeadingTrackFactory(factory.DictFactory): type_ = "heading" title = "Heading Track" position = "" duration = "" beetbox-beets-00724b7/test/plugins/factories/__init__.py0000664000175000017500000000000115253035401022572 0ustar pieterpieter beetbox-beets-00724b7/test/plugins/factories/musicbrainz.py0000664000175000017500000001751115253035401023377 0ustar pieterpieterimport factory from factory.fuzzy import FuzzyChoice from beetsplug._utils.musicbrainz import ArtistRelationType class _SortNameFactory(factory.DictFactory): name: str | factory.LazyAttribute sort_name = factory.LazyAttribute(lambda o: f"{o.name}, The") class _PeriodFactory(factory.DictFactory): begin: str | None = None end: str | None = None ended = factory.LazyAttribute(lambda obj: obj.end is not None) class _IdFactory(factory.DictFactory): class Params: id_base = 0 index = 1 id = factory.LazyAttribute( lambda o: f"00000000-0000-0000-0000-{o.id_base + o.index:012d}" ) class AliasFactory(_SortNameFactory, _PeriodFactory): class Params: prefix = "" suffix = "" locale = "en" name = factory.LazyAttribute( lambda o: ( f"{o.prefix + ' ' if o.prefix else ''}Alias {o.suffix or o.locale}" ) ) primary = True type = "Artist name" type_id = factory.LazyAttribute( lambda o: { "Artist name": "894afba6-2816-3c24-8072-eadb66bd04bc", "Label name": "3a1a0c48-d885-3b89-87b2-9e8a483c5675", "Legal name": "d4dcd0c0-b341-3612-a332-c0ce797b25cf", "Recording name": "5d564c8f-97de-3572-94bb-7f40ad661499", "Release group name": "156e24ca-8746-3cfc-99ae-0a867c765c67", "Release name": "df187855-059b-3514-9d5e-d240de0b4228", "Search hint": "abc2db8a-7386-354d-82f4-252c0213cbe4", }[o.type] ) class ArtistFactory(_SortNameFactory, _IdFactory): class Params: id_base = 0 country: str | None = None disambiguation = "" name = "Artist" type = "Person" type_id = "b6e035f4-3ce9-331c-97df-83397230b0df" aliases = factory.List( [ factory.SubFactory( AliasFactory, type="Artist name", prefix=factory.SelfAttribute("...name"), ) ] ) class ArtistCreditFactory(factory.DictFactory): artist = factory.SubFactory(ArtistFactory) joinphrase = "" name = factory.LazyAttribute(lambda o: f"{o.artist['name']} Credit") class ArtistRelationFactory(_PeriodFactory): artist = factory.SubFactory( ArtistFactory, name=factory.LazyAttribute( lambda o: f"{o.factory_parent.type.capitalize()} Artist" ), ) attribute_ids = factory.Dict({}) attribute_credits = factory.Dict({}) attributes = factory.List([]) direction = "backward" source_credit = "" target_credit = "" type = FuzzyChoice(ArtistRelationType.__args__) # type: ignore[attr-defined] type_id = factory.Faker("uuid4") class AreaFactory(factory.DictFactory): disambiguation = "" id = factory.Faker("uuid4") iso_3166_1_codes = factory.List([]) iso_3166_2_codes = factory.List([]) name = "Area" sort_name = "Area, The" type: None = None type_id: None = None class ReleaseEventFactory(factory.DictFactory): area = factory.SubFactory(AreaFactory) date = factory.Faker("date") class ReleaseGroupFactory(_IdFactory): class Params: id_base = 100 aliases = factory.List( [ factory.SubFactory( AliasFactory, type="Release group name", prefix=factory.SelfAttribute("...title"), ) ] ) artist_credit = factory.List([factory.SubFactory(ArtistCreditFactory)]) disambiguation = factory.LazyAttribute( lambda o: f"{o.title} Disambiguation" ) first_release_date = "2001-02-03" genres = factory.List([]) primary_type = "Album" primary_type_id = "f529b476-6e62-324f-b0aa-1f3e33d313fc" secondary_type_ids = factory.List([]) secondary_types = factory.List([]) tags = factory.List([]) title = "Release Group" class GenreFactory(factory.DictFactory): id = factory.Faker("uuid4") count = 1 disambiguation = "" name = "Genre" class TagFactory(GenreFactory): name = "Tag" class LabelFactory(_SortNameFactory, _IdFactory): aliases = factory.List([]) disambiguation = "" genres = factory.List([]) label_code: str | None = None name = "Label" tags = factory.List([]) type = "Imprint" type_id = "b6285b2a-3514-3d43-80df-fcf528824ded" class LabelInfoFactory(factory.DictFactory): catalog_number = "LAB123" label = factory.SubFactory(LabelFactory) class TextRepresentationFactory(factory.DictFactory): language = "eng" script = "Latn" class RecordingFactory(_IdFactory): class Params: id_base = 1000 aliases = factory.List( [ factory.SubFactory( AliasFactory, type="Recording name", prefix=factory.SelfAttribute("...title"), ) ] ) artist_credit = factory.List( [ factory.SubFactory( ArtistCreditFactory, artist__name="Recording Artist" ) ] ) disambiguation = "" isrcs = factory.List([]) length = 360 title = "Recording" video = False genres = factory.List([]) tags = factory.List([]) class TrackFactory(_IdFactory): class Params: id_base = 10000 artist_credit = factory.List([]) length = factory.LazyAttribute(lambda o: o.recording["length"]) number = "A1" position = 1 recording = factory.SubFactory(RecordingFactory) title = factory.LazyAttribute( lambda o: ( f"{'Video: ' if o.recording['video'] else ''}{o.recording['title']}" ) ) class MediumFactory(_IdFactory): class Params: id_base = 100000 format = "Digital Media" format_id = "907a28d9-b3b2-3ef6-89a8-7b18d91d4794" position = 1 title = "Medium" data_tracks = factory.List([]) track_offset: int | None = None tracks = factory.List([factory.SubFactory(TrackFactory)]) track_count = factory.LazyAttribute(lambda o: len(o.tracks)) class UrlFactory(factory.DictFactory): id = factory.Faker("uuid4") resource = "https://example.com" class UrlRelationFactory(factory.DictFactory): type = "purchase for download" url = factory.SubFactory(UrlFactory) class ReleaseFactory(_IdFactory): class Params: id_base = 1000000 aliases = factory.List( [ factory.SubFactory( AliasFactory, type="Release name", prefix=factory.SelfAttribute("...title"), ) ] ) artist_credit = factory.List( [factory.SubFactory(ArtistCreditFactory, artist__id_base=10)] ) asin = factory.LazyAttribute(lambda o: f"{o.title} Asin") barcode = "0000000000000" cover_art_archive = factory.Dict( { "artwork": False, "back": False, "count": 0, "darkened": False, "front": False, } ) disambiguation = factory.LazyAttribute( lambda o: f"{o.title} Disambiguation" ) genres = factory.List([factory.SubFactory(GenreFactory)]) label_info = factory.List([factory.SubFactory(LabelInfoFactory)]) media = factory.List([factory.SubFactory(MediumFactory)]) packaging: str | None = None packaging_id: str | None = None quality = "normal" release_events = factory.List( [ factory.SubFactory( ReleaseEventFactory, area=None, date="2021-03-26" ), factory.SubFactory( ReleaseEventFactory, area__iso_3166_1_codes=["US"], date="2020-01-01", ), ] ) release_group = factory.SubFactory(ReleaseGroupFactory) status = "Official" status_id = "4e304316-386d-3409-af2e-78857eec5cfe" tags = factory.List([factory.SubFactory(TagFactory)]) text_representation = factory.SubFactory(TextRepresentationFactory) title = "Album" beetbox-beets-00724b7/test/plugins/test_lyrics.py0000664000175000017500000011056315253035401021437 0ustar pieterpieter"""Tests for the 'lyrics' plugin.""" from __future__ import annotations import re import textwrap from functools import partial from http import HTTPStatus from pathlib import Path from types import SimpleNamespace from typing import TYPE_CHECKING import pytest import requests from beets.library import Item from beets.test.helper import PluginMixin, PluginTestHelper from beets.util.lyrics import Lyrics from beetsplug import lyrics from .lyrics_pages import lyrics_pages if TYPE_CHECKING: from .lyrics_pages import LyricsPage PHRASE_BY_TITLE = { "Lady Madonna": "friday night arrives without a suitcase", "Jazz'n'blues": "as i check my balance i kiss the screen", "Beets song": "via plugins, beets becomes a panacea", } @pytest.fixture(scope="module") def helper(module_helper): """Reuse one module helper for explicit item and media-write checks. Helper-backed tests mutate known items and write an MP3 fixture, but they do not assert against the full library shared with other tests in this module. """ return module_helper class TestLyricsUtils: @pytest.mark.parametrize( "artist, title", [ ("Various Artists", "Title"), ("Artist", ""), ("", "Title"), (" ", ""), ("", " "), ("", ""), ], ) def test_search_empty(self, artist, title): actual_pairs = lyrics.search_pairs(Item(artist=artist, title=title)) assert not list(actual_pairs) @pytest.mark.parametrize( "artist, artist_sort, expected_extra_artists", [ ("Alice ft. Bob", "", ["Alice"]), ("Alice feat Bob", "", ["Alice"]), ("Alice feat. Bob", "", ["Alice"]), ("Alice feats Bob", "", []), ("Alice featuring Bob", "", ["Alice"]), ("Alice & Bob", "", ["Alice"]), ("Alice and Bob", "", ["Alice"]), ("Alice", "", []), ("Alice", "Alice", []), ("Alice", "alice", []), ("Alice", "alice ", []), ("Alice", "Alice A", ["Alice A"]), ("CHVRCHΞS", "CHVRCHES", ["CHVRCHES"]), ("横山克", "Masaru Yokoyama", ["Masaru Yokoyama"]), ], ) def test_search_pairs_artists( self, artist, artist_sort, expected_extra_artists ): item = Item(artist=artist, artist_sort=artist_sort, title="song") actual_artists = [a for a, _ in lyrics.search_pairs(item)] # Make sure that the original artist name is still the first entry assert actual_artists == [artist, *expected_extra_artists] @pytest.mark.parametrize( "title, expected_extra_titles", [ ("1/2", []), ("1 / 2", ["1", "2"]), ("Song (live)", ["Song"]), ("Song (live) (new)", ["Song"]), ("Song (live (new))", ["Song"]), ("Song ft. B", ["Song"]), ("Song featuring B", ["Song"]), ("Song and B", []), ("Song: B", ["Song"]), ], ) def test_search_pairs_titles(self, title, expected_extra_titles): item = Item(title=title, artist="A") actual_titles = { t: None for _, tit in lyrics.search_pairs(item) for t in tit } assert list(actual_titles) == [title, *expected_extra_titles] @pytest.mark.parametrize( "text, expected", [ ("test", "test"), ("Mørdag", "mordag"), ("l'été c'est fait pour jouer", "l-ete-c-est-fait-pour-jouer"), ("\xe7afe au lait (boisson)", "cafe-au-lait-boisson"), ("Multiple spaces -- and symbols! -- merged", "multiple-spaces-and-symbols-merged"), # noqa: E501 ("\u200bno-width-space", "no-width-space"), ("El\u002dp", "el-p"), ("\u200bblackbear", "blackbear"), ("\u200d", ""), ("\u2010", ""), ], ) # fmt: skip def test_slug(self, text, expected): assert lyrics.slug(text) == expected @pytest.mark.parametrize( "text, expected", [ ("If They’re Shooting at You", "If-They-re-Shooting-at-You"), ("‘Round Midnight", "-Round-Midnight"), ("Don't Stop", "Don-t-Stop"), ], ) def test_musixmatch_encode(self, text, expected): assert lyrics.MusiXmatch.encode(text) == expected class TestHtml: def test_scrape_strip_cruft(self): initial = """  one
two !

four""" expected = "\none\ntwo !\n\nfour" assert lyrics.Html.normalize_space(initial) == expected def test_scrape_merge_paragraphs(self): text = 'one

two

three' expected = "one\n\ntwo\n\nthree" assert lyrics.Html.merge_paragraphs(text) == expected class TestSearchBackend: @pytest.fixture def backend(self, dist_thresh): plugin = lyrics.LyricsPlugin() plugin.config.set({"dist_thresh": dist_thresh}) return lyrics.SearchBackend(plugin.config, plugin._log) @pytest.mark.parametrize( "dist_thresh, target_artist, artist, should_match", [ (0.11, "Target Artist", "Target Artist", True), (0.11, "Target Artist", "Target Artis", True), (0.11, "Target Artist", "Target Arti", False), (0.11, "Psychonaut", "Psychonaut (BEL)", True), (0.11, "beets song", "beats song", True), (0.10, "beets song", "beats song", False), ( 0.11, "Lucid Dreams (Forget Me)", "Lucid Dreams (Remix) ft. Lil Uzi Vert", False, ), ( 0.12, "Lucid Dreams (Forget Me)", "Lucid Dreams (Remix) ft. Lil Uzi Vert", True, ), ], ) def test_check_match(self, backend, target_artist, artist, should_match): result = lyrics.SearchResult(artist, "", "") assert backend.check_match(target_artist, "", result) == should_match @pytest.fixture(scope="module") def lyrics_root_dir(pytestconfig: pytest.Config): return pytestconfig.rootpath / "test" / "rsrc" / "lyrics" class LyricsPluginMixin(PluginMixin): plugin = "lyrics" @pytest.fixture def plugin_config(self): """Return lyrics configuration to test.""" return {} @pytest.fixture def lyrics_plugin(self, backend_name, plugin_config): """Set configuration and returns the plugin's instance.""" plugin_config["sources"] = [backend_name] self.config[self.plugin].set(plugin_config) return lyrics.LyricsPlugin() class TestLyricsPlugin(LyricsPluginMixin): @pytest.fixture def backend_name(self): """Return lyrics configuration to test.""" return "lrclib" @pytest.mark.parametrize( "request_kwargs, expected_log_match", [ ( {"status_code": HTTPStatus.BAD_GATEWAY}, r"LRCLib: Request error: 502", ), ({"text": "invalid"}, r"LRCLib: Could not decode.*JSON"), ], ) def test_error_handling( self, requests_mock, lyrics_plugin, caplog, request_kwargs, expected_log_match, ): """Errors are logged with the backend name.""" requests_mock.get(lyrics.LRCLib.SEARCH_URL, **request_kwargs) assert lyrics_plugin.get_lyrics("", "", "", 0.0) is None assert caplog.messages last_log = caplog.messages[-1] assert last_log assert re.search(expected_log_match, last_log, re.I) @pytest.mark.parametrize( "plugin_config, old_lyrics, found, expected", [ pytest.param({}, "old", "new", "old", id="no_force_keeps_old"), pytest.param( {"force": True}, "old", "new", "new", id="force_overwrites_with_new", ), pytest.param( {"force": True, "local": True}, "old", "new", "old", id="force_local_keeps_old", ), pytest.param( {"force": True, "fallback": None}, "old", None, "old", id="force_fallback_none_keeps_old", ), pytest.param( {"force": True, "fallback": ""}, "old", None, "", id="force_fallback_empty_uses_empty", ), pytest.param( {"force": True, "fallback": "default"}, "old", None, "default", id="force_fallback_default_uses_default", ), pytest.param( {"force": True, "synced": True}, "[00:00.00] old synced", "new plain", "[00:00.00] old synced", id="keep-existing-synced-lyrics", ), pytest.param( {"force": True, "synced": True}, "[00:00.00] old synced", "[00:00.00] new synced", "[00:00.00] new synced", id="replace-with-new-synced-lyrics", ), pytest.param( {"force": True, "synced": False}, "[00:00.00] old synced", "new plain", "new plain", id="replace-with-unsynced-lyrics-when-disabled", ), pytest.param( {"force": True, "keep_synced": True}, "[00:00.00] old synced", "new", "[00:00.00] old synced", id="keep_synced_keeps_old_synced", ), ], ) def test_overwrite_config( self, monkeypatch, helper, lyrics_plugin, old_lyrics, found, expected ): monkeypatch.setattr( lyrics_plugin, "find_lyrics", lambda _: Lyrics(found) if found is not None else None, ) item = helper.create_item(id=1, lyrics=old_lyrics) lyrics_plugin.add_item_lyrics(item, False) assert item.lyrics == expected def test_set_additional_lyrics_info( self, monkeypatch, helper, lyrics_plugin, is_importable ): lyrics = Lyrics( "sing in the rain every hour of the day", "lrclib", url="https://lrclib.net/api/1", ) monkeypatch.setattr(lyrics_plugin, "find_lyrics", lambda _: lyrics) item = helper.add_item( id=1, lyrics="", lyrics_translation_language="EN" ) lyrics_plugin.add_item_lyrics(item, False) item = helper.lib.get_item(item.id) assert item.lyrics_url == lyrics.url assert item.lyrics_instrumental == "0" assert item.lyrics_backend == lyrics.backend if is_importable("langdetect"): assert item.lyrics_language == "EN" else: with pytest.raises(AttributeError): item.lyrics_language # make sure translation language is cleared with pytest.raises(AttributeError): item.lyrics_translation_language def test_imported_skips_auto_ignored_items( self, lyrics_plugin, monkeypatch ): lyrics_plugin.config["auto_ignore"].set("album:Greatest Hits") items = [ Item(title="Old Song", album="Greatest Hits", genre="Rock"), Item(title="Come Together", album="Abbey Road", genre="Rock"), ] calls = [] monkeypatch.setattr( lyrics_plugin, "add_item_lyrics", lambda current_item, write: calls.append( (current_item.title, write) ), ) task = SimpleNamespace(imported_items=lambda: items) lyrics_plugin.imported(None, task) assert calls == [("Come Together", False)] class LyricsBackendTest(LyricsPluginMixin): @pytest.fixture def backend(self, lyrics_plugin): """Return a lyrics backend instance.""" return lyrics_plugin.backends[0] @pytest.fixture def lyrics_html(self, lyrics_root_dir, file_name): return (lyrics_root_dir / f"{file_name}.txt").read_text( encoding="utf-8" ) @pytest.mark.on_lyrics_update class TestLyricsSources(LyricsBackendTest): @pytest.fixture(scope="class") def plugin_config(self): return {"google_API_key": "test", "synced": True} @pytest.fixture( params=[pytest.param(lp, marks=lp.marks) for lp in lyrics_pages], ids=str, ) def lyrics_page(self, request): return request.param @pytest.fixture def backend_name(self, lyrics_page): return lyrics_page.backend @pytest.fixture(autouse=True) def _patch_google_search(self, requests_mock, lyrics_page): """Mock the Google Search API to return the lyrics page under test.""" requests_mock.real_http = True data = { "items": [ { "title": lyrics_page.url_title, "link": lyrics_page.url, "displayLink": lyrics_page.root_url, } ] } requests_mock.get(lyrics.Google.SEARCH_URL, json=data) @pytest.fixture(autouse=True) def _set_lrcmux_sources(self, lyrics_plugin, backend_name): if backend_name == "lrcmux": lyrics_plugin.config["lrcmux"]["sources"] = ["ytmusic"] def test_backend_source( self, monkeypatch, lyrics_plugin, lyrics_page: LyricsPage ): """Test parsed lyrics from each of the configured lyrics pages.""" monkeypatch.setattr( "beetsplug.lyrics.LyricsRequestHandler.create_session", lambda _: requests.Session(), ) expected_lyrics = Lyrics( lyrics_page.lyrics, lyrics_page.backend, url=lyrics_page.url, language=lyrics_page.language, ) actual_lyrics = lyrics_plugin.find_lyrics( Item( artist=lyrics_page.artist, title=lyrics_page.track_title, album="", length=186.0, ) ) assert actual_lyrics assert actual_lyrics.text == expected_lyrics.text assert actual_lyrics == expected_lyrics class TestGoogleLyrics(LyricsBackendTest): """Test scraping heuristics on a fake html page.""" @pytest.fixture(scope="class") def backend_name(self): return "google" @pytest.fixture def plugin_config(self): return {"google_API_key": "test"} @pytest.fixture(scope="class") def file_name(self): return "examplecom/beetssong" @pytest.fixture def search_item(self, url_title, url): return {"title": url_title, "link": url} @pytest.mark.parametrize("plugin_config", [{}]) def test_disabled_without_api_key(self, lyrics_plugin): assert not lyrics_plugin.backends def test_mocked_source_ok(self, backend, lyrics_html): """Test that lyrics of the mocked page are correctly scraped""" result = backend.scrape(lyrics_html).lower() assert result assert PHRASE_BY_TITLE["Beets song"] in result @pytest.mark.parametrize( "url_title, expected_artist, expected_title", [ ("Artist - beets song Lyrics", "Artist", "beets song"), ("www.azlyrics.com | Beats song by Artist", "Artist", "Beats song"), ("lyric.com | seets bong lyrics by Artist", "Artist", "seets bong"), ("foo", "", "foo"), ("Artist - Beets Song lyrics | AZLyrics", "Artist", "Beets Song"), ("Letra de Artist - Beets Song", "Artist", "Beets Song"), ("Letra de Artist - Beets ...", "Artist", "Beets"), ("Artist Beets Song", "Artist", "Beets Song"), ("BeetsSong - Artist", "Artist", "BeetsSong"), ("Artist - BeetsSong", "Artist", "BeetsSong"), ("Beets Song", "", "Beets Song"), ("Beets Song Artist", "Artist", "Beets Song"), ( "BeetsSong (feat. Other & Another) - Artist", "Artist", "BeetsSong (feat. Other & Another)", ), ( ( "Beets song lyrics by Artist - original song full text. " "Official Beets song lyrics, 2024 version | LyricsMode.com" ), "Artist", "Beets song", ), ], ) @pytest.mark.parametrize("url", ["http://doesntmatter.com"]) def test_make_search_result( self, backend, search_item, expected_artist, expected_title ): result = backend.make_search_result("Artist", "Beets song", search_item) assert result.artist == expected_artist assert result.title == expected_title class TestGeniusLyrics(LyricsBackendTest): @pytest.fixture(scope="class") def backend_name(self): return "genius" @pytest.mark.parametrize( "file_name, expected_line_count", [ ("geniuscom/2pacalleyezonmelyrics", 131), ("geniuscom/Ttngchinchillalyrics", 29), ("geniuscom/sample", 0), # see https://github.com/beetbox/beets/issues/3535 ], ) # fmt: skip def test_scrape(self, backend, lyrics_html, expected_line_count): result = backend.scrape(lyrics_html) or "" assert len(result.splitlines()) == expected_line_count class TestTekstowoLyrics(LyricsBackendTest): @pytest.fixture(scope="class") def backend_name(self): return "tekstowo" @pytest.mark.parametrize( "file_name, expecting_lyrics", [ ("tekstowopl/piosenka24kgoldncityofangels1", True), ( "tekstowopl/piosenkabeethovenbeethovenpianosonata17tempestthe3rdmovement", False, ), ], ) def test_scrape(self, backend, lyrics_html, expecting_lyrics): assert bool(backend.scrape(lyrics_html)) == expecting_lyrics LYRICS_DURATION = 950 def lyrics_match(**overrides): return { "id": 1, "instrumental": False, "duration": LYRICS_DURATION, "syncedLyrics": "[00:00.00] synced", "plainLyrics": "plain", **overrides, } class TestLRCLibLyrics(LyricsBackendTest): ITEM_DURATION = 999 SYNCED = "[00:00.00] synced" @pytest.fixture(scope="class") def backend_name(self): return "lrclib" @pytest.fixture def fetch_lyrics(self, backend, requests_mock, response_data): requests_mock.get(backend.GET_URL, status_code=HTTPStatus.NOT_FOUND) requests_mock.get(backend.SEARCH_URL, json=response_data) return partial(backend.fetch, "la", "la", "la", self.ITEM_DURATION) @pytest.mark.parametrize("response_data", [[lyrics_match()]]) @pytest.mark.parametrize( "plugin_config, expected_lyrics", [ pytest.param({"synced": True}, SYNCED, id="pick-synced"), pytest.param({"synced": False}, "plain", id="pick-plain"), ], ) def test_synced_config_option( self, backend_name, fetch_lyrics, expected_lyrics ): lyrics = fetch_lyrics() assert lyrics assert lyrics.text == expected_lyrics assert lyrics.backend == backend_name @pytest.mark.parametrize( "response_data", [[lyrics_match(plainLyrics=None)]] ) @pytest.mark.parametrize("plugin_config", [{"synced": False}]) def test_null_plain_lyrics_falls_back_to_synced(self, fetch_lyrics): """Use synced lyrics when 'plainLyrics' is null. LRCLib may return a null 'plainLyrics' while still providing synced lyrics, so preferring plain text must not discard the data we have. The timestamps are dropped, since this is standing in for plain text. """ lyrics = fetch_lyrics() assert lyrics assert lyrics.text == "synced" @pytest.mark.parametrize( "response_data, expected_lyrics", [ pytest.param([], None, id="handle non-matching lyrics"), pytest.param([lyrics_match()], SYNCED, id="synced when available"), pytest.param( [ lyrics_match( syncedLyrics="[00:01.234] 3-decimal synced lyrics" ) ], "[00:01.234] 3-decimal synced lyrics", id="synced with 3-decimal millisecond timestamp", ), pytest.param( [lyrics_match(duration=1)], None, id="none: duration too short" ), pytest.param( [lyrics_match(instrumental=True)], "", id="instrumental track" ), pytest.param( [lyrics_match(syncedLyrics=None)], "plain", id="plain by default", ), pytest.param( [lyrics_match(plainLyrics=None, syncedLyrics=None)], None, id="none: no lyrics text despite instrumental being False", ), pytest.param( [ lyrics_match( duration=ITEM_DURATION, syncedLyrics=None, plainLyrics="plain with closer duration", ), lyrics_match(syncedLyrics=SYNCED, plainLyrics="plain 2"), ], SYNCED, id="prefer synced lyrics even if plain duration is closer", ), pytest.param( [ lyrics_match( duration=ITEM_DURATION, syncedLyrics=None, plainLyrics="valid plain", ), lyrics_match( duration=1, syncedLyrics="synced with invalid duration" ), ], "valid plain", id="ignore synced with invalid duration", ), pytest.param( [ lyrics_match( duration=59, syncedLyrics="[01:00.00] invalid synced" ) ], None, id="ignore synced with a timestamp longer than duration", ), pytest.param( [lyrics_match(syncedLyrics=None), lyrics_match()], SYNCED, id="prefer match with synced lyrics", ), ], ) @pytest.mark.parametrize("plugin_config", [{"synced": True}]) def test_fetch_lyrics(self, fetch_lyrics, expected_lyrics): lyrics = fetch_lyrics() if expected_lyrics is None: assert not lyrics else: assert lyrics assert lyrics.text == expected_lyrics class TestLRCMuxLyrics(LyricsBackendTest): SYNCED = "[00:00.00] synced" PLAIN = "plain" @pytest.fixture(scope="class") def backend_name(self): return "lrcmux" @pytest.mark.parametrize( "plugin_config, mocked_text, expected_format, expected_level", [ pytest.param({"synced": True}, SYNCED, "lrc", "line", id="synced"), pytest.param({"synced": False}, PLAIN, "txt", "none", id="plain"), pytest.param( {"synced": True, "lrcmux": {"sources": ["ytmusic"]}}, SYNCED, "lrc", "line", id="synced-sources", ), ], ) def test_fetch_lyrics( self, backend, requests_mock, mocked_text, expected_format, expected_level, plugin_config, ): requests_mock.get(backend.url, text=mocked_text) result = backend.fetch("la", "la", "la", 0) assert result assert result.text == mocked_text assert result.backend == "lrcmux" assert f"format={expected_format}" in result.url assert f"level={expected_level}" in result.url if sources := (plugin_config.get("lrcmux") or {}).get("sources"): assert f"sources={','.join(sources)}" in result.url @pytest.mark.parametrize("plugin_config", [{}]) def test_not_found(self, backend, requests_mock): requests_mock.get(backend.url, status_code=HTTPStatus.NOT_FOUND) assert backend.fetch("la", "la", "", 0) is None @pytest.mark.parametrize("plugin_config", [{}]) def test_empty_response(self, backend, requests_mock): requests_mock.get(backend.url, text="") assert backend.fetch("la", "la", "", 0) is None @pytest.mark.requires_import("langdetect") class TestTranslation: @pytest.fixture(autouse=True) def _patch_bing(self, requests_mock): def callback(request, _): if b"Refrain" in request.body: translations = ( "" " | [Refrain : Doja Cat]" " | Difficile pour moi de te laisser partir (Te laisser partir, te laisser partir)" # noqa: E501 " | Mon corps ne me laissait pas le cacher (Cachez-le)" " | [Chorus]" " | Quoi qu’il arrive, je ne plierais pas (Ne plierait pas, ne plierais pas)" # noqa: E501 " | Chevauchant à travers le tonnerre, la foudre" ) elif b"00:00.00" in request.body: translations = ( "" " | [00:00.00] Quelques paroles synchronisées" " | [00:01.00] Quelques paroles plus synchronisées" ) else: translations = ( "" " | Quelques paroles synchronisées" " | Quelques paroles plus synchronisées" ) return [ { "detectedLanguage": {"language": "en", "score": 1.0}, "translations": [{"text": translations, "to": "fr"}], } ] requests_mock.post(lyrics.Translator.TRANSLATE_URL, json=callback) @pytest.mark.parametrize( "new_lyrics, old_lyrics, expected", [ pytest.param( """ [Refrain: Doja Cat] Hard for me to let you go (Let you go, let you go) My body wouldn't let me hide it (Hide it) [Chorus] No matter what, I wouldn't fold (Wouldn't fold, wouldn't fold) Ridin' through the thunder, lightnin'""", Lyrics(""), """ [Refrain: Doja Cat] / [Refrain : Doja Cat] Hard for me to let you go (Let you go, let you go) / Difficile pour moi de te laisser partir (Te laisser partir, te laisser partir) My body wouldn't let me hide it (Hide it) / Mon corps ne me laissait pas le cacher (Cachez-le) [Chorus] No matter what, I wouldn't fold (Wouldn't fold, wouldn't fold) / Quoi qu’il arrive, je ne plierais pas (Ne plierait pas, ne plierais pas) Ridin' through the thunder, lightnin' / Chevauchant à travers le tonnerre, la foudre""", # noqa: E501 id="plain", ), pytest.param( """ [00:00.00] Some synced lyrics [00:00.50] [00:01.00] Some more synced lyrics """, Lyrics(""), """ [00:00.00] Some synced lyrics / Quelques paroles synchronisées [00:00.50] [00:01.00] Some more synced lyrics / Quelques paroles plus synchronisées""", # noqa: E501 id="synced", ), pytest.param( "Quelques paroles", Lyrics(""), "Quelques paroles", id="already in the target language", ), pytest.param( "Some lyrics", Lyrics( "Some lyrics / Some translation", language="EN", translation_language="FR", ), "Some lyrics / Some translation", id="already translated", ), ], ) def test_translate(self, new_lyrics, old_lyrics, expected): plugin = lyrics.LyricsPlugin() bing = lyrics.Translator(plugin._log, "123", "FR", ["EN"]) assert bing.translate( Lyrics(textwrap.dedent(new_lyrics)), old_lyrics ).full_text == textwrap.dedent(expected) class TestRestFiles: @pytest.fixture def rest_dir(self, tmp_path): return tmp_path @pytest.fixture def rest_files(self, rest_dir): return lyrics.RestFiles(rest_dir) def test_write(self, rest_dir: Path, rest_files): items = [ Item(albumartist=aa, album=a, title=t, lyrics=lyr) for aa, a, t, lyr in [ ("Artist One", "Album One", "Song One", "Lyrics One"), ("Artist One", "Album One", "Song Two", "Lyrics Two"), ("Artist Two", "Album Two", "Song Three", "Lyrics Three"), ] ] rest_files.write(items) assert (rest_dir / "index.rst").exists() assert (rest_dir / "conf.py").exists() artist_one_file = rest_dir / "artists" / "artist-one.rst" artist_two_file = rest_dir / "artists" / "artist-two.rst" assert artist_one_file.exists() assert artist_two_file.exists() c = artist_one_file.read_text() assert ( c.index("Artist One") < c.index("Album One") < c.index("Song One") < c.index("Lyrics One") < c.index("Song Two") < c.index("Lyrics Two") ) c = artist_two_file.read_text() assert ( c.index("Artist Two") < c.index("Album Two") < c.index("Song Three") < c.index("Lyrics Three") ) class TestLyricsRestDirectory(PluginTestHelper): plugin = "lyrics" @pytest.mark.parametrize( "config_path, arg_path, output_path", [ pytest.param( "test/config", "test/cmd", "test/cmd", id="config and cmd arg" ), pytest.param("test/config", None, "test/config", id="config only"), pytest.param(None, "test/cmd", "test/cmd", id="cmd arg only"), pytest.param( "~/test/config", None, "~/test/config", id="user home path" ), ], ) def test_rest_config(self, monkeypatch, config_path, arg_path, output_path): test_capture = {} class MockRestFiles: def __init__(self, directory): test_capture["directory"] = directory def write(self, items): test_capture["items"] = items monkeypatch.setattr(lyrics, "RestFiles", MockRestFiles) self.add_item(lyrics="hello") cmd_args = [] if arg_path is None else ["-r", arg_path] with self.configure_plugin({"rest_directory": config_path}): self.run_command("lyrics", *cmd_args) assert test_capture.get("directory") == Path(output_path).expanduser() class TestLyricsKeepSyncedCommand(PluginTestHelper): plugin = "lyrics" @pytest.mark.parametrize( "config_keep_synced, cmd_args, expected_keep_synced", [ pytest.param(False, (), False, id="disabled-by-default"), pytest.param(True, (), True, id="enabled-by-config"), pytest.param(False, ("--keep-synced",), True, id="cli-enables"), pytest.param( True, ("--no-keep-synced",), False, id="cli-disables-config" ), ], ) def test_keep_synced_cli_option( self, monkeypatch, config_keep_synced, cmd_args, expected_keep_synced ): self.config["lyrics"]["keep_synced"] = config_keep_synced self.add_item(lyrics="[00:00.00] old synced") observed_keep_synced = [] def capture_keep_synced(plugin, *_): observed_keep_synced.append(plugin.config["keep_synced"].get(bool)) monkeypatch.setattr( lyrics.LyricsPlugin, "add_item_lyrics", capture_keep_synced ) self.run_command("lyrics", *cmd_args) assert observed_keep_synced.pop(0) is expected_keep_synced class TestLyricsSyltProperty: """Unit tests for the Lyrics.sylt timestamp-to-millisecond converter.""" @pytest.mark.parametrize( "lrc_text, expected_sylt", [ pytest.param( "[00:01.00] line one\n[00:02.50] line two", [("line one", 1000), ("line two", 2500)], id="basic-lrc-to-ms", ), pytest.param( "[01:30.50] one and a half minutes", [("one and a half minutes", 90500)], id="over-one-minute", ), pytest.param( "plain lyrics without timestamps", [], id="plain-lyrics-have-no-sylt", ), pytest.param( "[00:00.00] timed\nuntimed line\n[00:05.00] timed again", [("timed", 0), ("timed again", 5000)], id="untimed-lines-omitted", ), pytest.param( "[00:00.00] \n[00:01.00] second", [("", 0), ("second", 1000)], id="empty-text-line-included", ), ], ) def test_sylt(self, lrc_text, expected_sylt): assert Lyrics(lrc_text).sylt == expected_sylt class TestSyncedLyricsWrite(LyricsPluginMixin): """Tests that add_item_lyrics passes the correct synced_lyrics tag.""" SYNCED_LRC = "[00:01.00] hello\n[00:02.00] world" @pytest.fixture def backend_name(self): return "lrclib" def test_sylt_data_passed_for_synced_lyrics( self, monkeypatch, helper, lyrics_plugin ): monkeypatch.setattr( lyrics_plugin, "find_lyrics", lambda _: Lyrics(self.SYNCED_LRC) ) item = helper.create_item(id=1, lyrics="") calls = [] monkeypatch.setattr( type(item), "try_write", lambda self, **kw: calls.append(kw) or True ) lyrics_plugin.add_item_lyrics(item, write=True) assert calls == [ {"tags": {"synced_lyrics": [("hello", 1000), ("world", 2000)]}} ] def test_lrc_text_kept_in_db_for_synced( self, monkeypatch, helper, lyrics_plugin ): """LRC text is stored in the DB so keep_synced detection still works.""" monkeypatch.setattr( lyrics_plugin, "find_lyrics", lambda _: Lyrics(self.SYNCED_LRC) ) item = helper.create_item(id=1, lyrics="") monkeypatch.setattr(type(item), "try_write", lambda self, **kw: True) lyrics_plugin.add_item_lyrics(item, write=True) assert item.lyrics == self.SYNCED_LRC def test_sylt_cleared_for_plain_lyrics( self, monkeypatch, helper, lyrics_plugin ): monkeypatch.setattr( lyrics_plugin, "find_lyrics", lambda _: Lyrics("plain lyrics") ) item = helper.create_item(id=1, lyrics="") calls = [] monkeypatch.setattr( type(item), "try_write", lambda self, **kw: calls.append(kw) or True ) lyrics_plugin.add_item_lyrics(item, write=True) assert calls == [{"tags": {"synced_lyrics": None}}] def test_sylt_and_uslt_written_to_mp3( self, monkeypatch, helper, lyrics_plugin ): """Integration: SYLT + plain USLT are written to a real MP3 file.""" import mutagen monkeypatch.setattr( lyrics_plugin, "find_lyrics", lambda _: Lyrics(self.SYNCED_LRC) ) item = helper.add_item_fixture(format="MP3", lyrics="") lyrics_plugin.add_item_lyrics(item, write=True) f = mutagen.File(item.path) assert f.tags.getall("SYLT"), "SYLT frame should be present" assert f.tags["SYLT::XXX"].text == [("hello", 1000), ("world", 2000)] assert f.tags.getall("USLT"), "USLT frame should be present" # USLT retains the full LRC text (with timestamps) so players that # parse LRC in USLT, and non-ID3 formats, continue to work. assert f.tags["USLT::XXX"].text == self.SYNCED_LRC beetbox-beets-00724b7/test/plugins/test_plugin_mediafield.py0000664000175000017500000000671215253035401023573 0ustar pieterpieter"""Tests the facility that lets plugins add custom field to MediaFile.""" import shutil import mediafile import pytest from beets.library import Item from beets.plugins import BeetsPlugin from beets.test import _common from beets.test.helper import BeetsTestCase from beets.util import syspath field_extension = mediafile.MediaField( mediafile.MP3DescStorageStyle("customtag"), mediafile.MP4StorageStyle("----:com.apple.iTunes:customtag"), mediafile.StorageStyle("customtag"), mediafile.ASFStorageStyle("customtag"), ) list_field_extension = mediafile.ListMediaField( mediafile.MP3ListDescStorageStyle("customlisttag"), mediafile.MP4ListStorageStyle("----:com.apple.iTunes:customlisttag"), mediafile.ListStorageStyle("customlisttag"), mediafile.ASFStorageStyle("customlisttag"), ) class ExtendedFieldTestMixin(BeetsTestCase): def _mediafile_fixture(self, name, extension="mp3"): name = f"{name}.{extension}" src = _common.RSRC / name target = self.temp_path / name shutil.copy(src, syspath(target)) return mediafile.MediaFile(target) def test_extended_field_write(self): plugin = BeetsPlugin() plugin.add_media_field("customtag", field_extension) try: mf = self._mediafile_fixture("empty") mf.customtag = "F#" mf.save() mf = mediafile.MediaFile(mf.path) assert mf.customtag == "F#" finally: delattr(mediafile.MediaFile, "customtag") Item._media_fields.remove("customtag") def test_extended_list_field_write(self): plugin = BeetsPlugin() plugin.add_media_field("customlisttag", list_field_extension) try: mf = self._mediafile_fixture("empty") mf.customlisttag = ["a", "b"] mf.save() mf = mediafile.MediaFile(mf.path) assert mf.customlisttag == ["a", "b"] finally: delattr(mediafile.MediaFile, "customlisttag") Item._media_fields.remove("customlisttag") def test_write_extended_tag_from_item(self): plugin = BeetsPlugin() plugin.add_media_field("customtag", field_extension) try: mf = self._mediafile_fixture("empty") assert mf.customtag is None item = Item(path=mf.path, customtag="Gb") item.write() mf = mediafile.MediaFile(mf.path) assert mf.customtag == "Gb" finally: delattr(mediafile.MediaFile, "customtag") Item._media_fields.remove("customtag") def test_read_flexible_attribute_from_file(self): plugin = BeetsPlugin() plugin.add_media_field("customtag", field_extension) try: mf = self._mediafile_fixture("empty") mf.update({"customtag": "F#"}) mf.save() item = Item.from_path(mf.path) assert item["customtag"] == "F#" finally: delattr(mediafile.MediaFile, "customtag") Item._media_fields.remove("customtag") def test_invalid_descriptor(self): with pytest.raises( ValueError, match="must be an instance of MediaField" ): mediafile.MediaFile.add_field("somekey", True) def test_overwrite_property(self): with pytest.raises( ValueError, match='property "artist" already exists' ): mediafile.MediaFile.add_field("artist", mediafile.MediaField()) beetbox-beets-00724b7/test/plugins/test_subsonicupdate.py0000664000175000017500000001156315253035401023162 0ustar pieterpieter"""Tests for the 'subsonic' plugin.""" import responses from beets import config from beets.test.helper import TestHelper from beetsplug import subsonicupdate class SubsonicPluginTest(TestHelper): """Test class for subsonicupdate.""" @responses.activate def setUp(self): """Sets up config and plugin for test.""" super().setUp() config["subsonic"]["user"] = "admin" config["subsonic"]["pass"] = "admin" config["subsonic"]["url"] = "http://localhost:4040" responses.add( responses.GET, "http://localhost:4040/rest/ping.view", status=200, body=self.PING_BODY, ) self.subsonicupdate = subsonicupdate.SubsonicUpdate() PING_BODY = """ { "subsonic-response": { "status": "failed", "version": "1.15.0" } } """ SUCCESS_BODY = """ { "subsonic-response": { "status": "ok", "version": "1.15.0", "scanStatus": { "scanning": true, "count": 1000 } } } """ FAILED_BODY = """ { "subsonic-response": { "status": "failed", "version": "1.15.0", "error": { "code": 40, "message": "Wrong username or password." } } } """ ERROR_BODY = """ { "timestamp": 1599185854498, "status": 404, "error": "Not Found", "message": "No message available", "path": "/rest/startScn" } """ @responses.activate def test_start_scan(self): """Tests success path based on best case scenario.""" responses.add( responses.GET, "http://localhost:4040/rest/startScan", status=200, body=self.SUCCESS_BODY, ) self.subsonicupdate.start_scan(self.lib) @responses.activate def test_start_scan_failed_bad_credentials(self): """Tests failed path based on bad credentials.""" responses.add( responses.GET, "http://localhost:4040/rest/startScan", status=200, body=self.FAILED_BODY, ) self.subsonicupdate.start_scan(self.lib) @responses.activate def test_start_scan_failed_not_found(self): """Tests failed path based on resource not found.""" responses.add( responses.GET, "http://localhost:4040/rest/startScan", status=404, body=self.ERROR_BODY, ) self.subsonicupdate.start_scan(self.lib) def test_start_scan_failed_unreachable(self): """Tests failed path based on service not available.""" self.subsonicupdate.start_scan(self.lib) @responses.activate def test_url_with_context_path(self): """Tests success for included with contextPath.""" config["subsonic"]["url"] = "http://localhost:4040/contextPath/" responses.add( responses.GET, "http://localhost:4040/contextPath/rest/startScan", status=200, body=self.SUCCESS_BODY, ) self.subsonicupdate.start_scan(self.lib) @responses.activate def test_url_with_trailing_forward_slash_url(self): """Tests success path based on trailing forward slash.""" config["subsonic"]["url"] = "http://localhost:4040/" responses.add( responses.GET, "http://localhost:4040/rest/startScan", status=200, body=self.SUCCESS_BODY, ) self.subsonicupdate.start_scan(self.lib) @responses.activate def test_url_with_missing_port(self): """Tests failed path based on missing port.""" config["subsonic"]["url"] = "http://localhost/airsonic" responses.add( responses.GET, "http://localhost/airsonic/rest/startScan", status=200, body=self.SUCCESS_BODY, ) self.subsonicupdate.start_scan(self.lib) @responses.activate def test_url_with_missing_schema(self): """Tests failed path based on missing schema.""" config["subsonic"]["url"] = "localhost:4040/airsonic" responses.add( responses.GET, "http://localhost:4040/rest/startScan", status=200, body=self.SUCCESS_BODY, ) self.subsonicupdate.start_scan(self.lib) @responses.activate def test_start_scan_failed_non_json_response(self): """Tests failed path based on a non-JSON server response.""" responses.add( responses.GET, "http://localhost:4040/rest/startScan", status=503, body="server unavailable", content_type="text/html", ) with self.assertLogs("beets", level="ERROR") as logs: self.subsonicupdate.start_scan(self.lib) assert "Subsonic server returned a non-JSON response" in "\n".join( logs.output ) beetbox-beets-00724b7/test/plugins/test_plexupdate.py0000664000175000017500000001620215253035401022300 0ustar pieterpieter"""Tests for the 'plexupdate' plugin.""" from __future__ import annotations import json from typing import TYPE_CHECKING from unittest import mock import pytest from beets.exceptions import UserError from beetsplug._utils.requests import SingletonMeta from beetsplug.plexupdate import ( PLEX_API, PlexAPI, PlexSession, UnauthorizedPlexError, ) if TYPE_CHECKING: from pathlib import Path from requests_mock import Mocker @pytest.fixture(autouse=True) def reset_plex_session(): """Drop the PlexSession singleton so each test gets a fresh session.""" yield SingletonMeta._instances.pop(PlexSession, None) @pytest.fixture def api(tmp_path: Path) -> PlexAPI: """PlexAPI for the local test server with a per-test token file.""" return PlexAPI( token_path=tmp_path / "plex_token.json", host="localhost", port=32400, library_name="Music", secure=False, verify=True, token_override="", ) @pytest.fixture def session(tmp_path: Path) -> PlexSession: """PlexSession bound to a token file in a per-test directory.""" return PlexSession(token_path=tmp_path / "plex_token.json") @pytest.fixture def plex_tv(requests_mock: Mocker) -> Mocker: """Mock the plex.tv PIN flow: issuing a pin and still-pending polls.""" requests_mock.post( f"{PLEX_API}/pins", json={"id": 1, "code": "ABCD", "expiresIn": 1800} ) requests_mock.get(f"{PLEX_API}/pins/1", json={"id": 1, "code": "ABCD"}) return requests_mock class TestUpdateLibrary: def test_get_named_music_section(self, requests_mock, api): requests_mock.get( "http://localhost:32400/library/sections", json={ "MediaContainer": { "Directory": [ {"key": "3", "title": "Movies"}, {"key": "2", "title": "My Music Library"}, ] } }, ) api.library_name = "My Music Library" assert api.get_music_section() == "2" def test_update_library(self, requests_mock, api): requests_mock.get( "http://localhost:32400/library/sections", json={ "MediaContainer": { "Directory": [{"key": "2", "title": "Music"}] } }, ) requests_mock.get("http://localhost:32400/library/sections/2/refresh") assert api.update_library().status_code == 200 def test_update_library_unauthorized(self, requests_mock, api): """A rejected token surfaces as an UnauthorizedPlexError.""" requests_mock.get( "http://localhost:32400/library/sections", json={ "MediaContainer": { "Directory": [{"key": "2", "title": "Music"}] } }, ) requests_mock.get( "http://localhost:32400/library/sections/2/refresh", status_code=401 ) with pytest.raises(UnauthorizedPlexError, match="reauthenticate"): api.update_library() def test_update_library_missing_section(self, requests_mock, api): # The server has no section with the configured name. requests_mock.get( "http://localhost:32400/library/sections", json={ "MediaContainer": { "Directory": [{"key": "3", "title": "Other Library"}] } }, ) with pytest.raises(UserError, match="No music library named"): api.update_library() class TestPlexSession: def test_session_saves_token(self, session): session.save_token({"X-Plex-Token": "TOKEN123"}) assert session.token == "TOKEN123" assert session.load_token() == { "X-Plex-Token": "TOKEN123", "client_identifier": session.client_id, } def test_wait_for_login_timeout(self, plex_tv, session): # The pin never gets an auth token. with mock.patch("beetsplug.plexupdate.time.sleep"): assert session.wait_for_login(1, timeout=1) is None def test_request_attaches_token_to_local_server( self, requests_mock, session ): """The stored token is sent to the local server.""" requests_mock.get("http://localhost:32400/library/sections", json={}) session.save_token({"X-Plex-Token": "TOKEN123"}) session.get("http://localhost:32400/library/sections") assert ( requests_mock.request_history[0].headers["X-Plex-Token"] == "TOKEN123" ) def test_request_prefers_configured_token(self, requests_mock, tmp_path): """The configured token wins over the stored plex.tv token.""" session = PlexSession( token_path=tmp_path / "plex_token.json", token_override="CONFIG_TOKEN", ) session.save_token({"X-Plex-Token": "TOKEN123"}) requests_mock.get("http://localhost:32400/library/sections", json={}) session.get("http://localhost:32400/library/sections") assert ( requests_mock.request_history[0].headers["X-Plex-Token"] == "CONFIG_TOKEN" ) class TestUIAuthenticateFlow: def test_ui_authenticate_flow(self, requests_mock, plex_tv, api): # The first poll is still pending, the second grants access. requests_mock.get( f"{PLEX_API}/pins/1", response_list=[ {"json": {"id": 1, "code": "ABCD"}}, {"json": {"id": 1, "code": "ABCD", "authToken": "TOKEN123"}}, ], ) with ( mock.patch("beetsplug.plexupdate.time.sleep"), mock.patch("beetsplug.plexupdate.webbrowser.open") as open_mock, ): api.ui_authenticate_flow() open_mock.assert_called_once() # The pin request carries the identifying headers. request = requests_mock.request_history[0] assert ( request.headers["X-Plex-Client-Identifier"] == api.session.client_id ) # The access token is persisted for later runs. assert api.session.token == "TOKEN123" assert json.loads( api.session.token_path.read_text(encoding="utf-8") ) == { "X-Plex-Token": "TOKEN123", "client_identifier": api.session.client_id, } def test_ui_authenticate_flow_timeout(self, plex_tv, api): with ( mock.patch("beetsplug.plexupdate.time.sleep"), mock.patch("beetsplug.plexupdate.webbrowser.open"), mock.patch.object(api.session, "wait_for_login", return_value=None), ): with pytest.raises(UserError): api.ui_authenticate_flow() # No token is stored when the login is not completed. assert api.session.token is None def test_ui_authenticate_flow_network_error(self, requests_mock, api): # A failing plex.tv request surfaces as a UserError instead of a # raw requests exception. requests_mock.post(f"{PLEX_API}/pins", status_code=500) with pytest.raises(UserError, match="Plex login flow failed"): api.ui_authenticate_flow() beetbox-beets-00724b7/test/plugins/test_zero.py0000664000175000017500000002177715253035401021121 0ustar pieterpieter"""Tests for the 'zero' plugin""" from mediafile import MediaFile from beets.library import Item from beets.test.helper import IOMixin, PluginTestCase from beetsplug.zero import ZeroPlugin class ZeroPluginTest(IOMixin, PluginTestCase): plugin = "zero" preload_plugin = False def test_no_patterns(self): item = self.add_item_fixture( comments="test comment", title="Title", month=1, year=2000 ) item.write() with self.configure_plugin({"fields": ["comments", "month"]}): item.write() mf = MediaFile(item.filepath) assert mf.comments is None assert mf.month is None assert mf.title == "Title" assert mf.year == 2000 def test_pattern_match(self): item = self.add_item_fixture(comments="encoded by encoder") item.write() with self.configure_plugin( {"fields": ["comments"], "comments": ["encoded by"]} ): item.write() mf = MediaFile(item.filepath) assert mf.comments is None def test_pattern_nomatch(self): item = self.add_item_fixture(comments="recorded at place") item.write() with self.configure_plugin( {"fields": ["comments"], "comments": ["encoded_by"]} ): item.write() mf = MediaFile(item.filepath) assert mf.comments == "recorded at place" def test_do_not_change_database(self): item = self.add_item_fixture(year=2000) item.write() with self.configure_plugin({"fields": ["year"]}): item.write() assert item["year"] == 2000 def test_change_database(self): item = self.add_item_fixture(year=2000) item.write() with self.configure_plugin( {"fields": ["year"], "update_database": True} ): item.write() assert item["year"] == 0 def test_album_art(self): path = self.create_mediafile_fixture(images=["jpg"]) item = Item.from_path(path) with self.configure_plugin({"fields": ["images"]}): item.write() mf = MediaFile(path) assert not mf.images def test_auto_false(self): item = self.add_item_fixture(year=2000) item.write() with self.configure_plugin( {"fields": ["year"], "update_database": True, "auto": False} ): item.write() assert item["year"] == 2000 def test_subcommand_update_database_true(self): item = self.add_item_fixture( year=2016, day=13, month=3, comments="test comment" ) item.write() item_id = item.id with self.configure_plugin( {"fields": ["comments"], "update_database": True, "auto": False} ): self.io.addinput("y") self.run_command("zero") mf = MediaFile(item.filepath) item = self.lib.get_item(item_id) assert item["year"] == 2016 assert mf.year == 2016 assert mf.comments is None assert item["comments"] == "" def test_subcommand_update_database_false(self): item = self.add_item_fixture( year=2016, day=13, month=3, comments="test comment" ) item.write() item_id = item.id with self.configure_plugin( {"fields": ["comments"], "update_database": False, "auto": False} ): self.io.addinput("y") self.run_command("zero") mf = MediaFile(item.filepath) item = self.lib.get_item(item_id) assert item["year"] == 2016 assert mf.year == 2016 assert item["comments"] == "test comment" assert mf.comments is None def test_subcommand_query_include(self): item = self.add_item_fixture( year=2016, day=13, month=3, comments="test comment" ) item.write() with self.configure_plugin( {"fields": ["comments"], "update_database": False, "auto": False} ): self.run_command("zero", "year: 2016") mf = MediaFile(item.filepath) assert mf.year == 2016 assert mf.comments is None def test_subcommand_query_exclude(self): item = self.add_item_fixture( year=2016, day=13, month=3, comments="test comment" ) item.write() with self.configure_plugin( {"fields": ["comments"], "update_database": False, "auto": False} ): self.run_command("zero", "year: 0000") mf = MediaFile(item.filepath) assert mf.year == 2016 assert mf.comments == "test comment" def test_no_fields(self): item = self.add_item_fixture(year=2016) item.write() mediafile = MediaFile(item.filepath) assert mediafile.year == 2016 item_id = item.id with self.configure_plugin({"fields": []}): self.io.addinput("y") self.run_command("zero") item = self.lib.get_item(item_id) assert item["year"] == 2016 assert mediafile.year == 2016 def test_whitelist_and_blacklist(self): item = self.add_item_fixture(year=2016) item.write() mf = MediaFile(item.filepath) assert mf.year == 2016 item_id = item.id with self.configure_plugin( {"fields": ["year"], "keep_fields": ["comments"]} ): self.io.addinput("y") self.run_command("zero") item = self.lib.get_item(item_id) assert item["year"] == 2016 assert mf.year == 2016 def test_keep_fields(self): item = self.add_item_fixture(year=2016, comments="test comment") tags = {"comments": "test comment", "year": 2016} with self.configure_plugin( {"fields": None, "keep_fields": ["year"], "update_database": True} ): z = ZeroPlugin() z.write_event(item, item.path, tags) assert tags["comments"] is None assert tags["year"] == 2016 def test_keep_fields_removes_preserved_tags(self): self.config["zero"]["keep_fields"] = ["year"] self.config["zero"]["fields"] = None self.config["zero"]["update_database"] = True z = ZeroPlugin() assert "id" not in z.fields_to_progs def test_fields_removes_preserved_tags(self): self.config["zero"]["fields"] = ["year id"] self.config["zero"]["update_database"] = True z = ZeroPlugin() assert "id" not in z.fields_to_progs def test_omit_single_disc_with_tags_single(self): item = self.add_item_fixture( disctotal=1, disc=1, comments="test comment" ) item.write() with self.configure_plugin( {"omit_single_disc": True, "fields": ["comments"]} ): item.write() mf = MediaFile(item.filepath) assert mf.comments is None assert mf.disc is None assert mf.disctotal is None def test_omit_single_disc_with_tags_multi(self): item = self.add_item_fixture( disctotal=4, disc=1, comments="test comment" ) item.write() with self.configure_plugin( {"omit_single_disc": True, "fields": ["comments"]} ): item.write() mf = MediaFile(item.filepath) assert mf.comments is None assert mf.disc == 1 assert mf.disctotal == 4 def test_omit_single_disc_only_change_single(self): item = self.add_item_fixture(disctotal=1, disc=1) item.write() with self.configure_plugin({"omit_single_disc": True}): item.write() mf = MediaFile(item.filepath) assert mf.disc is None assert mf.disctotal is None def test_omit_single_disc_only_change_multi(self): item = self.add_item_fixture(disctotal=4, disc=1) item.write() with self.configure_plugin({"omit_single_disc": True}): item.write() mf = MediaFile(item.filepath) assert mf.disc == 1 assert mf.disctotal == 4 def test_empty_query_n_response_no_changes(self): item = self.add_item_fixture( year=2016, day=13, month=3, comments="test comment" ) item.write() item_id = item.id with self.configure_plugin( {"fields": ["comments"], "update_database": True, "auto": False} ): self.io.addinput("n") self.run_command("zero") mf = MediaFile(item.filepath) item = self.lib.get_item(item_id) assert item["year"] == 2016 assert mf.year == 2016 assert mf.comments == "test comment" assert item["comments"] == "test comment" def test_keep_fields_images_preserves_art(self): path = self.create_mediafile_fixture(images=["jpg"]) item = Item.from_path(path) with self.configure_plugin({"fields": None, "keep_fields": ["images"]}): item.write() mf = MediaFile(path) assert mf.images, ( "images should be preserved when 'images' is in keep_fields" ) beetbox-beets-00724b7/test/plugins/test_thumbnails.py0000664000175000017500000002125315253035401022275 0ustar pieterpieterimport os.path from unittest.mock import Mock, call, patch import pytest from beets.test.helper import BeetsTestCase from beets.util import syspath from beetsplug.thumbnails import ( LARGE_DIR, NORMAL_DIR, GioURI, PathlibURI, ThumbnailsPlugin, ) class ThumbnailsTest(BeetsTestCase): @patch("beetsplug.thumbnails.ArtResizer") @patch("beetsplug.thumbnails.ThumbnailsPlugin._check_local_ok", Mock()) @patch("beetsplug.thumbnails.os.stat") def test_add_tags(self, mock_stat, mock_artresizer): plugin = ThumbnailsPlugin() plugin.get_uri = Mock( side_effect={b"/path/to/cover": "COVER_URI"}.__getitem__ ) artpath = b"/path/to/cover" mock_stat.return_value.st_mtime = 12345 plugin.add_tags(artpath, b"/path/to/thumbnail") metadata = {"Thumb::URI": "COVER_URI", "Thumb::MTime": "12345"} mock_artresizer.shared.write_metadata.assert_called_once_with( b"/path/to/thumbnail", metadata ) mock_stat.assert_called_once_with(syspath(artpath)) @patch("beetsplug.thumbnails.os") @patch("beetsplug.thumbnails.ArtResizer") @patch("beetsplug.thumbnails.GioURI") def test_check_local_ok(self, mock_giouri, mock_artresizer, mock_os): # test local resizing capability mock_artresizer.shared.local = False mock_artresizer.shared.can_write_metadata = False plugin = ThumbnailsPlugin() assert not plugin._check_local_ok() # test dirs creation mock_artresizer.shared.local = True mock_artresizer.shared.can_write_metadata = True def exists(path): if path == syspath(NORMAL_DIR): return False if path == syspath(LARGE_DIR): return True raise ValueError(f"unexpected path {path!r}") mock_os.path.exists = exists plugin = ThumbnailsPlugin() mock_os.makedirs.assert_called_once_with(syspath(NORMAL_DIR)) assert plugin._check_local_ok() # test metadata writer function mock_os.path.exists = lambda _: True mock_artresizer.shared.local = True mock_artresizer.shared.can_write_metadata = False with pytest.raises(RuntimeError): ThumbnailsPlugin() mock_artresizer.shared.local = True mock_artresizer.shared.can_write_metadata = True assert ThumbnailsPlugin()._check_local_ok() # test URI getter function giouri_inst = mock_giouri.return_value giouri_inst.available = True assert ThumbnailsPlugin().get_uri == giouri_inst.uri giouri_inst.available = False assert ThumbnailsPlugin().get_uri.__self__.__class__ == PathlibURI @patch("beetsplug.thumbnails.ThumbnailsPlugin._check_local_ok", Mock()) @patch("beetsplug.thumbnails.ArtResizer") @patch("beets.util.syspath", Mock(side_effect=lambda x: x)) @patch("beetsplug.thumbnails.os") @patch("beetsplug.thumbnails.shutil") def test_make_cover_thumbnail(self, mock_shutils, mock_os, mock_artresizer): thumbnail_dir = os.path.normpath(b"/thumbnail/dir") md5_file = os.path.join(thumbnail_dir, b"md5") artpath = os.path.normpath(b"/path/to/art") path_to_resized_art = os.path.normpath(b"/path/to/resized/artwork") mock_os.path.join = os.path.join # don't mock that function plugin = ThumbnailsPlugin() plugin.add_tags = Mock() album = Mock(artpath=artpath) plugin.thumbnail_file_name = Mock(return_value=b"md5") mock_os.path.exists.return_value = False mock_resize = mock_artresizer.shared.resize mock_resize.return_value = path_to_resized_art plugin.make_cover_thumbnail(album, artpath, 12345, thumbnail_dir) mock_os.path.exists.assert_called_once_with(syspath(md5_file)) mock_resize.assert_called_once_with(12345, artpath, md5_file) plugin.add_tags.assert_called_once_with(artpath, path_to_resized_art) mock_shutils.move.assert_called_once_with( syspath(path_to_resized_art), syspath(md5_file) ) # now test with recent thumbnail & with force mock_os.path.exists.return_value = True plugin.force = False mock_resize.reset_mock() def os_stat(target): if target == syspath(md5_file): return Mock(st_mtime=3) if target == syspath(artpath): return Mock(st_mtime=2) raise ValueError(f"invalid target {target}") mock_os.stat.side_effect = os_stat plugin.make_cover_thumbnail(album, artpath, 12345, thumbnail_dir) assert mock_resize.call_count == 0 # and with force plugin.config["force"] = True plugin.make_cover_thumbnail(album, artpath, 12345, thumbnail_dir) mock_resize.assert_called_once_with(12345, artpath, md5_file) @patch("beetsplug.thumbnails.ThumbnailsPlugin._check_local_ok", Mock()) def test_make_dolphin_cover_thumbnail(self): plugin = ThumbnailsPlugin() tmp = self.temp_path album = Mock( path=os.fsencode(tmp), artpath=os.fsencode(tmp / "cover.jpg") ) plugin.make_dolphin_cover_thumbnail(album.path, album.artpath) filename = tmp / ".directory" assert filename.read_text() == "[Desktop Entry]\nIcon=./cover.jpg" # not rewritten when it already exists (yup that's a big limitation) album.artpath = b"/my/awesome/art.tiff" plugin.make_dolphin_cover_thumbnail(album.path, album.artpath) assert filename.read_text() == "[Desktop Entry]\nIcon=./cover.jpg" @patch("beetsplug.thumbnails.ThumbnailsPlugin._check_local_ok", Mock()) @patch("beetsplug.thumbnails.ArtResizer") def test_process_album(self, mock_artresizer): get_size = mock_artresizer.shared.get_size plugin = ThumbnailsPlugin() make_cover = plugin.make_cover_thumbnail = Mock(return_value=True) make_dolphin = plugin.make_dolphin_cover_thumbnail = Mock() # no art album = Mock(artpath=None) plugin.process_album(album) assert get_size.call_count == 0 assert make_dolphin.call_count == 0 # cannot get art size album.artpath = b"/path/to/art" get_size.return_value = None plugin.process_album(album) get_size.assert_called_once_with(b"/path/to/art") assert make_cover.call_count == 0 # dolphin tests plugin.config["dolphin"] = False plugin.process_album(album) assert make_dolphin.call_count == 0 plugin.config["dolphin"] = True plugin.process_album(album) make_dolphin.assert_called_once_with(album.path, album.artpath) # small art get_size.return_value = 200, 200 plugin.process_album(album) make_cover.assert_called_once_with( album, album.artpath, 128, NORMAL_DIR ) # big art make_cover.reset_mock() get_size.return_value = 500, 500 plugin.process_album(album) make_cover.assert_has_calls( [ call(album, album.artpath, 128, NORMAL_DIR), call(album, album.artpath, 256, LARGE_DIR), ], any_order=True, ) @patch("beetsplug.thumbnails.ThumbnailsPlugin._check_local_ok", Mock()) def test_invokations(self): plugin = ThumbnailsPlugin() plugin.process_album = Mock() album = Mock() plugin.process_album.reset_mock() lib = Mock() album2 = Mock() lib.albums.return_value = [album, album2] plugin.process_query(lib, Mock(), None) plugin.process_album.assert_has_calls( [call(album), call(album2)], any_order=True ) @patch("beetsplug.thumbnails.BaseDirectory") def test_thumbnail_file_name(self, mock_basedir): plug = ThumbnailsPlugin() plug.get_uri = Mock(return_value="file:///my/uri") assert ( plug.thumbnail_file_name(b"idontcare") == b"9488f5797fbe12ffb316d607dfd93d04.png" ) def test_uri(self): gio = GioURI() if not gio.available: self.skipTest("GIO library not found") import ctypes with pytest.raises(ctypes.ArgumentError): gio.uri("/foo") assert gio.uri(b"/foo") == "file:///foo" assert gio.uri(b"/foo!") == "file:///foo!" assert ( gio.uri(b"/music/\xec\x8b\xb8\xec\x9d\xb4") == "file:///music/%EC%8B%B8%EC%9D%B4" ) class TestPathlibURI: """Test PathlibURI class""" def test_uri(self): test_uri = PathlibURI() # test it won't break if we pass it bytes for a path test_uri.uri(b"/") beetbox-beets-00724b7/test/plugins/test_replace.py0000664000175000017500000000716415253035401021547 0ustar pieterpieterimport shutil from pathlib import Path import pytest from mediafile import MediaFile from beets.exceptions import UserError from beets.test import _common from beets.test.helper import PluginTestHelper from beetsplug.replace import ReplacePlugin replace = ReplacePlugin() class TestReplaceCommand(PluginTestHelper): plugin = "replace" def test_command_callback_accepts_cli_arguments(self): with pytest.raises(UserError, match="Usage: beet replace"): self.run_command("replace") class TestReplace: @pytest.fixture(autouse=True) def _fake_dir(self, tmp_path): self.fake_dir = tmp_path @pytest.fixture(autouse=True) def _fake_file(self, tmp_path): self.fake_file = tmp_path def test_path_is_dir(self): fake_directory = self.fake_dir / "fakeDir" fake_directory.mkdir() with pytest.raises(UserError): replace.file_check(fake_directory) def test_path_is_unsupported_file(self): fake_file = self.fake_file / "fakefile.txt" fake_file.write_text("test", encoding="utf-8") with pytest.raises(UserError): replace.file_check(fake_file) def test_path_is_supported_file(self): dest = self.fake_file / "full.mp3" src = _common.RSRC / "full.mp3" shutil.copyfile(src, dest) mediafile = MediaFile(dest) mediafile.albumartist = "AAA" mediafile.disctitle = "DDD" mediafile.genres = ["a", "b", "c"] mediafile.composer = None mediafile.save() replace.file_check(Path(str(dest))) def test_select_song_valid_choice(self, monkeypatch, capfd): songs = ["Song A", "Song B", "Song C"] monkeypatch.setattr("builtins.input", lambda _: "2") selected_song = replace.select_song(songs) captured = capfd.readouterr() assert "1. Song A" in captured.out assert "2. Song B" in captured.out assert "3. Song C" in captured.out assert selected_song == "Song B" def test_select_song_cancel(self, monkeypatch): songs = ["Song A", "Song B", "Song C"] monkeypatch.setattr("builtins.input", lambda _: "0") selected_song = replace.select_song(songs) assert selected_song is None def test_select_song_invalid_then_valid(self, monkeypatch, capfd): songs = ["Song A", "Song B", "Song C"] inputs = iter(["invalid", "4", "3"]) monkeypatch.setattr("builtins.input", lambda _: next(inputs)) selected_song = replace.select_song(songs) captured = capfd.readouterr() assert "Invalid input. Please type in a number." in captured.out assert ( "Invalid choice. Please enter a number between 1 and 3." in captured.out ) assert selected_song == "Song C" def test_confirm_replacement_file_not_exist(self): class Song: path = b"test123321.txt" song = Song() with pytest.raises(UserError): replace.confirm_replacement("test", song) def test_confirm_replacement_yes(self, monkeypatch): src = _common.RSRC / "full.mp3" monkeypatch.setattr("builtins.input", lambda _: "YES ") class Song: path = str(src).encode() song = Song() assert replace.confirm_replacement("test", song) is True def test_confirm_replacement_no(self, monkeypatch): src = _common.RSRC / "full.mp3" monkeypatch.setattr("builtins.input", lambda _: "test123") class Song: path = str(src).encode() song = Song() assert replace.confirm_replacement("test", song) is False beetbox-beets-00724b7/test/plugins/test_aura.py0000664000175000017500000001230315253035401021053 0ustar pieterpieterfrom __future__ import annotations from http import HTTPStatus from typing import TYPE_CHECKING, Any import pytest from beets.dbcore.types import MULTI_VALUE_DELIMITER if TYPE_CHECKING: from flask.testing import Client @pytest.fixture(scope="session") def helper(session_helper): """Keep the helper temp dir alive past the module-scoped Flask app. ``create_app`` opens a configured SQLite library before tests replace it with ``helper.lib``. On Windows, module teardown can otherwise try to delete ``library.db`` while the app still holds a file handle. The API assertions filter known data, so sharing state for the session is harmless. """ return session_helper @pytest.fixture(scope="module") def app(helper): from beetsplug.aura import create_app app = create_app() app.config["lib"] = helper.lib return app @pytest.fixture(scope="module") def item(helper): return helper.add_item_fixture( album="Album", title="Title", artist="Artist", albumartist="Album Artist", genres=["rock", "pop"], track=2, ) @pytest.fixture(scope="module") def album(helper, item): return helper.lib.add_album([item]) @pytest.fixture(scope="module", autouse=True) def _other_album_and_item(helper): """Add another item and album to prove that filtering works.""" item = helper.add_item_fixture( album="Other Album", title="Other Title", artist="Other Artist", albumartist="Other Album Artist", ) helper.lib.add_album([item]) class TestAuraResponse: @pytest.fixture def get_response_data(self, client: Client, item): """Return a callback accepting `endpoint` and `params` parameters.""" def get(endpoint: str, params: dict[str, str]) -> dict[str, Any] | None: """Add additional `params` and GET the given endpoint. `include` parameter is added to every call to check that the functionality that fetches related entities works. Before returning the response data, ensure that the request is successful. """ response = client.get( endpoint, query_string={"include": "tracks,artists,albums", **params}, ) assert response.status_code == HTTPStatus.OK return response.json return get @pytest.fixture(scope="class") def track_document(self, item, album): return { "type": "track", "id": str(item.id), "attributes": { "album": item.album, "albumartist": item.albumartist, "artist": item.artist, "genre": item.genres, "genres": item.genres, "size": item.filepath.stat().st_size, "title": item.title, "track": item.track, }, "relationships": { "albums": {"data": [{"id": str(album.id), "type": "album"}]}, "artists": {"data": [{"id": item.artist, "type": "artist"}]}, }, } @pytest.fixture(scope="class") def artist_document(self, item): return { "type": "artist", "id": item.artist, "attributes": {"name": item.artist}, "relationships": { "tracks": {"data": [{"id": str(item.id), "type": "track"}]} }, } @pytest.fixture(scope="class") def album_document(self, album): return { "type": "album", "id": str(album.id), "attributes": { "artist": album.albumartist, "title": album.album, "genre": album.genres, "genres": album.genres, }, "relationships": { "tracks": {"data": [{"id": str(album.id), "type": "track"}]} }, } def test_tracks( self, get_response_data, item, album_document, artist_document, track_document, ): """Test tracks response. 1. Filter by a field which has an int type. 2. Sort by a field that has no value: make sure the item is included in the response. """ data = get_response_data( "/aura/tracks", {"filter[track]": item.track, "sort": "mb_trackid"} ) assert data == { "data": [track_document], "included": [artist_document, album_document], } def test_artists( self, get_response_data, item, artist_document, track_document ): data = get_response_data( "/aura/artists", {"filter[artist]": item.artist} ) assert data == {"data": [artist_document], "included": [track_document]} def test_albums( self, get_response_data, album, album_document, track_document ): """Test albums response. 1. Filter by a field which has a list type. """ data = get_response_data( "/aura/albums", {"filter[genres]": MULTI_VALUE_DELIMITER.join(album.genres)}, ) assert data == {"data": [album_document], "included": [track_document]} beetbox-beets-00724b7/test/plugins/test_edit.py0000664000175000017500000006544215253035401021064 0ustar pieterpieterimport codecs from typing import ClassVar from unittest.mock import patch from beets.dbcore.query import TrueQuery from beets.importer import Action from beets.library import Item from beets.test.helper import ( AutotagImportTestCase, AutotagStub, BeetsTestCase, IOMixin, PluginMixin, TerminalImportMixin, ) from beetsplug.edit import EditPlugin, dump, load class ModifyFileMocker: """Helper for modifying a file, replacing or editing its contents. Used for mocking the calls to the external editor during testing. """ def __init__(self, contents=None, replacements=None): """`self.contents` and `self.replacements` are initialized here, in order to keep the rest of the functions of this class with the same signature as `EditPlugin.get_editor()`, making mocking easier. - `contents`: string with the contents of the file to be used for `overwrite_contents()` - `replacement`: dict with the in-place replacements to be used for `replace_contents()`, in the form {'previous string': 'new string'} TODO: check if it can be solved more elegantly with a decorator """ self.contents = contents self.replacements = replacements self.action = self.overwrite_contents if replacements: self.action = self.replace_contents # The two methods below mock the `edit` utility function in the plugin. def overwrite_contents(self, filename, log): """Modify `filename`, replacing its contents with `self.contents`. If `self.contents` is empty, the file remains unchanged. """ if self.contents: with codecs.open(filename, "w", encoding="utf-8") as f: f.write(self.contents) def replace_contents(self, filename, log): """Modify `filename`, reading its contents and replacing the strings specified in `self.replacements`. """ with codecs.open(filename, "r", encoding="utf-8") as f: contents = f.read() for old, new_ in self.replacements.items(): contents = contents.replace(old, new_) with codecs.open(filename, "w", encoding="utf-8") as f: f.write(contents) class EditMixin(PluginMixin): """Helper containing some common functionality used for the Edit tests.""" plugin = "edit" def assertItemFieldsModified( self, library_items, items, fields=[], allowed=["path"] ): """Assert that items in the library (`lib_items`) have different values on the specified `fields` (and *only* on those fields), compared to `items`. An empty `fields` list results in asserting that no modifications have been performed. `allowed` is a list of field changes that are ignored (they may or may not have changed; the assertion doesn't care). """ for lib_item, item in zip(library_items, items): diff_fields = [ field for field in lib_item._fields if lib_item[field] != item[field] ] assert set(diff_fields).difference(allowed) == set(fields) def run_mocked_interpreter(self, modify_file_args={}, stdin=[]): """Run the edit command during an import session, with mocked stdin and yaml writing. """ m = ModifyFileMocker(**modify_file_args) with patch("beetsplug.edit.edit", side_effect=m.action): for char in stdin: self.importer.add_choice(char) self.importer.run() def run_mocked_command(self, modify_file_args={}, stdin=[], args=[]): """Run the edit command, with mocked stdin and yaml writing, and passing `args` to `run_command`.""" m = ModifyFileMocker(**modify_file_args) with patch("beetsplug.edit.edit", side_effect=m.action): for char in stdin: self.io.addinput(char) self.run_command("edit", *args) @patch("beets.library.Item.write") class EditCommandTest(IOMixin, EditMixin, BeetsTestCase): """Black box tests for `beetsplug.edit`. Command line interaction is simulated using mocked stdin, and yaml editing via an external editor is simulated using `ModifyFileMocker`. """ TRACK_COUNT = 10 def setUp(self): super().setUp() # Add an album, storing the original fields for comparison. self.album = self.add_album_fixture(track_count=self.TRACK_COUNT) self.album_orig = {f: self.album[f] for f in self.album._fields} self.items_orig = [ {f: item[f] for f in item._fields} for item in self.album.items() ] def test_title_edit_discard(self, mock_write): """Edit title for all items in the library, then discard changes.""" # Edit track titles. self.run_mocked_command( {"replacements": {"t\u00eftle": "modified t\u00eftle"}}, # Cancel. ["c"], ) assert mock_write.call_count == 0 self.assertItemFieldsModified(self.album.items(), self.items_orig, []) def test_title_edit_apply(self, mock_write): """Edit title for all items in the library, then apply changes.""" # Edit track titles. self.run_mocked_command( {"replacements": {"t\u00eftle": "modified t\u00eftle"}}, # Apply changes. ["a"], ) assert mock_write.call_count == self.TRACK_COUNT self.assertItemFieldsModified( self.album.items(), self.items_orig, ["title", "mtime"] ) def test_single_title_edit_apply(self, mock_write): """Edit title for one item in the library, then apply changes.""" # Edit one track title. self.run_mocked_command( {"replacements": {"t\u00eftle 9": "modified t\u00eftle 9"}}, # Apply changes. ["a"], ) assert mock_write.call_count == 1 # No changes except on last item. self.assertItemFieldsModified( list(self.album.items())[:-1], self.items_orig[:-1], [] ) assert list(self.album.items())[-1].title == "modified t\u00eftle 9" def test_title_edit_keep_editing_then_apply(self, mock_write): """Edit titles, keep editing once, then apply changes.""" self.run_mocked_command( {"replacements": {"t\u00eftle": "modified t\u00eftle"}}, # keep Editing, then Apply ["e", "a"], ) assert mock_write.call_count == self.TRACK_COUNT self.assertItemFieldsModified( self.album.items(), self.items_orig, ["title", "mtime"] ) def test_title_edit_keep_editing_then_cancel(self, mock_write): """Edit titles, keep editing once, then cancel.""" self.run_mocked_command( {"replacements": {"t\u00eftle": "modified t\u00eftle"}}, # keep Editing, then Cancel ["e", "c"], ) assert mock_write.call_count == 0 self.assertItemFieldsModified(self.album.items(), self.items_orig, []) def test_noedit(self, mock_write): """Do not edit anything.""" # Do not edit anything. self.run_mocked_command( {"contents": None}, # No stdin. [], ) assert mock_write.call_count == 0 self.assertItemFieldsModified(self.album.items(), self.items_orig, []) def test_album_edit_apply(self, mock_write): """Edit the album field for all items in the library, apply changes. By design, the album should not be updated."" """ # Edit album. self.run_mocked_command( {"replacements": {"\u00e4lbum": "modified \u00e4lbum"}}, # Apply changes. ["a"], ) assert mock_write.call_count == self.TRACK_COUNT self.assertItemFieldsModified( self.album.items(), self.items_orig, ["album", "mtime"] ) # Ensure album is *not* modified. self.album.load() assert self.album.album == "\u00e4lbum" def test_single_edit_add_field(self, mock_write): """Edit the yaml file appending an extra field to the first item, then apply changes.""" # Append "foo: bar" to item with id == 2. ("id: 1" would match both # "id: 1" and "id: 10") self.run_mocked_command( {"replacements": {"id: 2": "id: 2\nfoo: bar"}}, # Apply changes. ["a"], ) assert self.lib.items("id:2")[0].foo == "bar" # Even though a flexible attribute was written (which is not directly # written to the tags), write should still be called since templates # might use it. assert mock_write.call_count == 1 def test_a_album_edit_apply(self, mock_write): """Album query (-a), edit album field, apply changes.""" self.run_mocked_command( {"replacements": {"\u00e4lbum": "modified \u00e4lbum"}}, # Apply changes. ["a"], args=["-a"], ) self.album.load() assert mock_write.call_count == self.TRACK_COUNT assert self.album.album == "modified \u00e4lbum" self.assertItemFieldsModified( self.album.items(), self.items_orig, ["album", "mtime"] ) def test_a_albumartist_edit_apply(self, mock_write): """Album query (-a), edit albumartist field, apply changes.""" self.run_mocked_command( {"replacements": {"album artist": "modified album artist"}}, # Apply changes. ["a"], args=["-a"], ) self.album.load() assert mock_write.call_count == self.TRACK_COUNT assert self.album.albumartist == "the modified album artist" self.assertItemFieldsModified( self.album.items(), self.items_orig, ["albumartist", "mtime"] ) def test_a_album_edit_preserves_missing_artpath(self, mock_write): """Album query (-a), edit album field, preserve missing artpath.""" self.config["edit"]["albumfields"] = "album artpath" self.run_mocked_command( {"replacements": {"\u00e4lbum": "modified \u00e4lbum"}}, # Apply changes. ["a"], args=["-a"], ) self.album.load() assert mock_write.call_count == self.TRACK_COUNT assert self.album.album == "modified \u00e4lbum" assert self.album.artpath is None self.assertItemFieldsModified( self.album.items(), self.items_orig, ["album", "mtime"] ) def test_malformed_yaml(self, mock_write): """Edit the yaml file incorrectly (resulting in a malformed yaml document).""" # Edit the yaml file to an invalid file. self.run_mocked_command( {"contents": "!MALFORMED"}, # Edit again to fix? No. ["n"], ) assert mock_write.call_count == 0 def test_invalid_yaml(self, mock_write): """Edit the yaml file incorrectly (resulting in a well-formed but invalid yaml document).""" # Edit the yaml file to an invalid but parseable file. self.run_mocked_command( {"contents": "wellformed: yes, but invalid"}, # No stdin. [], ) assert mock_write.call_count == 0 class ApplyDataMatchingTest(PluginMixin, BeetsTestCase): """`apply_data` must match documents to objects by their ``id`` field, not by their position in the list. A reordered or otherwise misaligned document list must not cause one object's data to be applied to a different object. """ plugin = "edit" def make_items(self): items = [] for i in (1, 2, 3): item = Item(id=i, title=f"Title {i}", track=i, artist="Artist") items.append(item) return items def test_matches_by_id_when_documents_are_reordered(self): plugin = EditPlugin() items = self.make_items() old_data = [ {"id": i.id, "title": i.title, "track": i.track} for i in items ] # The saved documents come back in a different order than `items`, # as could happen after a "keep editing" round-trip or a reordering # editor action. Only track 2's title was actually edited. new_data = [ {"id": 3, "title": "Title 3", "track": 3}, {"id": 1, "title": "Title 1", "track": 1}, {"id": 2, "title": "Modified Title 2", "track": 2}, ] plugin.apply_data(items, old_data, new_data) assert [i.title for i in items] == [ "Title 1", "Modified Title 2", "Title 3", ] assert [i.track for i in items] == [1, 2, 3] def test_ignores_document_with_missing_id(self): plugin = EditPlugin() items = self.make_items() old_data = [ {"id": i.id, "title": i.title, "track": i.track} for i in items ] # A document without an `id` must never be silently applied to an # unrelated object. new_data = [ {"title": "Header-like doc", "track": 99}, {"id": 2, "title": "Modified Title 2", "track": 2}, {"id": 3, "title": "Title 3", "track": 3}, ] plugin.apply_data(items, old_data, new_data) assert items[0].title == "Title 1" assert items[0].track == 1 def test_ignores_documents_with_duplicate_id(self): plugin = EditPlugin() items = self.make_items() old_data = [ {"id": i.id, "title": i.title, "track": i.track} for i in items ] # The user changed document 2's `id` to 1, an id that already # belongs to another document. Neither document should be applied: # we can't tell which one is legitimately item 1's data. new_data = [ {"id": 1, "title": "Title 1", "track": 1}, {"id": 1, "title": "Modified Title 2", "track": 2}, {"id": 3, "title": "Title 3", "track": 3}, ] plugin.apply_data(items, old_data, new_data) assert items[0].title == "Title 1" assert items[0].track == 1 assert items[1].title == "Title 2" assert items[1].track == 2 class AlbumHeaderFieldsTest(PluginMixin, BeetsTestCase): """`_importer_edit_album_header` must strip item-only fixed fields (title, track, path, ...), since the header is built from a single item and then applied to every item in the album. Flexible fields are not part of either model's fixed schema, so they must be left alone rather than discarded by an overly broad filter. """ plugin = "edit" class _StubTask: is_album = True def __init__(self, items): self.items = items def test_keeps_flexible_fields_but_drops_item_only_fields(self): item = Item(id=1, title="Title 1", track=1, album="Album", mood="Happy") task = self._StubTask([item]) self.config["edit"]["albumfields"] = "album mood track title" header = EditPlugin()._importer_edit_album_header(task) assert header == {"album": "Album", "mood": "Happy"} class EditDuringImporterTestCase( EditMixin, TerminalImportMixin, AutotagImportTestCase ): """TODO""" matching = AutotagStub.GOOD IGNORED: ClassVar[list[str]] = ["added", "album_id", "id", "mtime", "path"] def setUp(self): super().setUp() # Create some mediafiles, and store them for comparison. self.prepare_album_for_import(1) self.items_orig = [Item.from_path(f.path) for f in self.import_media] class EditDuringImporterNonSingletonTest(EditDuringImporterTestCase): def setUp(self): super().setUp() self.importer = self.setup_importer() def test_importer_edit_album_header_and_items(self): """Edit both the album header and per-track fields simultaneously.""" self.config["edit"]["itemfields"] = "title" self.config["edit"]["albumfields"] = "album" self.run_mocked_interpreter( { "replacements": { "Tag Album": "Modified Album", "Tag Track": "Modified Track", } }, # eDit, Apply changes. ["d", "a"], ) # All items should have the new album and new title. assert all(i.album == "Modified Album" for i in self.lib.items()) assert all("Modified Track" in i.title for i in self.lib.items()) assert self.lib.albums()[0].album == "Modified Album" def test_importer_edit_album_header_skip_no_albumfields(self): """When albumfields is empty, no header section is produced; editing works as before. """ self.config["edit"]["itemfields"] = "title" self.config["edit"]["albumfields"] = "" self.run_mocked_interpreter( {"replacements": {"Tag Track": "Edited Track"}}, # eDit, Apply changes. ["d", "a"], ) assert all("Edited Track" in i.title for i in self.lib.items()) def test_importer_edit_album_header_ignores_item_only_fields(self): """`albumfields` may be misconfigured with item-only fields (e.g. `track`, `title`, `path`) that vary per track. Those must not end up in the header, since the header gets applied to every item and would otherwise stamp one track's values onto the whole album. """ self.prepare_album_for_import(3) self.items_orig = [Item.from_path(f.path) for f in self.import_media] self.config["edit"]["itemfields"] = "track title artist album" self.config["edit"]["albumfields"] = "album albumartist track title" self.run_mocked_interpreter( {"replacements": {"Tag Album": "Modified Album"}}, # eDit, Apply changes. ["d", "a"], ) titles = [i.title for i in self.lib.items()] tracks = [i.track for i in self.lib.items()] assert len(set(titles)) == len(titles) assert len(set(tracks)) == len(tracks) assert all(i.album == "Modified Album" for i in self.lib.items()) def test_importer_edit_candidate_keeps_rejected_albumfields_in_tracks(self): """Item-only album fields remain editable in candidate tracks.""" self.config["edit"]["albumfields"] = "album title track" self.config["edit"]["itemfields"] = "album title track" seen_docs = {} def inspect_and_edit(filename, log): with codecs.open(filename, encoding="utf-8") as f: docs = load(f.read()) headers = [doc for doc in docs if "id" not in doc] tracks = [doc for doc in docs if "id" in doc] seen_docs["headers"] = headers seen_docs["tracks"] = tracks tracks[0]["title"] = "Issue 6953 edited title" with codecs.open(filename, "w", encoding="utf-8") as f: f.write(dump(docs)) with patch("beetsplug.edit.edit", side_effect=inspect_and_edit): self.importer.add_choice("c") self.importer.add_choice("1") self.importer.add_choice("a") self.importer.run() assert len(seen_docs["headers"]) == 1 assert set(seen_docs["headers"][0]) == {"album"} assert len(seen_docs["tracks"]) == 1 assert set(seen_docs["tracks"][0]) == {"id", "title", "track"} items = list(self.lib.items()) assert len(items) == 1 assert items[0].title == "Issue 6953 edited title" assert items[0].mb_trackid == "match 1" albums = list(self.lib.albums()) assert len(albums) == 1 assert albums[0].mb_albumid == "albumid" def test_importer_edit_album_header_albumartist(self): """Edit albumartist in the header (default albumfields).""" self.run_mocked_interpreter( {"replacements": {"Tag Artist": "Modified Artist"}}, # eDit, Apply changes. ["d", "a"], ) assert all( i.albumartist is not None and "Modified Artist" in i.albumartist for i in self.lib.items() ) or all( i.albumartist is None and "Tag Artist" in i.artist for i in self.lib.items() ) def test_importer_edit_album_header_reordered(self): """If the user moves the album header document below the track documents, it must still be recognized as the header (identified by the absence of an `id` field) rather than misapplying a track's fields to every item. """ self.config["edit"]["itemfields"] = "title" self.config["edit"]["albumfields"] = "album" def reorder_and_edit(filename, log): with codecs.open(filename, encoding="utf-8") as f: docs = load(f.read()) header = next(d for d in docs if "id" not in d) tracks = [d for d in docs if "id" in d] header["album"] = "Modified Album" with codecs.open(filename, "w", encoding="utf-8") as f: f.write(dump([*tracks, header])) with patch("beetsplug.edit.edit", side_effect=reorder_and_edit): self.importer.add_choice("d") self.importer.add_choice("a") self.importer.run() assert all(i.album == "Modified Album" for i in self.lib.items()) assert all("Tag Track" in i.title for i in self.lib.items()) def test_edit_apply_asis(self): """Edit the album field for all items in the library, apply changes, using the original item tags. """ # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Tag Track": "Edited Track"}}, # eDit, Apply changes. ["d", "a"], ) # Check that only the 'title' field is modified. self.assertItemFieldsModified( self.lib.items(), self.items_orig, ["title", "albumartist", "albumartists"], [*self.IGNORED, "mb_albumartistid", "mb_albumartistids"], ) assert all("Edited Track" in i.title for i in self.lib.items()) # Ensure album is *not* fetched from a candidate. assert self.lib.albums()[0].mb_albumid == "" def test_edit_discard_asis(self): """Edit the album field for all items in the library, discard changes, using the original item tags. """ # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Tag Track": "Edited Track"}}, # eDit, Cancel, Use as-is. ["d", "c", "u"], ) # Check that nothing is modified, the album is imported ASIS. self.assertItemFieldsModified( self.lib.items(), self.items_orig, [], [*self.IGNORED, "albumartist", "mb_albumartistid"], ) assert all("Tag Track" in i.title for i in self.lib.items()) # Ensure album is *not* fetched from a candidate. assert self.lib.albums()[0].mb_albumid == "" def test_edit_apply_candidate(self): """Edit the album field for all items in the library, apply changes, using a candidate. """ # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Applied Track": "Edited Track"}}, # edit Candidates, 1, Apply changes. ["c", "1", "a"], ) # Check that 'title' field is modified, and other fields come from # the candidate. assert all("Edited Track " in i.title for i in self.lib.items()) assert all("match " in i.mb_trackid for i in self.lib.items()) # Ensure album is fetched from a candidate. assert "albumid" in self.lib.albums()[0].mb_albumid def test_edit_retag_apply(self): """Import the album using a candidate, then retag and edit and apply changes. """ self.run_mocked_interpreter( {}, # 1, Apply changes. ["1", Action.APPLY], ) # Retag and edit track titles. On retag, the importer will reset items # ids but not the db connections. self.importer.paths = [] self.importer.query = TrueQuery() self.run_mocked_interpreter( {"replacements": {"Applied Track": "Edited Track"}}, # eDit, Apply changes. ["d", "a"], ) # Check that 'title' field is modified, and other fields come from # the candidate. assert all("Edited Track " in i.title for i in self.lib.items()) assert all("match " in i.mb_trackid for i in self.lib.items()) # Ensure album is fetched from a candidate. assert "albumid" in self.lib.albums()[0].mb_albumid def test_edit_discard_candidate(self): """Edit the album field for all items in the library, discard changes, using a candidate. """ # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Applied Track": "Edited Track"}}, # edit Candidates, 1, Apply changes. ["c", "1", "a"], ) # Check that 'title' field is modified, and other fields come from # the candidate. assert all("Edited Track " in i.title for i in self.lib.items()) assert all("match " in i.mb_trackid for i in self.lib.items()) # Ensure album is fetched from a candidate. assert "albumid" in self.lib.albums()[0].mb_albumid def test_edit_apply_candidate_singleton(self): """Edit the album field for all items in the library, apply changes, using a candidate and singleton mode. """ # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Applied Track": "Edited Track"}}, # edit Candidates, 1, Apply changes, aBort. ["c", "1", "a", "b"], ) # Check that 'title' field is modified, and other fields come from # the candidate. assert all("Edited Track " in i.title for i in self.lib.items()) assert all("match " in i.mb_trackid for i in self.lib.items()) class EditDuringImporterSingletonTest(EditDuringImporterTestCase): def setUp(self): super().setUp() self.importer = self.setup_singleton_importer() def test_edit_apply_asis_singleton(self): """Edit the album field for all items in the library, apply changes, using the original item tags and singleton mode. """ # Edit track titles. self.run_mocked_interpreter( {"replacements": {"Tag Track": "Edited Track"}}, # eDit, Apply changes, aBort. ["d", "a", "b"], ) # Check that only the 'title' field is modified. self.assertItemFieldsModified( self.lib.items(), self.items_orig, ["title"], [*self.IGNORED, "albumartist", "mb_albumartistid"], ) assert all("Edited Track" in i.title for i in self.lib.items()) beetbox-beets-00724b7/test/plugins/test_autobpm.py0000664000175000017500000000337315253035401021601 0ustar pieterpieterimport pytest from beets.test.helper import ImportHelper, PluginTestHelper pytestmark = pytest.mark.requires_import("librosa") class TestAutoBPMPlugin(ImportHelper, PluginTestHelper): plugin = "autobpm" @pytest.fixture def item(self): return self.add_item_fixture() @pytest.fixture def importer(self): self.import_media = [] self.prepare_album_for_import(1) track = self.import_media[0] track.bpm = None track.save() return self.setup_importer(autotag=False) def test_command(self, item): item.bpm = None item.store() self.run_command("autobpm") item.load() assert item.bpm == 117 def test_command_force(self, item): item.bpm = 10 item.store() self.run_command("autobpm") item.load() assert item.bpm == 10 self.run_command("autobpm", "--force") item.load() assert item.bpm == 117 def test_command_overwrite(self, item): item.bpm = 10 item.store() self.unload_plugins() self.config[self.plugin]["overwrite"] = True self.load_plugins() self.run_command("autobpm") item.load() assert item.bpm == 117 def test_command_quiet(self, item, caplog): item.bpm = 10 item.store() with caplog.at_level("DEBUG"): self.run_command("autobpm", "--quiet") assert not any("already exists" in msg for msg in caplog.messages) with caplog.at_level("DEBUG"): self.run_command("autobpm") assert any("already exists" in msg for msg in caplog.messages) def test_import(self, importer): importer.run() assert self.lib.items().get().bpm == 117 beetbox-beets-00724b7/test/plugins/test_hook.py0000664000175000017500000001001715253035401021063 0ustar pieterpieterfrom __future__ import annotations import os import sys from pathlib import Path from typing import TYPE_CHECKING, ClassVar import pytest from beets import plugins from beets.test.helper import PluginTestHelper if TYPE_CHECKING: from collections.abc import Callable from beets.events import EventType class HookTestCase(PluginTestHelper): plugin = "hook" preload_plugin = False def _get_hook(self, event: str, command: str) -> dict[str, str]: return {"event": event, "command": command} class TestHookLogs(HookTestCase): HOOK: EventType = "write" def _configure_hook(self, command: str) -> None: config = {"hooks": [self._get_hook(self.HOOK, command)]} with self.configure_plugin(config): plugins.send(self.HOOK) # type: ignore[arg-type] def test_hook_empty_command(self, caplog: pytest.LogCaptureFixture): with caplog.at_level("DEBUG"): self._configure_hook("") assert 'invalid command ""' in caplog.messages # FIXME: fails on windows @pytest.mark.skipif(sys.platform == "win32", reason="win32") def test_hook_non_zero_exit(self, caplog: pytest.LogCaptureFixture): with caplog.at_level("DEBUG"): self._configure_hook('sh -c "exit 1"') assert f"hook for {self.HOOK} exited with status 1" in caplog.messages def test_hook_non_existent_command(self, caplog: pytest.LogCaptureFixture): with caplog.at_level("DEBUG"): self._configure_hook("non-existent-command") assert f"hook for {self.HOOK} failed: " in caplog.text # The error message is different for each OS. Unfortunately the text is # different in each case, where the only shared text is the string # 'file' and substring 'Err' assert "Err" in caplog.text assert "file" in caplog.text class TestHookCommand(HookTestCase): EVENTS: ClassVar[list[EventType]] = ["write", "after_write"] @pytest.fixture(autouse=True) def setUp(self): self.paths = [str(self.temp_path / e) for e in self.EVENTS] def _test_command( self, make_test_path: Callable[[str, str], str], send_path_kwarg: bool = False, ) -> None: """Check that each of the configured hooks is executed. Configure hooks for each event: 1. Use the given 'make_test_path' callable to create a test path from the event and the original path. 2. Configure a hook with a command to touch this path. For each of the original paths: 1. Send a test event 2. Assert that a file has been created under the original path, which proves that the configured hook command has been executed. """ events_with_paths: list[tuple[EventType, str]] = list( zip(self.EVENTS, self.paths) ) hooks = [ self._get_hook(e, f"touch {make_test_path(e, p)}") for e, p in events_with_paths ] with self.configure_plugin({"hooks": hooks}): for event, path in events_with_paths: if send_path_kwarg: plugins.send(event, path=path) # type: ignore[call-overload] else: plugins.send(event) # type: ignore[arg-type] assert Path(os.fsdecode(path)).is_file() @pytest.mark.skipif(sys.platform == "win32", reason="win32") def test_hook_no_arguments(self): self._test_command(lambda _, p: p) @pytest.mark.skipif(sys.platform == "win32", reason="win32") def test_hook_event_substitution(self): self._test_command(lambda e, p: p.replace(e, "{event}")) @pytest.mark.skipif(sys.platform == "win32", reason="win32") def test_hook_argument_substitution(self): self._test_command(lambda *_: "{path}", send_path_kwarg=True) @pytest.mark.skipif(sys.platform == "win32", reason="win32") def test_hook_bytes_interpolation(self): self.paths = [p.encode() for p in self.paths] self._test_command(lambda *_: "{path}", send_path_kwarg=True) beetbox-beets-00724b7/test/plugins/test_embyupdate.py0000664000175000017500000002165315253035401022272 0ustar pieterpieterimport responses from beets.test.helper import PluginTestCase from beetsplug import embyupdate class EmbyUpdateTest(PluginTestCase): plugin = "embyupdate" def setUp(self): super().setUp() self.config["emby"] = { "host": "localhost", "port": 8096, "username": "username", "password": "password", } def test_api_url_only_name(self): assert ( embyupdate.api_url( self.config["emby"]["host"].get(), self.config["emby"]["port"].get(), "/Library/Refresh", ) == "http://localhost:8096/Library/Refresh?format=json" ) def test_api_url_http(self): assert ( embyupdate.api_url( "http://localhost", self.config["emby"]["port"].get(), "/Library/Refresh", ) == "http://localhost:8096/Library/Refresh?format=json" ) def test_api_url_https(self): assert ( embyupdate.api_url( "https://localhost", self.config["emby"]["port"].get(), "/Library/Refresh", ) == "https://localhost:8096/Library/Refresh?format=json" ) def test_password_data(self): assert embyupdate.password_data( self.config["emby"]["username"].get(), self.config["emby"]["password"].get(), ) == { "username": "username", "password": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", "passwordMd5": "5f4dcc3b5aa765d61d8327deb882cf99", } def test_create_header_no_token(self): assert embyupdate.create_headers( "e8837bc1-ad67-520e-8cd2-f629e3155721" ) == { "x-emby-authorization": ( "MediaBrowser " 'UserId="e8837bc1-ad67-520e-8cd2-f629e3155721", ' 'Client="other", ' 'Device="beets", ' 'DeviceId="beets", ' 'Version="0.0.0"' ) } def test_create_header_with_token(self): assert embyupdate.create_headers( "e8837bc1-ad67-520e-8cd2-f629e3155721", token="abc123" ) == { "x-emby-authorization": ( "MediaBrowser " 'UserId="e8837bc1-ad67-520e-8cd2-f629e3155721", ' 'Client="other", ' 'Device="beets", ' 'DeviceId="beets", ' 'Version="0.0.0"' ), "x-mediabrowser-token": "abc123", } @responses.activate def test_get_token(self): body = ( '{"User":{"Name":"username", ' '"ServerId":"1efa5077976bfa92bc71652404f646ec",' '"Id":"2ec276a2642e54a19b612b9418a8bd3b","HasPassword":true,' '"HasConfiguredPassword":true,' '"HasConfiguredEasyPassword":false,' '"LastLoginDate":"2015-11-09T08:35:03.6357440Z",' '"LastActivityDate":"2015-11-09T08:35:03.6665060Z",' '"Configuration":{"AudioLanguagePreference":"",' '"PlayDefaultAudioTrack":true,"SubtitleLanguagePreference":"",' '"DisplayMissingEpisodes":false,' '"DisplayUnairedEpisodes":false,' '"GroupMoviesIntoBoxSets":false,' '"DisplayChannelsWithinViews":[],' '"ExcludeFoldersFromGrouping":[],"GroupedFolders":[],' '"SubtitleMode":"Default","DisplayCollectionsView":true,' '"DisplayFoldersView":false,"EnableLocalPassword":false,' '"OrderedViews":[],"IncludeTrailersInSuggestions":true,' '"EnableCinemaMode":true,"LatestItemsExcludes":[],' '"PlainFolderViews":[],"HidePlayedInLatest":true,' '"DisplayChannelsInline":false},' '"Policy":{"IsAdministrator":true,"IsHidden":false,' '"IsDisabled":false,"BlockedTags":[],' '"EnableUserPreferenceAccess":true,"AccessSchedules":[],' '"BlockUnratedItems":[],' '"EnableRemoteControlOfOtherUsers":false,' '"EnableSharedDeviceControl":true,' '"EnableLiveTvManagement":true,"EnableLiveTvAccess":true,' '"EnableMediaPlayback":true,' '"EnableAudioPlaybackTranscoding":true,' '"EnableVideoPlaybackTranscoding":true,' '"EnableContentDeletion":false,' '"EnableContentDownloading":true,"EnableSync":true,' '"EnableSyncTranscoding":true,"EnabledDevices":[],' '"EnableAllDevices":true,"EnabledChannels":[],' '"EnableAllChannels":true,"EnabledFolders":[],' '"EnableAllFolders":true,"InvalidLoginAttemptCount":0,' '"EnablePublicSharing":true}},' '"SessionInfo":{"SupportedCommands":[],' '"QueueableMediaTypes":[],"PlayableMediaTypes":[],' '"Id":"89f3b33f8b3a56af22088733ad1d76b3",' '"UserId":"2ec276a2642e54a19b612b9418a8bd3b",' '"UserName":"username","AdditionalUsers":[],' '"ApplicationVersion":"Unknown version",' '"Client":"Unknown app",' '"LastActivityDate":"2015-11-09T08:35:03.6665060Z",' '"DeviceName":"Unknown device","DeviceId":"Unknown device id",' '"SupportsRemoteControl":false,"PlayState":{"CanSeek":false,' '"IsPaused":false,"IsMuted":false,"RepeatMode":"RepeatNone"}},' '"AccessToken":"4b19180cf02748f7b95c7e8e76562fc8",' '"ServerId":"1efa5077976bfa92bc71652404f646ec"}' ) responses.add( responses.POST, ("http://localhost:8096/Users/AuthenticateByName"), body=body, status=200, content_type="application/json", ) headers = { "x-emby-authorization": ( "MediaBrowser " 'UserId="e8837bc1-ad67-520e-8cd2-f629e3155721", ' 'Client="other", ' 'Device="beets", ' 'DeviceId="beets", ' 'Version="0.0.0"' ) } auth_data = { "username": "username", "password": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", "passwordMd5": "5f4dcc3b5aa765d61d8327deb882cf99", } assert ( embyupdate.get_token("http://localhost", 8096, headers, auth_data) == "4b19180cf02748f7b95c7e8e76562fc8" ) @responses.activate def test_get_user(self): body = ( '[{"Name":"username",' '"ServerId":"1efa5077976bfa92bc71652404f646ec",' '"Id":"2ec276a2642e54a19b612b9418a8bd3b","HasPassword":true,' '"HasConfiguredPassword":true,' '"HasConfiguredEasyPassword":false,' '"LastLoginDate":"2015-11-09T08:35:03.6357440Z",' '"LastActivityDate":"2015-11-09T08:42:39.3693220Z",' '"Configuration":{"AudioLanguagePreference":"",' '"PlayDefaultAudioTrack":true,"SubtitleLanguagePreference":"",' '"DisplayMissingEpisodes":false,' '"DisplayUnairedEpisodes":false,' '"GroupMoviesIntoBoxSets":false,' '"DisplayChannelsWithinViews":[],' '"ExcludeFoldersFromGrouping":[],"GroupedFolders":[],' '"SubtitleMode":"Default","DisplayCollectionsView":true,' '"DisplayFoldersView":false,"EnableLocalPassword":false,' '"OrderedViews":[],"IncludeTrailersInSuggestions":true,' '"EnableCinemaMode":true,"LatestItemsExcludes":[],' '"PlainFolderViews":[],"HidePlayedInLatest":true,' '"DisplayChannelsInline":false},' '"Policy":{"IsAdministrator":true,"IsHidden":false,' '"IsDisabled":false,"BlockedTags":[],' '"EnableUserPreferenceAccess":true,"AccessSchedules":[],' '"BlockUnratedItems":[],' '"EnableRemoteControlOfOtherUsers":false,' '"EnableSharedDeviceControl":true,' '"EnableLiveTvManagement":true,"EnableLiveTvAccess":true,' '"EnableMediaPlayback":true,' '"EnableAudioPlaybackTranscoding":true,' '"EnableVideoPlaybackTranscoding":true,' '"EnableContentDeletion":false,' '"EnableContentDownloading":true,' '"EnableSync":true,"EnableSyncTranscoding":true,' '"EnabledDevices":[],"EnableAllDevices":true,' '"EnabledChannels":[],"EnableAllChannels":true,' '"EnabledFolders":[],"EnableAllFolders":true,' '"InvalidLoginAttemptCount":0,"EnablePublicSharing":true}}]' ) responses.add( responses.GET, "http://localhost:8096/Users/Public", body=body, status=200, content_type="application/json", ) response = embyupdate.get_user("http://localhost", 8096, "username") assert response[0]["Id"] == "2ec276a2642e54a19b612b9418a8bd3b" assert response[0]["Name"] == "username" beetbox-beets-00724b7/test/plugins/test_importfeeds.py0000664000175000017500000001112015253035401022440 0ustar pieterpieterimport datetime from pathlib import Path from unittest import mock import pytest from beets.library import Album, Item from beets.test.helper import PluginTestCase from beets.util import FilesystemError from beetsplug.importfeeds import ImportFeedsPlugin class ImportFeedsTest(PluginTestCase): plugin = "importfeeds" def setUp(self): super().setUp() self.importfeeds = ImportFeedsPlugin() self.feeds_dir = self.temp_path / "importfeeds" self.config["importfeeds"]["dir"] = str(self.feeds_dir) def test_multi_format_album_playlist(self): self.config["importfeeds"]["formats"] = "m3u_multi" album = Album(album="album/name", id=1) item_path = Path("path") / "to" / "item" item = Item(title="song", album_id=1, path=item_path) self.lib.add(album) self.lib.add(item) self.importfeeds.album_imported(self.lib, album) playlist_path = self.feeds_dir / next(self.feeds_dir.iterdir()) assert str(playlist_path).endswith("album_name.m3u") assert str(item_path) in playlist_path.read_text() def test_playlist_in_subdir(self): self.config["importfeeds"]["formats"] = "m3u" self.config["importfeeds"]["m3u_name"] = str( Path("subdir") / "imported.m3u" ) album = Album(album="album/name", id=1) item_path = Path("path") / "to" / "item" item = Item(title="song", album_id=1, path=item_path) self.lib.add(album) self.lib.add(item) self.importfeeds.album_imported(self.lib, album) playlist = self.feeds_dir / self.config["importfeeds"]["m3u_name"].get() playlist_subdir = playlist.parent assert playlist_subdir.is_dir() assert playlist.is_file() def test_playlist_per_session(self): self.config["importfeeds"]["formats"] = "m3u_session" self.config["importfeeds"]["m3u_name"] = "imports.m3u" album = Album(album="album/name", id=1) item_path = Path("path") / "to" / "item" item = Item(title="song", album_id=1, path=item_path) self.lib.add(album) self.lib.add(item) self.importfeeds.import_begin(self) self.importfeeds.album_imported(self.lib, album) date = datetime.datetime.now().strftime("%Y%m%d_%Hh%M") playlist = self.feeds_dir / f"imports_{date}.m3u" assert playlist.is_file() assert str(item_path) in playlist.read_text() def test_link_failure_warns_and_continues(self): """A symlink that can't be created is logged as a warning and skipped; remaining items are still processed (#840).""" self.config["importfeeds"]["formats"] = "link" album = Album(album="album/name", id=1) item1 = Item(title="one", album_id=1, path=Path("path") / "one") item2 = Item(title="two", album_id=1, path=Path("path") / "two") self.lib.add(album) self.lib.add(item1) self.lib.add(item2) with ( mock.patch( "beetsplug.importfeeds.link", side_effect=[FilesystemError("x", "link", (b"a", b"b")), None], ) as mock_link, mock.patch.object(self.importfeeds, "_log") as log, ): self.importfeeds.album_imported(self.lib, album) log.warning.assert_called_once() assert mock_link.call_count == 2 def test_non_filesystem_error_is_not_swallowed(self): """Only FilesystemError is caught; other errors still propagate.""" self.config["importfeeds"]["formats"] = "link" album = Album(album="album/name", id=1) item_path = Path("path") / "to" / "item" item = Item(title="song", album_id=1, path=item_path) self.lib.add(album) self.lib.add(item) with ( mock.patch( "beetsplug.importfeeds.link", side_effect=ValueError("unexpected"), ), pytest.raises(ValueError, match="unexpected"), ): self.importfeeds.album_imported(self.lib, album) def test_link_creates_symlink(self): """The happy path still creates the symlink when it succeeds.""" self.config["importfeeds"]["formats"] = "link" self.feeds_dir.mkdir(parents=True, exist_ok=True) album = Album(album="album/name", id=1) item_path = Path("path") / "to" / "item" item = Item(title="song", album_id=1, path=item_path) self.lib.add(album) self.lib.add(item) self.importfeeds.album_imported(self.lib, album) linked = self.feeds_dir / item.filepath.name assert linked.is_symlink() beetbox-beets-00724b7/test/plugins/test_random.py0000664000175000017500000001416215253035401021410 0ustar pieterpieter"""Test the beets.random utilities associated with the random plugin.""" import math import random import pytest from beetsplug.random import _equal_chance_permutation, random_objs @pytest.fixture(scope="class") def helper(class_helper): """Use class scope because each random test class owns its item list. The helper creates lightweight item objects for class setup; tests do not need a fresh beets temp dir per method or shared state between classes. """ return class_helper @pytest.fixture(scope="module", autouse=True) def seed_random(): random.seed(12345) class TestEqualChancePermutation: """Test the _equal_chance_permutation function.""" @pytest.fixture(autouse=True) def setup(self, helper): """Set up the test environment with items.""" self.lib = helper.lib self.artist1 = "Artist 1" self.artist2 = "Artist 2" self.item1 = helper.create_item(artist=self.artist1) self.item2 = helper.create_item(artist=self.artist2) self.items = [self.item1, self.item2] for _ in range(8): self.items.append(helper.create_item(artist=self.artist2)) def _stats(self, data): mean = sum(data) / len(data) stdev = math.sqrt(sum((p - mean) ** 2 for p in data) / (len(data) - 1)) quot, rem = divmod(len(data), 2) if rem: median = sorted(data)[quot] else: median = sum(sorted(data)[quot - 1 : quot + 1]) / 2 return mean, stdev, median def test_equal_permutation(self): """We have a list of items where only one item is from artist1 and the rest are from artist2. If we permute weighted by the artist field then the solo track will almost always end up near the start. If we use a different field then it'll be in the middle on average. """ def experiment(field, histogram=False): """Permutes the list of items 500 times and calculates the position of self.item1 each time. Returns stats about that position. """ positions = [] for _ in range(500): shuffled = list( _equal_chance_permutation(self.items, field=field) ) positions.append(shuffled.index(self.item1)) # Print a histogram (useful for debugging). if histogram: for i in range(len(self.items)): print(f"{i:2d} {'*' * positions.count(i)}") return self._stats(positions) _, stdev1, median1 = experiment("artist") _, stdev2, median2 = experiment("track") assert 0 == pytest.approx(median1, abs=1) assert len(self.items) // 2 == pytest.approx(median2, abs=1) assert stdev2 > stdev1 @pytest.mark.parametrize( "input_items, field, expected", [ ([], "artist", []), ([{"artist": "Artist 1"}], "artist", [{"artist": "Artist 1"}]), # Missing field should not raise an error, but return empty ([{"artist": "Artist 1"}], "nonexistent", []), # Multiple items with the same field value ( [{"artist": "Artist 1"}, {"artist": "Artist 1"}], "artist", [{"artist": "Artist 1"}, {"artist": "Artist 1"}], ), ], ) def test_equal_permutation_items( self, input_items, field, expected, helper ): """Test _equal_chance_permutation with empty input.""" result = list( _equal_chance_permutation( [helper.create_item(**i) for i in input_items], field ) ) for item in expected: for key, value in item.items(): assert any(getattr(r, key) == value for r in result) assert len(result) == len(expected) class TestRandomObjs: """Test the random_objs function.""" @pytest.fixture(autouse=True) def setup(self, helper): """Set up the test environment with items.""" self.lib = helper.lib self.artist1 = "Artist 1" self.artist2 = "Artist 2" self.items = [ helper.create_item(artist=self.artist1, length=180), # 3 minutes helper.create_item(artist=self.artist2, length=240), # 4 minutes helper.create_item(artist=self.artist2, length=300), # 5 minutes ] def test_random_selection_by_count(self): """Test selecting a specific number of items.""" selected = list(random_objs(self.items, "artist", number=2)) assert len(selected) == 2 assert all(item in self.items for item in selected) def test_random_selection_by_time(self): """Test selecting items constrained by total time (minutes).""" selected = list( random_objs(self.items, "artist", time_minutes=6) ) # 6 minutes total_time = ( sum(item.length for item in selected) / 60 ) # Convert to minutes assert total_time <= 6 def test_equal_chance_permutation(self, helper): """Test equal chance permutation ensures balanced artist selection.""" # Add more items to make the test meaningful for _ in range(5): self.items.append( helper.create_item(artist=self.artist1, length=180) ) selected = list( random_objs(self.items, "artist", number=10, equal_chance=True) ) artist_counts = {} for item in selected: artist_counts[item.artist] = artist_counts.get(item.artist, 0) + 1 # Ensure both artists are represented (not strictly equal due to randomness) assert len(artist_counts) >= 2 def test_empty_input_list(self): """Test behavior with an empty input list.""" selected = list(random_objs([], "artist", number=1)) assert len(selected) == 0 def test_no_constraints_returns_all(self): """Test that no constraints return all items in random order.""" selected = list(random_objs(self.items, "artist", number=3)) assert len(selected) == len(self.items) assert set(selected) == set(self.items) beetbox-beets-00724b7/test/plugins/test_art.py0000664000175000017500000011621415253035401020717 0ustar pieterpieter"""Tests for the album art fetchers.""" from __future__ import annotations import os import shutil from pathlib import Path from typing import TYPE_CHECKING from unittest.mock import patch import confuse import pytest from beets import config, importer, logging, util from beets.autotag import AlbumInfo, AlbumMatch, Distance from beets.library import Album from beets.test import _common from beets.test.helper import ( RUNNING_IN_CI, FetchImageHelper, TestHelper, has_program, is_importable, ) from beets.util import clean_module_tempdir from beets.util.artresizer import ArtResizer from beetsplug import fetchart if TYPE_CHECKING: from collections.abc import Iterator, Sequence from unittest.mock import MagicMock logger = logging.getLogger("beets.test_art") REQUIRES_ARTRESIZER = pytest.mark.skipif( not (has_program("magick") or is_importable("PIL")) and not RUNNING_IN_CI, reason="requires ImageMagick or Pillow", ) class Settings(fetchart.FetchArtPlugin): """Used to pass settings to the ArtSources when the plugin isn't fully instantiated. """ def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) class DummyRemoteArtSource(fetchart.RemoteArtSource): NAME = "Dummy Art Source" ID = "dummy" def get( self, album, plugin: fetchart.FetchArtPlugin, paths: Sequence[bytes] | None, ) -> Iterator[fetchart.Candidate]: return iter(()) class UseThePlugin(TestHelper): modules = (fetchart.__name__, ArtResizer.__module__) @pytest.fixture(autouse=True) def setup_plugin(self, setup): self.plugin = fetchart.FetchArtPlugin() @pytest.fixture(autouse=True) def requests_mock_all(self, requests_mock): """Will disable all outgoing requests and raise an error! Tests need to mock all requests! """ # Register some “safe� mocks you actually want to allow, if any: # requests_mock.get("https://example.com/health", json={"status": "ok"}) # Disable any URL not explicitly mocked return @pytest.fixture(autouse=True, scope="class") def cleanup(self): try: yield finally: for module in self.modules: clean_module_tempdir(module) @pytest.fixture def dpath(self) -> bytes: dpath = self.temp_path / "arttest" dpath.mkdir() return os.fsencode(dpath) class CAAData: """Helper mixin for mocking requests to the Cover Art Archive.""" MBID_RELASE = "rid" MBID_GROUP = "rgid" RELEASE_URL = f"coverartarchive.org/release/{MBID_RELASE}" GROUP_URL = f"coverartarchive.org/release-group/{MBID_GROUP}" RELEASE_URL = f"https://{RELEASE_URL}" GROUP_URL = f"https://{GROUP_URL}" RESPONSE_RELEASE = """{ "images": [ { "approved": false, "back": false, "comment": "GIF", "edit": 12345, "front": true, "id": 12345, "image": "http://coverartarchive.org/release/rid/12345.gif", "thumbnails": { "1200": "http://coverartarchive.org/release/rid/12345-1200.jpg", "250": "http://coverartarchive.org/release/rid/12345-250.jpg", "500": "http://coverartarchive.org/release/rid/12345-500.jpg", "large": "http://coverartarchive.org/release/rid/12345-500.jpg", "small": "http://coverartarchive.org/release/rid/12345-250.jpg" }, "types": ["Front"] }, { "approved": false, "back": false, "comment": "", "edit": 12345, "front": false, "id": 12345, "image": "http://coverartarchive.org/release/rid/12345.jpg", "thumbnails": { "1200": "http://coverartarchive.org/release/rid/12345-1200.jpg", "250": "http://coverartarchive.org/release/rid/12345-250.jpg", "500": "http://coverartarchive.org/release/rid/12345-500.jpg", "large": "http://coverartarchive.org/release/rid/12345-500.jpg", "small": "http://coverartarchive.org/release/rid/12345-250.jpg" }, "types": ["Front"] } ], "release": "https://musicbrainz.org/release/releaseid" }""" RESPONSE_RELEASE_WITHOUT_THUMBNAILS = """{ "images": [ { "approved": false, "back": false, "comment": "GIF", "edit": 12345, "front": true, "id": 12345, "image": "http://coverartarchive.org/release/rid/12345.gif", "types": ["Front"] }, { "approved": false, "back": false, "comment": "", "edit": 12345, "front": false, "id": 12345, "image": "http://coverartarchive.org/release/rid/12345.jpg", "thumbnails": { "large": "http://coverartarchive.org/release/rgid/12345-500.jpg", "small": "http://coverartarchive.org/release/rgid/12345-250.jpg" }, "types": ["Front"] } ], "release": "https://musicbrainz.org/release/releaseid" }""" RESPONSE_GROUP = """{ "images": [ { "approved": false, "back": false, "comment": "", "edit": 12345, "front": true, "id": 12345, "image": "http://coverartarchive.org/release/releaseid/12345.jpg", "thumbnails": { "1200": "http://coverartarchive.org/release/rgid/12345-1200.jpg", "250": "http://coverartarchive.org/release/rgid/12345-250.jpg", "500": "http://coverartarchive.org/release/rgid/12345-500.jpg", "large": "http://coverartarchive.org/release/rgid/12345-500.jpg", "small": "http://coverartarchive.org/release/rgid/12345-250.jpg" }, "types": ["Front"] } ], "release": "https://musicbrainz.org/release/release-id" }""" RESPONSE_GROUP_WITHOUT_THUMBNAILS = """{ "images": [ { "approved": false, "back": false, "comment": "", "edit": 12345, "front": true, "id": 12345, "image": "http://coverartarchive.org/release/releaseid/12345.jpg", "types": ["Front"] } ], "release": "https://musicbrainz.org/release/release-id" }""" class TestFetchImage(UseThePlugin, FetchImageHelper): URL = "http://example.com/test.jpg" @pytest.fixture def settings(self) -> Settings: return Settings(maxwidth=0) @pytest.fixture def source(self) -> DummyRemoteArtSource: return DummyRemoteArtSource(logger, self.plugin.config) @pytest.fixture def candidate(self, source: DummyRemoteArtSource) -> fetchart.Candidate: return fetchart.Candidate(logger, source.ID, url=self.URL) def test_invalid_type_returns_none( self, source, candidate, settings, image_request_mock ) -> None: image_request_mock.get(self.URL, content_type="image/watercolour") source.fetch_image(candidate, settings) assert candidate.path is None def test_jpeg_type_returns_path( self, source, candidate, settings, image_request_mock ) -> None: image_request_mock.get(self.URL, content_type="image/jpeg") source.fetch_image(candidate, settings) assert candidate.path is not None def test_extension_set_by_content_type( self, source, candidate, settings, image_request_mock ) -> None: image_request_mock.get(self.URL, content_type="image/png") source.fetch_image(candidate, settings) assert candidate.path is not None assert os.path.splitext(candidate.path)[1] == b".png" assert Path(os.fsdecode(candidate.path)).exists() def test_does_not_rely_on_server_content_type( self, source, candidate, settings, image_request_mock ) -> None: image_request_mock.get( self.URL, content_type="image/jpeg", file_type="image/png" ) source.fetch_image(candidate, settings) assert candidate.path is not None assert os.path.splitext(candidate.path)[1] == b".png" assert Path(os.fsdecode(candidate.path)).exists() class TestFSArt(UseThePlugin): @pytest.fixture def settings(self) -> Settings: return Settings(cautious=False, cover_names=("art",), fallback=None) @pytest.fixture def source(self) -> fetchart.FileSystem: return fetchart.FileSystem(logger, self.plugin.config) def test_finds_jpg_in_directory(self, source, dpath, settings) -> None: _common.touch(os.path.join(dpath, b"a.jpg")) candidate = next(source.get(Album(), settings, [dpath])) assert candidate.path == os.path.join(dpath, b"a.jpg") def test_appropriately_named_file_takes_precedence( self, source, dpath, settings ) -> None: _common.touch(os.path.join(dpath, b"a.jpg")) _common.touch(os.path.join(dpath, b"art.jpg")) candidate = next(source.get(Album(), settings, [dpath])) assert candidate.path == os.path.join(dpath, b"art.jpg") def test_non_image_file_not_identified( self, source, dpath, settings ) -> None: _common.touch(os.path.join(dpath, b"a.txt")) with pytest.raises(StopIteration): next(source.get(Album(), settings, [dpath])) def test_cautious_skips_fallback(self, source, dpath, settings) -> None: _common.touch(os.path.join(dpath, b"a.jpg")) settings.cautious = True with pytest.raises(StopIteration): next(source.get(Album(), settings, [dpath])) def test_configured_fallback_is_used(self, source, dpath, settings) -> None: fallback = self.temp_path / "a.jpg" fallback.touch() settings.fallback = fallback # type: ignore candidate = next(source.get(Album(), settings, [dpath])) assert candidate.path == fallback def test_empty_dir(self, source, dpath, settings) -> None: with pytest.raises(StopIteration): next(source.get(Album(), settings, [dpath])) def test_precedence_amongst_correct_files( self, source, dpath, settings ) -> None: images = [b"front-cover.jpg", b"front.jpg", b"back.jpg"] paths = [os.path.join(dpath, i) for i in images] for p in paths: _common.touch(p) settings.cover_names = [b"cover", b"front", b"back"] candidates = [ candidate.path for candidate in source.get(Album(), settings, [dpath]) ] assert candidates == paths @patch("os.path.samefile") def test_is_candidate_fallback_os_error( self, mock_samefile, source ) -> None: mock_samefile.side_effect = OSError("os error") fallback = self.temp_path / "a.jpg" self.plugin.fallback = str(fallback) candidate = fetchart.Candidate(logger, source.ID, os.fsencode(fallback)) result = self.plugin._is_candidate_fallback(candidate) mock_samefile.assert_called_once() assert not result class TestCombined(UseThePlugin, FetchImageHelper, CAAData): ASIN = "xxxx" MBID = "releaseid" AMAZON_URL = f"https://images.amazon.com/images/P/{ASIN}.01.LZZZZZZZ.jpg" AMAZON_URL_2 = f"https://images.amazon.com/images/P/{ASIN}.02.LZZZZZZZ.jpg" AAO_URL = f"https://www.albumart.org/index_detail.php?asin={ASIN}" def test_main_interface_returns_amazon_art(self, image_request_mock): image_request_mock.get(self.AMAZON_URL) album = Album(asin=self.ASIN) candidate = self.plugin.art_for_album(album, None) assert candidate is not None def test_main_interface_returns_none_for_missing_asin_and_path(self): album = Album() candidate = self.plugin.art_for_album(album, None) assert candidate is None def test_main_interface_gives_precedence_to_fs_art( self, dpath, image_request_mock ): _common.touch(os.path.join(dpath, b"art.jpg")) image_request_mock.get(self.AMAZON_URL) album = Album(asin=self.ASIN) candidate = self.plugin.art_for_album(album, [dpath]) assert candidate is not None assert candidate.path == os.path.join(dpath, b"art.jpg") def test_main_interface_falls_back_to_amazon( self, dpath, image_request_mock ): image_request_mock.get(self.AMAZON_URL) album = Album(asin=self.ASIN) candidate = self.plugin.art_for_album(album, [dpath]) assert candidate is not None assert not candidate.path.startswith(dpath) def test_main_interface_tries_amazon_before_aao( self, dpath, image_request_mock ): image_request_mock.get(self.AMAZON_URL) album = Album(asin=self.ASIN) self.plugin.art_for_album(album, [dpath]) assert image_request_mock.mocker.called_once assert ( image_request_mock.mocker.request_history[0].url == self.AMAZON_URL ) def test_main_interface_falls_back_to_aao(self, dpath, image_request_mock): image_request_mock.get(self.AMAZON_URL, content_type="text/html") image_request_mock.get(self.AMAZON_URL_2, content_type="text/html") image_request_mock.get(self.AAO_URL, content_type="image/jpeg") album = Album(asin=self.ASIN) self.plugin.art_for_album(album, [dpath]) assert image_request_mock.mocker.request_history[-1].url == self.AAO_URL def test_main_interface_uses_caa_when_mbid_available( self, image_request_mock ): image_request_mock.get(self.RELEASE_URL, content=self.RESPONSE_RELEASE) image_request_mock.get(self.GROUP_URL, content=self.RESPONSE_GROUP) image_request_mock.get( "http://coverartarchive.org/release/rid/12345.gif", content_type="image/gif", ) image_request_mock.get( "http://coverartarchive.org/release/rid/12345.jpg", content_type="image/jpeg", ) album = Album( mb_albumid=self.MBID_RELASE, mb_releasegroupid=self.MBID_GROUP, asin=self.ASIN, ) candidate = self.plugin.art_for_album(album, None) assert candidate is not None assert image_request_mock.mocker.call_count == 3 assert ( image_request_mock.mocker.request_history[0].url == self.RELEASE_URL ) def test_local_only_does_not_access_network(self, image_request_mock): album = Album(mb_albumid=self.MBID, asin=self.ASIN) self.plugin.art_for_album(album, None, local_only=True) assert not image_request_mock.mocker.called def test_local_only_gets_fs_image(self, dpath, image_request_mock): _common.touch(os.path.join(dpath, b"art.jpg")) album = Album(mb_albumid=self.MBID, asin=self.ASIN) candidate = self.plugin.art_for_album(album, [dpath], local_only=True) assert candidate is not None assert candidate.path == os.path.join(dpath, b"art.jpg") assert not image_request_mock.mocker.called class TestAAO(UseThePlugin, FetchImageHelper): ASIN = "xxxx" AAO_URL = f"https://www.albumart.org/index_detail.php?asin={ASIN}" @pytest.fixture def settings(self) -> Settings: return Settings() @pytest.fixture def source(self) -> fetchart.AlbumArtOrg: return fetchart.AlbumArtOrg(logger, self.plugin.config) def test_aao_scraper_finds_image( self, source, settings, image_request_mock ) -> None: body = """
View larger image """ image_request_mock.get( self.AAO_URL, content=body, content_type="text/html" ) album = Album(asin=self.ASIN) candidate = next(source.get(album, settings, [])) assert candidate.url == "TARGET_URL" def test_aao_scraper_returns_no_result_when_no_image_present( self, source, settings, image_request_mock ) -> None: image_request_mock.get( self.AAO_URL, content="blah blah", content_type="text/html" ) album = Album(asin=self.ASIN) with pytest.raises(StopIteration): next(source.get(album, settings, [])) class TestITunesStore(UseThePlugin, FetchImageHelper): @pytest.fixture def settings(self) -> Settings: return Settings() @pytest.fixture def source(self) -> fetchart.ITunesStore: return fetchart.ITunesStore(logger, self.plugin.config) @pytest.fixture def album(self) -> Album: return Album(albumartist="some artist", album="some album") def test_itunesstore_finds_image( self, source, settings, album, image_request_mock ): json = """{ "results": [ { "artistName": "some artist", "collectionName": "some album", "artworkUrl100": "url_to_the_image" } ] }""" image_request_mock.get( fetchart.ITunesStore.API_URL, content=json, content_type="application/json", ) candidate = next(source.get(album, settings, [])) assert candidate.url == "url_to_the_image" assert candidate.match == fetchart.MetadataMatch.EXACT def test_itunesstore_no_result( self, source, settings, album, image_request_mock, caplog ): json = '{"results": []}' image_request_mock.get( fetchart.ITunesStore.API_URL, content=json, content_type="application/json", ) expected = "got no results" with caplog.at_level("DEBUG", logger="beets.test_art"): with pytest.raises(StopIteration): next(source.get(album, settings, [])) assert expected in caplog.messages[1] def test_itunesstore_requestexception( self, source, settings, album, requests_mock, caplog ): requests_mock.get( fetchart.ITunesStore.API_URL, json={"error": "not found"}, status_code=404, ) expected = "iTunes search failed: 404 Client Error" with caplog.at_level("DEBUG", logger="beets.test_art"): with pytest.raises(StopIteration): next(source.get(album, settings, [])) assert expected in caplog.messages[1] def test_itunesstore_fallback_match( self, source: fetchart.ITunesStore, settings, album, image_request_mock ): json = """{ "results": [ { "collectionName": "some album", "artworkUrl100": "url_to_the_image" } ] }""" image_request_mock.get( fetchart.ITunesStore.API_URL, content=json, content_type="application/json", ) candidate = next(source.get(album, settings, [])) assert candidate.url == "url_to_the_image" assert candidate.match == fetchart.MetadataMatch.FALLBACK def test_itunesstore_returns_result_without_artwork( self, source, settings, album, image_request_mock, caplog ): json = """{ "results": [ { "artistName": "some artist", "collectionName": "some album" } ] }""" image_request_mock.get( fetchart.ITunesStore.API_URL, content=json, content_type="application/json", ) expected = "Malformed itunes candidate" with caplog.at_level("DEBUG", logger="beets.test_art"): with pytest.raises(StopIteration): next(source.get(album, settings, [])) assert expected in caplog.messages[1] def test_itunesstore_returns_no_result_when_error_received( self, source, settings, album, image_request_mock, caplog ): json = '{"error": {"errors": [{"reason": "some reason"}]}}' image_request_mock.get( fetchart.ITunesStore.API_URL, content=json, content_type="application/json", ) expected = "not found in json. Fields are" with caplog.at_level("DEBUG", logger="beets.test_art"): with pytest.raises(StopIteration): next(source.get(album, settings, [])) assert expected in caplog.messages[1] def test_itunesstore_returns_no_result_with_malformed_response( self, source, settings, album, image_request_mock, caplog ): json = """bla blup""" image_request_mock.get( fetchart.ITunesStore.API_URL, content=json, content_type="application/json", ) expected = "Could not decode json response:" with caplog.at_level("DEBUG", logger="beets.test_art"): with pytest.raises(StopIteration): next(source.get(album, settings, [])) assert expected in caplog.messages[1] class TestGoogleImage(UseThePlugin, FetchImageHelper): @pytest.fixture def settings(self) -> Settings: return Settings() @pytest.fixture def source(self) -> fetchart.GoogleImages: return fetchart.GoogleImages(logger, self.plugin.config) def test_google_art_finds_image(self, source, settings, image_request_mock): album = Album(albumartist="some artist", album="some album") json = '{"items": [{"link": "url_to_the_image"}]}' image_request_mock.get( fetchart.GoogleImages.URL, content=json, content_type="application/json", ) candidate = next(source.get(album, settings, [])) assert candidate.url == "url_to_the_image" def test_google_art_returns_no_result_when_error_received( self, source, settings, image_request_mock ): album = Album(albumartist="some artist", album="some album") json = '{"error": {"errors": [{"reason": "some reason"}]}}' image_request_mock.get( fetchart.GoogleImages.URL, content=json, content_type="application/json", ) with pytest.raises(StopIteration): next(source.get(album, settings, [])) def test_google_art_returns_no_result_with_malformed_response( self, source, settings, image_request_mock ): album = Album(albumartist="some artist", album="some album") json = """bla blup""" image_request_mock.get( fetchart.GoogleImages.URL, content=json, content_type="application/json", ) with pytest.raises(StopIteration): next(source.get(album, settings, [])) class TestCoverArtArchive(UseThePlugin, FetchImageHelper, CAAData): @pytest.fixture def settings(self) -> Settings: return Settings(maxwidth=0) @pytest.fixture def source(self) -> fetchart.CoverArtArchive: return fetchart.CoverArtArchive(logger, self.plugin.config) def test_caa_finds_image(self, source, settings, image_request_mock): album = Album( mb_albumid=self.MBID_RELASE, mb_releasegroupid=self.MBID_GROUP ) image_request_mock.get(self.RELEASE_URL, content=self.RESPONSE_RELEASE) image_request_mock.get(self.GROUP_URL, content=self.RESPONSE_GROUP) candidates = list(source.get(album, settings, [])) assert len(candidates) == 3 assert image_request_mock.mocker.call_count == 2 assert ( image_request_mock.mocker.request_history[0].url == self.RELEASE_URL ) def test_fetchart_uses_caa_pre_sized_maxwidth_thumbs( self, source, image_request_mock ): # CAA provides pre-sized thumbnails of width 250px, 500px, and 1200px # We only test with one of them here maxwidth = 1200 settings = Settings(maxwidth=maxwidth) album = Album( mb_albumid=self.MBID_RELASE, mb_releasegroupid=self.MBID_GROUP ) image_request_mock.get(self.RELEASE_URL, content=self.RESPONSE_RELEASE) image_request_mock.get(self.GROUP_URL, content=self.RESPONSE_GROUP) candidates = list(source.get(album, settings, [])) assert len(candidates) == 3 for candidate in candidates: assert candidate.url is not None assert f"-{maxwidth}.jpg" in candidate.url def test_caa_finds_image_if_maxwidth_is_set_and_thumbnails_is_empty( self, source, image_request_mock ): # CAA provides pre-sized thumbnails of width 250px, 500px, and 1200px # We only test with one of them here maxwidth = 1200 settings = Settings(maxwidth=maxwidth) album = Album( mb_albumid=self.MBID_RELASE, mb_releasegroupid=self.MBID_GROUP ) image_request_mock.get( self.RELEASE_URL, content=self.RESPONSE_RELEASE_WITHOUT_THUMBNAILS ) image_request_mock.get( self.GROUP_URL, content=self.RESPONSE_GROUP_WITHOUT_THUMBNAILS ) candidates = list(source.get(album, settings, [])) assert len(candidates) == 3 for candidate in candidates: assert candidate.url is not None assert f"-{maxwidth}.jpg" not in candidate.url class TestFanartTV(UseThePlugin, FetchImageHelper): RESPONSE_MULTIPLE = """{ "name": "artistname", "mbid_id": "artistid", "albums": { "thereleasegroupid": { "albumcover": [ { "id": "24", "url": "http://example.com/1.jpg", "likes": "0" }, { "id": "42", "url": "http://example.com/2.jpg", "likes": "0" }, { "id": "23", "url": "http://example.com/3.jpg", "likes": "0" } ], "cdart": [ { "id": "123", "url": "http://example.com/4.jpg", "likes": "0", "disc": "1", "size": "1000" } ] } } }""" RESPONSE_NO_ART = """{ "name": "artistname", "mbid_id": "artistid", "albums": { "thereleasegroupid": { "cdart": [ { "id": "123", "url": "http://example.com/4.jpg", "likes": "0", "disc": "1", "size": "1000" } ] } } }""" RESPONSE_ERROR = """{ "status": "error", "error message": "the error message" }""" RESPONSE_MALFORMED = "bla blup" @pytest.fixture def settings(self): return Settings(maxwidth=0) @pytest.fixture def source(self): return fetchart.FanartTV(logger, self.plugin.config) def test_fanarttv_finds_image(self, source, settings, image_request_mock): album = Album(mb_releasegroupid="thereleasegroupid") image_request_mock.get( f"{fetchart.FanartTV.API_ALBUMS}thereleasegroupid", content=self.RESPONSE_MULTIPLE, content_type="application/json", ) candidate = next(source.get(album, settings, [])) assert candidate.url == "http://example.com/1.jpg" def test_fanarttv_returns_no_result_when_error_received( self, source, settings, image_request_mock ): album = Album(mb_releasegroupid="thereleasegroupid") image_request_mock.get( f"{fetchart.FanartTV.API_ALBUMS}thereleasegroupid", content=self.RESPONSE_ERROR, content_type="application/json", ) with pytest.raises(StopIteration): next(source.get(album, settings, [])) def test_fanarttv_returns_no_result_with_malformed_response( self, source, settings, image_request_mock ): album = Album(mb_releasegroupid="thereleasegroupid") image_request_mock.get( f"{fetchart.FanartTV.API_ALBUMS}thereleasegroupid", content=self.RESPONSE_MALFORMED, content_type="application/json", ) with pytest.raises(StopIteration): next(source.get(album, settings, [])) def test_fanarttv_only_other_images( self, source, settings, image_request_mock ): # The source used to fail when there were images present, but no cover album = Album(mb_releasegroupid="thereleasegroupid") image_request_mock.get( f"{fetchart.FanartTV.API_ALBUMS}thereleasegroupid", content=self.RESPONSE_NO_ART, content_type="application/json", ) with pytest.raises(StopIteration): next(source.get(album, settings, [])) class TestArtImporter(UseThePlugin): @pytest.fixture(autouse=True) def _setup(self, setup_plugin): # Mock the album art fetcher to always return our test file. self.art_file = self.temp_path / "tmpcover.jpg" self.art_file.touch() self.old_afa = self.plugin.art_for_album self.afa_response = fetchart.Candidate( logger, source_name="test", path=self.art_file ) def art_for_album(i, p, local_only=False): return self.afa_response self.plugin.art_for_album = art_for_album # Test library. (self.lib_path / "album").mkdir() itempath = self.lib_path / "album" / "test.mp3" shutil.copyfile(_common.RSRC / "full.mp3", itempath) self.i = _common.item() self.i.path = itempath self.album = self.lib.add_album([self.i]) self.lib._connection().commit() # The import configuration. self.session = _common.import_session(self.lib) # Import task for the coroutine. self.task = importer.ImportTask(None, None, [self.i]) self.task.is_album = True self.task.album = self.album info = AlbumInfo( album="some album", album_id="albumid", artist="some artist", artist_id="artistid", tracks=[], ) self.task.set_choice(AlbumMatch(Distance(), info, {})) yield self.plugin.art_for_album = self.old_afa def _fetch_art(self, should_exist): """Execute the fetch_art coroutine for the task and return the album's resulting artpath. ``should_exist`` specifies whether to assert that art path was set (to the correct value) or or that the path was not set. """ # Execute the two relevant parts of the importer. self.plugin.fetch_art(self.session, self.task) self.plugin.assign_art(self.session, self.task) artpath = self.lib.albums()[0].art_filepath if should_exist: assert artpath == self.i.filepath.parent / "cover.jpg" assert artpath.exists() else: assert artpath is None return artpath def test_fetch_art(self): assert not self.lib.albums()[0].artpath self._fetch_art(True) def test_art_not_found(self): self.afa_response = None self._fetch_art(False) def test_no_art_for_singleton(self): self.task.is_album = False self._fetch_art(False) def test_leave_original_file_in_place(self): self._fetch_art(True) assert self.art_file.exists() def test_delete_original_file(self): prev_move = config["import"]["move"].get() try: config["import"]["move"] = True self._fetch_art(True) assert not self.art_file.exists() finally: config["import"]["move"] = prev_move def test_do_not_delete_original_if_already_in_place(self): artdest = self.i.filepath.parent / "cover.jpg" shutil.copyfile(self.art_file, artdest) self.afa_response = fetchart.Candidate( logger, source_name="test", path=artdest ) self._fetch_art(True) def test_fetch_art_if_imported_file_deleted(self): # See #1126. Test the following scenario: # - Album art imported, `album.artpath` set. # - Imported album art file subsequently deleted (by user or other # program). # `fetchart` should import album art again instead of printing the # message " has album art". self._fetch_art(True) util.remove(self.album.artpath) self.plugin.batch_fetch_art( self.lib, self.lib.albums(), force=False, quiet=False ) assert self.album.art_filepath.exists() class AlbumArtOperationMixin(UseThePlugin): """Base test case for album art operations. Provides common setup for testing album art processing operations by setting up a mock filesystem source that returns a predefined test image. """ IMAGE_PATH = _common.RSRC / "abbey-similar.jpg" IMAGE_FILESIZE = IMAGE_PATH.stat().st_size IMAGE_WIDTH = 500 IMAGE_HEIGHT = 490 IMAGE_WIDTH_HEIGHT_DIFF = IMAGE_WIDTH - IMAGE_HEIGHT @pytest.fixture(autouse=True, scope="class") def fs_mock(self, cleanup): def fs_source_get(_self, album, settings, paths): if paths: yield fetchart.Candidate( logger, source_name=_self.ID, path=self.IMAGE_PATH ) with patch("beetsplug.fetchart.FileSystem.get", fs_source_get): yield def get_album_art(self): return self.plugin.art_for_album(Album(), [""], True) @REQUIRES_ARTRESIZER class TestAlbumArtOperationConfiguration(AlbumArtOperationMixin): """Check that scale & filesize configuration is respected. Depending on `minwidth`, `enforce_ratio`, `margin_px`, and `margin_percent` configuration the plugin should or should not return an art candidate. """ def test_minwidth(self): self.plugin.minwidth = self.IMAGE_WIDTH / 2 assert self.get_album_art() self.plugin.minwidth = self.IMAGE_WIDTH * 2 assert not self.get_album_art() def test_enforce_ratio(self): self.plugin.enforce_ratio = True assert not self.get_album_art() self.plugin.enforce_ratio = False assert self.get_album_art() def test_enforce_ratio_with_px_margin(self): self.plugin.enforce_ratio = True self.plugin.margin_px = self.IMAGE_WIDTH_HEIGHT_DIFF * 0.5 assert not self.get_album_art() self.plugin.margin_px = self.IMAGE_WIDTH_HEIGHT_DIFF * 1.5 assert self.get_album_art() def test_enforce_ratio_with_percent_margin(self): self.plugin.enforce_ratio = True diff_by_width = self.IMAGE_WIDTH_HEIGHT_DIFF / self.IMAGE_WIDTH self.plugin.margin_percent = diff_by_width * 0.5 assert not self.get_album_art() self.plugin.margin_percent = diff_by_width * 1.5 assert self.get_album_art() @REQUIRES_ARTRESIZER class TestAlbumArtPerformOperation(AlbumArtOperationMixin): """Test that the art is resized and deinterlaced if necessary.""" @pytest.fixture def resizer_mock(self) -> Iterator[MagicMock]: with patch.object( ArtResizer.shared, "resize", return_value=self.IMAGE_PATH ) as mocked: yield mocked @pytest.fixture def deinterlacer_mock(self) -> Iterator[MagicMock]: with patch.object( ArtResizer.shared, "deinterlace", return_value=self.IMAGE_PATH ) as mocked: yield mocked def test_resize(self, resizer_mock): self.plugin.maxwidth = self.IMAGE_WIDTH / 2 assert self.get_album_art() resizer_mock.assert_called_once() def test_file_resized(self, resizer_mock): self.plugin.max_filesize = self.IMAGE_FILESIZE // 2 assert self.get_album_art() resizer_mock.assert_called_once() def test_file_not_resized(self, resizer_mock): self.plugin.max_filesize = self.IMAGE_FILESIZE assert self.get_album_art() resizer_mock.assert_not_called() def test_file_resized_but_not_scaled(self, resizer_mock): self.plugin.maxwidth = self.IMAGE_WIDTH * 2 self.plugin.max_filesize = self.IMAGE_FILESIZE // 2 assert self.get_album_art() resizer_mock.assert_called_once() def test_file_resized_and_scaled(self, resizer_mock): self.plugin.maxwidth = self.IMAGE_WIDTH / 2 self.plugin.max_filesize = self.IMAGE_FILESIZE // 2 assert self.get_album_art() assert resizer_mock.call_count == 2 def test_deinterlaced(self, deinterlacer_mock): self.plugin.deinterlace = True assert self.get_album_art() deinterlacer_mock.assert_called_once() def test_not_deinterlaced(self, deinterlacer_mock): self.plugin.deinterlace = False assert self.get_album_art() deinterlacer_mock.assert_not_called() def test_deinterlaced_and_resized(self, resizer_mock, deinterlacer_mock): self.plugin.maxwidth = self.IMAGE_WIDTH / 2 self.plugin.deinterlace = True assert self.get_album_art() deinterlacer_mock.assert_called_once() resizer_mock.assert_called_once() class TestDeprecatedConfig: """While refactoring the plugin, the remote_priority option was deprecated, and a new codepath should translate its effect. Check that it actually does so. """ # If we subclassed UseThePlugin, the configuration change would either be # overwritten by BeetsTestCase or be set after constructing the # plugin object @pytest.fixture(autouse=True) def setup(self): config["fetchart"]["remote_priority"] = True self.plugin = fetchart.FetchArtPlugin() def test_moves_filesystem_to_end(self): assert isinstance(self.plugin.sources[-1], fetchart.FileSystem) class TestEnforceRatioConfig: """Throw some data at the regexes.""" def _load_with_config(self, values, should_raise): if should_raise: for v in values: config["fetchart"]["enforce_ratio"] = v with pytest.raises(confuse.ConfigValueError): fetchart.FetchArtPlugin() else: for v in values: config["fetchart"]["enforce_ratio"] = v fetchart.FetchArtPlugin() def test_px(self): self._load_with_config("0px 4px 12px 123px".split(), False) self._load_with_config("00px stuff5px".split(), True) def test_percent(self): self._load_with_config("0% 0.00% 5.1% 5% 100%".split(), False) self._load_with_config("00% 1.234% foo5% 100.1%".split(), True) beetbox-beets-00724b7/test/plugins/test_playlist.py0000664000175000017500000001613115253035401021767 0ustar pieterpieterimport os from pathlib import Path from shlex import quote import beets from beets.test.helper import PluginTestCase class PlaylistTestCase(PluginTestCase): plugin = "playlist" preload_plugin = False c_track_path = Path("a") / "b" / "c.mp3" f_track_path = Path("d") / "e" / "f.mp3" i_track_path = Path("g") / "h" / "i.mp3" w_track_path = Path("u") / "v" / "w.mp3" z_track_path = Path("x") / "y" / "z.mp3" nonexisting_track_path = Path("nonexisting.mp3") def setUp(self): super().setUp() self.music_dir = (Path("~") / "Music").expanduser() for p, title, album in [ (self.c_track_path, "some item", "some album"), (self.f_track_path, "another item", "another album"), (self.z_track_path, "yet another item", "yet another album"), ]: self.add_album(path=self.music_dir / p, title=title, album=album) self.playlist_dir = self.temp_path / "playlists" self.playlist_dir.mkdir(parents=True, exist_ok=True) self.config["directory"] = str(self.music_dir) self.config["playlist"]["playlist_dir"] = str(self.playlist_dir) self.absolute_playlist_path = self.playlist_dir / "absolute.m3u" self.relative_playlist_path = self.playlist_dir / "relative.m3u" self.write_absolute_playlist() self.write_relative_playlist() self.setup_test() self.load_plugins() def write_absolute_playlist(self): lines = [ self.music_dir / self.c_track_path, self.music_dir / self.f_track_path, self.music_dir / self.nonexisting_track_path, ] self.absolute_playlist_path.write_text("\n".join(map(str, lines))) def write_relative_playlist(self): lines = [ self.c_track_path, self.f_track_path, self.nonexisting_track_path, ] self.relative_playlist_path.write_text("\n".join(map(str, lines))) def setup_test(self): raise NotImplementedError class PlaylistQueryTest: def test_name_query_with_absolute_paths_in_playlist(self): q = "playlist:absolute" results = self.lib.items(q) assert {i.title for i in results} == {"some item", "another item"} def test_path_query_with_absolute_paths_in_playlist(self): q = f"playlist:{quote(str(self.absolute_playlist_path))}" results = self.lib.items(q) assert {i.title for i in results} == {"some item", "another item"} def test_name_query_with_relative_paths_in_playlist(self): q = "playlist:relative" results = self.lib.items(q) assert {i.title for i in results} == {"some item", "another item"} def test_path_query_with_relative_paths_in_playlist(self): q = f"playlist:{quote(str(self.relative_playlist_path))}" results = self.lib.items(q) assert {i.title for i in results} == {"some item", "another item"} def test_name_query_with_nonexisting_playlist(self): q = "playlist:nonexisting" results = self.lib.items(q) assert set(results) == set() def test_path_query_with_nonexisting_playlist(self): q = f"playlist:{quote(str(self.nonexisting_track_path))}" results = self.lib.items(q) assert set(results) == set() class PlaylistTestRelativeToLib(PlaylistQueryTest, PlaylistTestCase): def setup_test(self): self.config["playlist"]["relative_to"] = "library" class PlaylistTestRelativeToDir(PlaylistQueryTest, PlaylistTestCase): def setup_test(self): self.config["playlist"]["relative_to"] = str(self.music_dir) class PlaylistTestRelativeToPls(PlaylistQueryTest, PlaylistTestCase): def write_relative_playlist(self): lines = [ os.path.relpath( self.music_dir / self.c_track_path, self.playlist_dir ), os.path.relpath( self.music_dir / self.f_track_path, self.playlist_dir ), os.path.relpath( self.music_dir / self.nonexisting_track_path, self.playlist_dir ), ] self.relative_playlist_path.write_text("\n".join(lines) + "\n") def setup_test(self): self.config["playlist"]["relative_to"] = "playlist" self.config["playlist"]["playlist_dir"] = str(self.playlist_dir) class PlaylistUpdateTest: def setup_test(self): self.config["playlist"]["auto"] = True self.config["playlist"]["relative_to"] = "library" class PlaylistTestItemMoved(PlaylistUpdateTest, PlaylistTestCase): def test_item_moved(self): # Emit item_moved event for an item that is in a playlist q = f"path:{quote(str(self.music_dir / self.f_track_path))}" results = self.lib.items(q) item = results[0] beets.plugins.send( "item_moved", item=item, source=item.path, destination=os.fsencode(self.music_dir / self.i_track_path), ) # Emit item_moved event for an item that is not in a playlist results = self.lib.items( f"path:{quote(str(self.music_dir / self.z_track_path))}" ) item = results[0] beets.plugins.send( "item_moved", item=item, source=item.path, destination=os.fsencode(self.music_dir / self.w_track_path), ) # Emit cli_exit event beets.plugins.send("cli_exit", lib=self.lib) expected_paths = [ self.c_track_path, self.i_track_path, self.nonexisting_track_path, ] # Check playlist with absolute paths lines = list( map(Path, self.absolute_playlist_path.read_text().splitlines()) ) assert lines == [self.music_dir / p for p in expected_paths] # Check playlist with relative paths lines = list( map(Path, self.relative_playlist_path.read_text().splitlines()) ) assert lines == expected_paths class PlaylistTestItemRemoved(PlaylistUpdateTest, PlaylistTestCase): def test_item_removed(self): # Emit item_removed event for an item that is in a playlist q = f"path:{quote(str(self.music_dir / self.f_track_path))}" results = self.lib.items(q) item = results[0] beets.plugins.send("item_removed", item=item) # Emit item_removed event for an item that is not in a playlist q = f"path:{quote(str(self.music_dir / self.z_track_path))}" results = self.lib.items(q) item = results[0] beets.plugins.send("item_removed", item=item) # Emit cli_exit event beets.plugins.send("cli_exit", lib=self.lib) expected_paths = [self.c_track_path, self.nonexisting_track_path] # Check playlist with absolute paths lines = list( map(Path, self.absolute_playlist_path.read_text().splitlines()) ) assert lines == [self.music_dir / p for p in expected_paths] # Check playlist with relative paths lines = list( map(Path, self.relative_playlist_path.read_text().splitlines()) ) assert lines == expected_paths beetbox-beets-00724b7/test/plugins/test_embedart.py0000664000175000017500000003342115253035401021712 0ustar pieterpieterfrom __future__ import annotations import os import shutil import tempfile import unittest from pathlib import Path from typing import TYPE_CHECKING from unittest.mock import MagicMock, patch import pytest from mediafile import MediaFile from beets import config, logging from beets.exceptions import UserError from beets.test import _common from beets.test.fixtures import DummyIMBackend from beets.test.helper import ( NEEDS_FFPROBE, FetchImageHelper, ImportHelper, IOMixin, PluginMixin, ) from beets.util.artresizer import ArtResizer from beetsplug._utils import art if TYPE_CHECKING: from beets.test.helper import ImageRequestMocker def require_artresizer_compare(test): def wrapper(*args, **kwargs): if not ArtResizer.shared.can_compare: raise unittest.SkipTest("compare not available") # PHASH computation in ImageMagick changed at some point in an # undocumented way. Check at a low level that comparisons of our # fixtures give the expected results. Only then, plugin logic tests # below are meaningful. # cf. https://github.com/ImageMagick/ImageMagick/discussions/5191 # It would be better to investigate what exactly change in IM and # handle that in ArtResizer.IMBackend.{can_compare,compare}. # Skipping the tests as below is a quick fix to CI, but users may # still see unexpected behaviour. abbey_artpath = _common.RSRC / "abbey.jpg" abbey_similarpath = _common.RSRC / "abbey-similar.jpg" abbey_differentpath = _common.RSRC / "abbey-different.jpg" compare_threshold = 20 similar_compares_ok = ArtResizer.shared.compare( abbey_artpath, abbey_similarpath, compare_threshold ) different_compares_ok = ArtResizer.shared.compare( abbey_artpath, abbey_differentpath, compare_threshold ) if not similar_compares_ok or different_compares_ok: raise unittest.SkipTest("IM version with broken compare") return test(*args, **kwargs) wrapper.__name__ = test.__name__ return wrapper class TestEmbedartCli(PluginMixin, IOMixin, ImportHelper, FetchImageHelper): plugin = "embedart" small_artpath = _common.RSRC / "image-2x3.jpg" abbey_artpath = _common.RSRC / "abbey.jpg" abbey_similarpath = _common.RSRC / "abbey-similar.jpg" abbey_differentpath = _common.RSRC / "abbey-different.jpg" def _setup_data(self, artpath=None): if not artpath: artpath = self.small_artpath self.image_data = artpath.read_bytes() def test_embed_art_from_file_with_yes_input(self): self._setup_data() album = self.add_album_fixture() item = album.items()[0] self.io.addinput("y") self.run_command("embedart", "-f", self.small_artpath) mediafile = MediaFile(item.filepath) assert mediafile.images[0].data == self.image_data def test_embed_art_from_file_with_no_input(self): self._setup_data() album = self.add_album_fixture() item = album.items()[0] self.io.addinput("n") self.run_command("embedart", "-f", self.small_artpath) mediafile = MediaFile(item.filepath) # make sure that images array is empty (nothing embedded) assert not mediafile.images def test_embed_art_from_file(self): self._setup_data() album = self.add_album_fixture() item = album.items()[0] self.run_command("embedart", "-y", "-f", self.small_artpath) mediafile = MediaFile(item.filepath) assert mediafile.images[0].data == self.image_data def test_embed_art_from_album(self): self._setup_data() album = self.add_album_fixture() item = album.items()[0] album.artpath = self.small_artpath album.store() self.run_command("embedart", "-y") mediafile = MediaFile(item.filepath) assert mediafile.images[0].data == self.image_data def test_embed_art_remove_art_file(self): self._setup_data() album = self.add_album_fixture() logging.getLogger("beets.embedart").setLevel(logging.DEBUG) handle, tmp_path = tempfile.mkstemp() tmp_path = Path(tmp_path) os.write(handle, self.image_data) os.close(handle) album.artpath = tmp_path album.store() config["embedart"]["remove_art_file"] = True self.run_command("embedart", "-y") if tmp_path.is_file(): tmp_path.unlink() pytest.fail(f"Artwork file {tmp_path} was not deleted") def test_art_file_missing(self): self.add_album_fixture() logging.getLogger("beets.embedart").setLevel(logging.DEBUG) with pytest.raises(UserError): self.run_command("embedart", "-y", "-f", "/doesnotexist") def test_embed_non_image_file(self): album = self.add_album_fixture() logging.getLogger("beets.embedart").setLevel(logging.DEBUG) handle, tmp_path = tempfile.mkstemp() tmp_path = Path(tmp_path) os.write(handle, b"I am not an image.") os.close(handle) try: self.run_command("embedart", "-y", "-f", tmp_path) finally: tmp_path.unlink() mediafile = MediaFile(album.items()[0].filepath) assert not mediafile.images # No image added. @require_artresizer_compare def test_reject_different_art(self): self._setup_data(self.abbey_artpath) album = self.add_album_fixture() item = album.items()[0] self.run_command("embedart", "-y", "-f", self.abbey_artpath) config["embedart"]["compare_threshold"] = 20 self.run_command("embedart", "-y", "-f", self.abbey_differentpath) mediafile = MediaFile(item.filepath) assert mediafile.images[0].data == self.image_data, ( f"Image written is not {self.abbey_artpath}" ) @require_artresizer_compare def test_accept_similar_art(self): self._setup_data(self.abbey_similarpath) album = self.add_album_fixture() item = album.items()[0] self.run_command("embedart", "-y", "-f", self.abbey_artpath) config["embedart"]["compare_threshold"] = 20 self.run_command("embedart", "-y", "-f", self.abbey_similarpath) mediafile = MediaFile(item.filepath) assert mediafile.images[0].data == self.image_data, ( f"Image written is not {self.abbey_similarpath}" ) def test_non_ascii_album_path(self): resource_path = _common.RSRC / "image.mp3" album = self.add_album_fixture() trackpath = album.items()[0].filepath shutil.copy(resource_path, trackpath) self.run_command("extractart", "-a", "-n", "extracted") assert (album.filepath / "extracted.png").exists() def test_extracted_extension(self): resource_path = _common.RSRC / "image-jpeg.mp3" album = self.add_album_fixture() trackpath = album.items()[0].filepath shutil.copy(resource_path, trackpath) self.run_command("extractart", "-a", "-n", "extracted") assert (album.filepath / "extracted.jpg").exists() def test_clear_art_with_yes_input(self): self._setup_data() album = self.add_album_fixture() item = album.items()[0] self.io.addinput("y") self.run_command("embedart", "-f", self.small_artpath) embedded_time = item.filepath.stat().st_mtime self.io.addinput("y") self.run_command("clearart") mediafile = MediaFile(item.filepath) assert not mediafile.images clear_time = item.filepath.stat().st_mtime assert clear_time > embedded_time # A run on a file without an image should not be modified self.io.addinput("y") self.run_command("clearart") no_clear_time = item.filepath.stat().st_mtime assert no_clear_time == clear_time def test_clear_art_with_no_input(self): self._setup_data() album = self.add_album_fixture() item = album.items()[0] self.io.addinput("y") self.run_command("embedart", "-f", self.small_artpath) self.io.addinput("n") self.run_command("clearart") mediafile = MediaFile(item.filepath) assert mediafile.images[0].data == self.image_data def test_embed_art_from_url_with_yes_input( self, image_request_mock: ImageRequestMocker ): self._setup_data() album = self.add_album_fixture() item = album.items()[0] image_request_mock.get( "http://example.com/test.jpg", content_type="image/jpeg" ) self.io.addinput("y") self.run_command("embedart", "-u", "http://example.com/test.jpg") mediafile = MediaFile(item.filepath) assert mediafile.images[0].data == image_request_mock.IMAGE_HEADERS[ "image/jpeg" ].ljust(32, b"\x00") def test_embed_art_from_url_png( self, image_request_mock: ImageRequestMocker ): self._setup_data() album = self.add_album_fixture() item = album.items()[0] image_request_mock.get( "http://example.com/test.png", content_type="image/png" ) self.run_command("embedart", "-y", "-u", "http://example.com/test.png") mediafile = MediaFile(item.filepath) assert mediafile.images[0].data == image_request_mock.IMAGE_HEADERS[ "image/png" ].ljust(32, b"\x00") def test_embed_art_from_url_not_image( self, image_request_mock: ImageRequestMocker ): self._setup_data() album = self.add_album_fixture() item = album.items()[0] image_request_mock.get( "http://example.com/test.html", content_type="text/html" ) self.run_command("embedart", "-y", "-u", "http://example.com/test.html") mediafile = MediaFile(item.filepath) assert not mediafile.images @NEEDS_FFPROBE def test_clearart_on_import_disabled(self): file_path = self.create_mediafile_fixture( images=["jpg"], target_dir=self.import_path ) self.import_media.append(file_path) with self.configure_plugin({"clearart_on_import": False}): importer = self.setup_importer(autotag=False, write=True) importer.run() item = self.lib.items()[0] assert MediaFile(item.filepath).images @NEEDS_FFPROBE def test_clearart_on_import_enabled(self): file_path = self.create_mediafile_fixture( images=["jpg"], target_dir=self.import_path ) self.import_media.append(file_path) # Force re-init the plugin to register the listener self.unload_plugins() with self.configure_plugin({"clearart_on_import": True}): importer = self.setup_importer(autotag=False, write=True) importer.run() item = self.lib.items()[0] assert not MediaFile(item.filepath).images class DummyArtResizer(ArtResizer): """An `ArtResizer` which pretends that ImageMagick is available, and has a sufficiently recent version to support image comparison. """ def __init__(self): self.local_method = DummyIMBackend() @patch("beets.util.artresizer.subprocess") @patch("beetsplug._utils.art.extract") class ArtSimilarityTest(unittest.TestCase): def setUp(self): self.item = _common.item() self.log = logging.getLogger("beets.embedart") self.artresizer = DummyArtResizer() def _similarity(self, threshold): return art.check_art_similarity( self.log, self.item, b"path", threshold, artresizer=self.artresizer ) def _popen(self, status=0, stdout="", stderr=""): """Create a mock `Popen` object.""" popen = MagicMock(returncode=status) popen.communicate.return_value = stdout, stderr return popen def _mock_popens( self, mock_extract, mock_subprocess, compare_status=0, compare_stdout=b"", compare_stderr=b"", convert_status=0, ): mock_extract.return_value = b"extracted_path" mock_subprocess.Popen.side_effect = [ # The `convert` call. self._popen(convert_status), # The `compare` call. self._popen(compare_status, compare_stdout, compare_stderr), ] def test_compare_success_similar(self, mock_extract, mock_subprocess): self._mock_popens(mock_extract, mock_subprocess, 0, b"10", b"err") assert self._similarity(20) def test_compare_success_different(self, mock_extract, mock_subprocess): self._mock_popens(mock_extract, mock_subprocess, 0, b"10", b"err") assert not self._similarity(5) def test_compare_status1_similar(self, mock_extract, mock_subprocess): self._mock_popens(mock_extract, mock_subprocess, 1, b"out", b"10") assert self._similarity(20) def test_compare_status1_different(self, mock_extract, mock_subprocess): self._mock_popens(mock_extract, mock_subprocess, 1, b"out", b"10") assert not self._similarity(5) def test_compare_failed(self, mock_extract, mock_subprocess): self._mock_popens(mock_extract, mock_subprocess, 2, b"out", b"10") assert self._similarity(20) is None def test_compare_parsing_error(self, mock_extract, mock_subprocess): self._mock_popens(mock_extract, mock_subprocess, 0, b"foo", b"bar") assert self._similarity(20) is None def test_compare_parsing_error_and_failure( self, mock_extract, mock_subprocess ): self._mock_popens(mock_extract, mock_subprocess, 1, b"foo", b"bar") assert self._similarity(20) is None def test_convert_failure(self, mock_extract, mock_subprocess): self._mock_popens(mock_extract, mock_subprocess, convert_status=1) assert self._similarity(20) is None beetbox-beets-00724b7/test/plugins/test_mbcollection.py0000664000175000017500000001213615253035401022601 0ustar pieterpieterimport re import uuid from contextlib import nullcontext as does_not_raise import pytest import requests from beets.library import Album from beets.test.helper import PluginMixin, TestHelper from beets.ui import UserError from beetsplug import mbcollection class TestMbCollectionPlugin(PluginMixin, TestHelper): """Tests for the MusicBrainzCollectionPlugin class methods.""" plugin = "mbcollection" COLLECTION_ID = str(uuid.uuid4()) @pytest.fixture(autouse=True) def setup_config(self): self.config["musicbrainz"]["user"] = "testuser" self.config["musicbrainz"]["pass"] = "testpass" self.config["mbcollection"]["collection"] = self.COLLECTION_ID @pytest.mark.parametrize( "user_collections,expectation", [ ( [], pytest.raises( UserError, match=r"no collections exist for user" ), ), ( [{"id": "c1", "entity_type": "event"}], pytest.raises(UserError, match=r"No release collection found."), ), ( [{"id": "c1", "entity_type": "release"}], pytest.raises(UserError, match=r"invalid collection ID"), ), ( [{"id": COLLECTION_ID, "entity_type": "release"}], does_not_raise(), ), ], ids=["no collections", "no release collections", "invalid ID", "valid"], ) def test_get_collection_validation( self, requests_mock, user_collections, expectation ): requests_mock.get( "/ws/2/collection", json={"collections": user_collections} ) with expectation: mbcollection.MusicBrainzCollectionPlugin().collection def test_mbupdate(self, requests_mock, monkeypatch): """Verify mbupdate sync of a MusicBrainz collection with the library. This test ensures that the command: - fetches collection releases using paginated requests, - submits releases that exist locally but are missing from the remote collection - and removes releases from the remote collection that are not in the local library. Small chunk sizes are forced to exercise pagination and batching logic. """ for mb_albumid in [ # already present in remote collection "in_collection1", "in_collection2", # two new albums not in remote collection "00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002", ]: self.lib.add(Album(mb_albumid=mb_albumid)) # The relevant collection requests_mock.get( "/ws/2/collection", json={ "collections": [ { "id": self.COLLECTION_ID, "entity_type": "release", "release_count": 3, } ] }, ) collection_releases = f"/ws/2/collection/{self.COLLECTION_ID}/releases" # Force small fetch chunk to require multiple paged requests. monkeypatch.setattr( "beetsplug.mbcollection.MBCollection.FETCH_CHUNK_SIZE", 2 ) # 3 releases are fetched in two pages. requests_mock.get( re.compile(rf".*{collection_releases}\b.*&offset=0.*"), json={ "releases": [{"id": "in_collection1"}, {"id": "not_in_library"}] }, ) requests_mock.get( re.compile(rf".*{collection_releases}\b.*&offset=2.*"), json={"releases": [{"id": "in_collection2"}]}, ) # Force small submission chunk monkeypatch.setattr( "beetsplug.mbcollection.MBCollection.SUBMISSION_CHUNK_SIZE", 1 ) # so that releases are added using two requests requests_mock.put( re.compile( rf".*{collection_releases}/00000000-0000-0000-0000-000000000001" ) ) requests_mock.put( re.compile( rf".*{collection_releases}/00000000-0000-0000-0000-000000000002" ) ) # and finally, one release is removed requests_mock.delete( re.compile(rf".*{collection_releases}/not_in_library") ) self.run_command("mbupdate", "--remove") assert requests_mock.call_count == 6 def test_mbupdate_logs_unauthorized_errors(self, requests_mock, caplog): response = requests.Response() response.status_code = 401 requests_mock.get( "/ws/2/collection", exc=requests.exceptions.HTTPError(response=response), ) with caplog.at_level("ERROR", logger="beets.mbcollection"): self.run_command("mbupdate") expected_message = ( "Failed to update MusicBrainz collection: HTTP Error: 401" " Unauthorized. Check your musicbrainz.user and musicbrainz.pass" " configuration" ) assert expected_message in caplog.text beetbox-beets-00724b7/test/plugins/test_tidal.py0000664000175000017500000010734715253035401021235 0ustar pieterpieter"""Tests for the 'tidal' plugin.""" from __future__ import annotations import logging import time from typing import TYPE_CHECKING from unittest.mock import Mock import pytest from beets.library import Item from beets.test.helper import PluginTestHelper from beetsplug.tidal import TidalPlugin from beetsplug.tidal.api import API_BASE, TidalAPI if TYPE_CHECKING: from beetsplug.tidal.api_types import ( AlbumAttributes, RelationshipData, ResourceIdentifier, SearchDocument, TidalAlbum, TidalArtist, TidalArtwork, TidalTrack, TrackAttributes, ) CURRENT_TS = 150000000 def _make_search_doc( resource_type: str, resource_ids: list[str] ) -> SearchDocument: return { "data": [ { "id": "search-result", "type": "searchResults", "attributes": {"trackingId": "tracking-id"}, "relationships": { resource_type: { "data": [ {"id": id_, "type": resource_type} for id_ in resource_ids ], "links": {}, } }, } ] } def _make_artwork(id_: str, href: str = "") -> TidalArtwork: return { "id": id_, "type": "artworks", "attributes": { "mediaType": "IMAGE", "files": [{"href": href, "meta": {"width": 1280, "height": 1280}}] if href else [], }, } def _make_artist(id_: str, name: str) -> TidalArtist: return { "id": id_, "type": "artists", "attributes": {"name": name, "popularity": 0.5}, } def _make_album( id_: str, title: str, tracks: list[TidalTrack], artist_ids: list[str], release_date: str = "2024-01-15", version: str | None = None, cover_art_id: str | None = None, ) -> tuple[TidalAlbum, dict[str, TidalTrack], dict[str, TidalArtist]]: artist_lookup = { aid: _make_artist(aid, f"Artist {aid}") for aid in artist_ids } track_lookup = {t["id"]: t for t in tracks} attrs: AlbumAttributes = { "albumType": "ALBUM", "barcodeId": "123456", "duration": "PT45M", "explicit": False, "mediaTags": [], "numberOfItems": len(tracks), "numberOfVolumes": 1, "popularity": 0.5, "title": title, "releaseDate": release_date, } if version: attrs["version"] = version relationships: dict[str, RelationshipData] = { "artists": { "data": [{"id": aid, "type": "artists"} for aid in artist_ids], "links": {}, }, "items": { "data": [{"id": t["id"], "type": "tracks"} for t in tracks], "links": {}, }, } if cover_art_id: relationships["coverArt"] = { "data": [{"id": cover_art_id, "type": "artworks"}], "links": {}, } album: TidalAlbum = { "id": id_, "type": "albums", "attributes": attrs, "relationships": relationships, } return album, track_lookup, artist_lookup def _make_track( id_: str, title: str, duration: str = "PT3M30S", isrc: str = "ISRC123", artist_ids: list[str] | None = None, version: str | None = None, ) -> TidalTrack: artist_relationships: list[ResourceIdentifier] = [ {"id": aid, "type": "artists"} for aid in (artist_ids or []) ] attrs: TrackAttributes = { "title": title, "duration": duration, "explicit": False, "isrc": isrc, "key": "C", "keyScale": "MAJOR", "mediaTags": [], "popularity": 0.5, } if version: attrs["version"] = version return { "id": id_, "type": "tracks", "attributes": attrs, "relationships": { "artists": {"data": artist_relationships, "links": {}} }, } @pytest.fixture(autouse=True) def set_current_ts(monkeypatch): monkeypatch.setattr("beetsplug.tidal.time.time", lambda: CURRENT_TS) class TidalPluginTest(PluginTestHelper): plugin = "tidal" def setup_beets(self): super().setup_beets() self.tidal = TidalPlugin() class TestAPI: def test_search_results_uses_query_filter(self): api = TidalAPI("client-id", "token.json") response = {"data": []} api.get_json = Mock(return_value=response) result = api.search_results("My Artist My Album", include=["albums"]) assert result == response api.get_json.assert_called_once_with( f"{API_BASE}/searchResults", params={ "filter[query]": "My Artist My Album", "explicitFilter": "INCLUDE", "countryCode": "US", "include": ["albums"], }, ) class TestParsing(TidalPluginTest): """High-level tests for album parsing.""" def test_parse_album(self): tracks = [ _make_track("101", "Track One", "PT3M", "ISRC1", ["1001"]), _make_track( "102", "Track Two", "PT4M", "ISRC2", ["1001"], version="Remastered", ), ] album, track_lookup, artist_lookup = _make_album( "1", "My Album", tracks, ["1001"], version="Deluxe Edition" ) info = self.tidal._get_album_info( album, track_lookup, artist_lookup, {} ) assert info.raw_data == { "album": "My Album (Deluxe Edition)", "album_id": "1", "albumdisambig": None, "albumstatus": None, "albumtype": "album", "albumtypes": ["album"], "artist": "Artist 1001", "artist_credit": None, "artist_id": "1001", "artist_sort": None, "artists": ["Artist 1001"], "artists_credit": None, "artists_ids": ["1001"], "artists_sort": None, "asin": None, "barcode": "123456", "catalognum": None, "country": None, "cover_art_url": None, "data_source": "Tidal", "data_url": None, "day": 15, "discogs_albumid": None, "discogs_artistid": None, "discogs_labelid": None, "duration": 2700, "genres": None, "label": None, "language": None, "media": None, "mediums": None, "month": 1, "original_day": None, "original_month": None, "original_year": None, "release_group_title": None, "releasegroup_id": None, "releasegroupdisambig": None, "script": None, "style": None, "tidal_album_id": "1", "tidal_album_popularity": 50, "tidal_artist_id": "1001", "tidal_updated": CURRENT_TS, "tracks": [ { "album": None, "arrangers": None, "arrangers_ids": [], "artist": "Artist 1001", "artist_credit": None, "artist_id": None, "artist_sort": None, "artists": ["Artist 1001"], "artists_credit": None, "artists_ids": ["1001"], "artists_sort": None, "bpm": None, "composer_sort": None, "composers": None, "composers_ids": [], "data_source": "Tidal", "data_url": None, "disctitle": None, "genres": None, "index": 1, "initial_key": None, "isrc": "ISRC1", "label": None, "length": 180, "lyricists": None, "lyricists_ids": [], "mb_workid": None, "media": None, "medium": None, "medium_index": None, "medium_total": None, "release_track_id": None, "remixers": None, "remixers_ids": [], "tidal_artist_id": "1001", "tidal_track_id": "101", "tidal_track_popularity": 50, "tidal_updated": CURRENT_TS, "title": "Track One", "track_alt": None, "track_id": "101", "work": None, "work_disambig": None, }, { "album": None, "arrangers": None, "arrangers_ids": [], "artist": "Artist 1001", "artist_credit": None, "artist_id": None, "artist_sort": None, "artists": ["Artist 1001"], "artists_credit": None, "artists_ids": ["1001"], "artists_sort": None, "bpm": None, "composer_sort": None, "composers": None, "composers_ids": [], "data_source": "Tidal", "data_url": None, "disctitle": None, "genres": None, "index": 2, "initial_key": None, "isrc": "ISRC2", "label": None, "length": 240, "lyricists": None, "lyricists_ids": [], "mb_workid": None, "media": None, "medium": None, "medium_index": None, "medium_total": None, "release_track_id": None, "remixers": None, "remixers_ids": [], "tidal_artist_id": "1001", "tidal_track_id": "102", "tidal_track_popularity": 50, "tidal_updated": CURRENT_TS, "title": "Track Two (Remastered)", "track_alt": None, "track_id": "102", "work": None, "work_disambig": None, }, ], "va": False, "year": 2024, } def test_parse_album_with_version(self): """Album title should have version appended.""" track = _make_track("101", "My Song", "PT3M", "ISRC001", ["1001"]) album, track_lookup, artist_lookup = _make_album( "3", "My Album", [track], ["1001"], version="Deluxe Edition" ) info = self.tidal._get_album_info( album, track_lookup, artist_lookup, {} ) assert info.album == "My Album (Deluxe Edition)" class TestArtworkParsing(TidalPluginTest): """Tests for artwork URL parsing.""" def test_artwork_with_url(self): """Cover art URL from included resources.""" track = _make_track("t1", "Song", "PT3M", "ISRC001", ["a1"]) album, track_lookup, artist_lookup = _make_album( "al1", "Album", [track], ["a1"], cover_art_id="ca1" ) artwork_lookup = { "ca1": _make_artwork( "ca1", "https://resources.tidal.com/images/ca1/1280x1280.jpg" ) } info = self.tidal._get_album_info( album, track_lookup, artist_lookup, artwork_lookup ) assert ( info.cover_art_url == "https://resources.tidal.com/images/ca1/1280x1280.jpg" ) def test_artwork_without_files_returns_none(self): """Cover art returns None when files array is empty.""" track = _make_track("t1", "Song", "PT3M", "ISRC001", ["a1"]) album, track_lookup, artist_lookup = _make_album( "al1", "Album", [track], ["a1"], cover_art_id="ca1" ) artwork_lookup = {"ca1": _make_artwork("ca1")} info = self.tidal._get_album_info( album, track_lookup, artist_lookup, artwork_lookup ) assert info.cover_art_url is None def test_artwork_without_relationship_returns_none(self): """No cover_art_url when album has no coverArt relationship.""" track = _make_track("t1", "Song", "PT3M", "ISRC001", ["a1"]) album, track_lookup, artist_lookup = _make_album( "al1", "Album", [track], ["a1"] ) info = self.tidal._get_album_info( album, track_lookup, artist_lookup, {} ) assert info.cover_art_url is None class TestTrackParsing(TidalPluginTest): """High-level tests for track parsing.""" def test_parse_track(self): track = _make_track("101", "My Track", "PT4M", "ISRC456", ["1001"]) artist_lookup = {"1001": _make_artist("1001", "My Artist")} info = self.tidal._get_track_info(track, artist_lookup) assert info.title == "My Track" assert info.track_id == "101" assert info.length == 240 # PT4M = 240 seconds assert info.isrc == "ISRC456" assert info.artist == "My Artist" assert info.tidal_track_id == "101" assert info.tidal_artist_id == "1001" assert info.tidal_track_popularity == 50 def test_parse_track_with_version(self): """Track title should have version appended.""" track = _make_track( "102", "My Song", "PT3M", "ISRC002", ["1001"], version="Remastered" ) artist_lookup = {"1001": _make_artist("1001", "My Artist")} info = self.tidal._get_track_info(track, artist_lookup) assert info.title == "My Song (Remastered)" assert info.tidal_track_id == "102" class TestTrackForID(TidalPluginTest): """Tests for track_for_id with mocked API.""" def test_track_for_id(self): """Test fetching track by ID via API.""" track = _make_track( "490839595", "API Track", "PT3M", "ISRC001", ["1001"] ) artist = _make_artist("1001", "API Artist") self.tidal.api.get_tracks = Mock( return_value={"data": [track], "included": [artist]} ) info = self.tidal.track_for_id("https://tidal.com/track/490839595") self.tidal.api.get_tracks.assert_called_once() assert info is not None assert info.title == "API Track" assert info.track_id == "490839595" assert info.artist == "API Artist" def test_track_for_id_not_found(self): """Test track_for_id returns None when not found.""" self.tidal.api.get_tracks = Mock(return_value={"data": []}) info = self.tidal.track_for_id("https://tidal.com/track/490839595") assert info is None info = self.tidal.track_for_id("does_not_exist") assert info is None class TestTracksForIDs(TidalPluginTest): """Tests for tracks_for_ids with mocked API.""" def test_tracks_for_ids(self): """Test fetching multiple tracks by IDs via API.""" track1 = _make_track( "490839595", "API Track 1", "PT3M", "ISRC001", ["1001"] ) track2 = _make_track( "490839596", "API Track 2", "PT4M", "ISRC002", ["1001"] ) artist = _make_artist("1001", "API Artist") self.tidal.api.get_tracks = Mock( return_value={"data": [track1, track2], "included": [artist]} ) results = list( self.tidal.tracks_for_ids( [ "https://tidal.com/track/490839595", "https://tidal.com/track/490839596", ] ) ) self.tidal.api.get_tracks.assert_called_once() assert len(results) == 2 assert results[0] is not None assert results[0].title == "API Track 1" assert results[1] is not None assert results[1].title == "API Track 2" def test_tracks_for_ids_with_missing(self): """Test tracks_for_ids yields None for IDs not found.""" track = _make_track( "490839595", "API Track", "PT3M", "ISRC001", ["1001"] ) artist = _make_artist("1001", "API Artist") self.tidal.api.get_tracks = Mock( return_value={"data": [track], "included": [artist]} ) results = list( self.tidal.tracks_for_ids( ["https://tidal.com/track/490839595", "does_not_exist"] ) ) assert len(results) == 2 assert results[0] is not None assert results[0].title == "API Track" assert results[1] is None class TestAlbumForID(TidalPluginTest): """Tests for album_for_id with mocked API.""" def test_album_for_id(self): """Test fetching album by ID via API.""" track = _make_track( "101", "Album Track", "PT3M30S", "ISRC001", ["1001"] ) album, track_lookup, artist_lookup = _make_album( "226495055", "API Album", [track], ["1001"] ) self.tidal.api.get_albums = Mock( return_value={ "data": [album], "included": [*artist_lookup.values(), *track_lookup.values()], } ) info = self.tidal.album_for_id("https://tidal.com/album/226495055") assert info is not None assert info.album == "API Album" assert info.album_id == "226495055" assert len(info.tracks) == 1 assert info.tracks[0].title == "Album Track" def test_album_for_id_not_found(self): """Test album_for_id returns None when not found.""" self.tidal.api.get_albums = Mock(return_value={"data": []}) info = self.tidal.album_for_id("https://tidal.com/album/226495055") assert info is None info = self.tidal.album_for_id("does_not_exist") assert info is None class TestAlbumsForIDs(TidalPluginTest): """Tests for albums_for_ids with mocked API.""" def test_albums_for_ids(self): """Test fetching multiple albums by IDs via API.""" track1 = _make_track( "101", "Album Track 1", "PT3M", "ISRC001", ["1001"] ) track2 = _make_track( "102", "Album Track 2", "PT4M", "ISRC002", ["1001"] ) album1, track_lookup1, artist_lookup1 = _make_album( "226495055", "API Album 1", [track1], ["1001"] ) album2, track_lookup2, artist_lookup2 = _make_album( "226495056", "API Album 2", [track2], ["1001"] ) # Combine lookups to simulate API response all_included = [ *artist_lookup1.values(), *artist_lookup2.values(), *track_lookup1.values(), *track_lookup2.values(), ] self.tidal.api.get_albums = Mock( return_value={"data": [album1, album2], "included": all_included} ) results = list( self.tidal.albums_for_ids( [ "https://tidal.com/album/226495055", "https://tidal.com/album/226495056", ] ) ) self.tidal.api.get_albums.assert_called_once() # Note: yields album then None for each ID assert len(results) == 2 assert results[0] is not None assert results[0].album == "API Album 1" assert results[1] is not None assert results[1].album == "API Album 2" def test_albums_for_ids_with_missing(self): """Test albums_for_ids yields None for IDs not found.""" track = _make_track("101", "Album Track", "PT3M", "ISRC001", ["1001"]) album, track_lookup, artist_lookup = _make_album( "226495055", "API Album", [track], ["1001"] ) self.tidal.api.get_albums = Mock( return_value={ "data": [album], "included": [*artist_lookup.values(), *track_lookup.values()], } ) results = list( self.tidal.albums_for_ids( ["https://tidal.com/album/226495055", "does_not_exist"] ) ) # yields (album, None) for (found, not_found) assert len(results) == 2 assert results[0] is not None assert results[0].album == "API Album" assert results[1] is None class TestCandidates(TidalPluginTest): """Tests for candidates method.""" def test_candidates_with_barcode(self): """Test that candidates uses barcode lookup first.""" track = _make_track("101", "Album Track", "PT3M", "ISRC001", ["1001"]) album, track_lookup, artist_lookup = _make_album( "1", "Barcode Album", [track], ["1001"] ) self.tidal.api.get_albums = Mock( return_value={ "data": [album], "included": [*artist_lookup.values(), *track_lookup.values()], } ) items = [Item(barcode="123456")] candidates = list( self.tidal.candidates(items, "Artist", "Album", False) ) self.tidal.api.get_albums.assert_called_once() assert len(candidates) == 1 assert candidates[0].album == "Barcode Album" def test_candidates_with_query_fallback(self): """Test that candidates falls back to query search when no barcode.""" items = [Item(title="My Song", artist="My Artist", album="My Album")] # Mock search returning album IDs self.tidal.api.search_results = Mock( return_value=_make_search_doc("albums", ["1"]) ) # Mock album lookup by ID track = _make_track("101", "Album Track", "PT3M", "ISRC001", ["1001"]) album, track_lookup, artist_lookup = _make_album( "1", "Query Album", [track], ["1001"] ) self.tidal.api.get_albums = Mock( return_value={ "data": [album], "included": [*artist_lookup.values(), *track_lookup.values()], } ) candidates = list( self.tidal.candidates(items, "My Artist", "My Album", False) ) # Should have called search_results assert self.tidal.api.search_results.called assert len(candidates) == 1 assert candidates[0].album == "Query Album" def test_album_search_handles_empty_response(self): self.tidal.api.search_results = Mock(return_value={"data": []}) self.tidal.api.get_albums = Mock() candidates = list(self.tidal.search_albums_by_query("missing album")) assert candidates == [] self.tidal.api.get_albums.assert_not_called() class TestItemCandidates(TidalPluginTest): """Tests for item_candidates method.""" def test_item_candidates_with_isrc(self): """Test that item_candidates uses ISRC lookup first.""" track = _make_track( "490839595", "ISRC Track", "PT3M", "ISRC001", ["1001"] ) artist = _make_artist("1001", "ISRC Artist") self.tidal.api.get_tracks = Mock( return_value={"data": [track], "included": [artist]} ) item = Item(isrc="ISRC001") results = list(self.tidal.item_candidates(item, "Artist", "Title")) self.tidal.api.get_tracks.assert_called_once() assert len(results) == 1 assert results[0].title == "ISRC Track" def test_item_candidates_with_query_fallback(self): """Test item_candidates falls back to query search when no ISRC.""" item = Item(title="Query Song", artist="Query Artist") self.tidal.api.search_results = Mock( return_value={ **_make_search_doc("tracks", ["490839595"]), "included": [ _make_track( "490839595", "Query Track", "PT3M", "ISRC002", ["1001"] ), _make_artist("1001", "Query Artist"), ], } ) results = list( self.tidal.item_candidates(item, "Query Artist", "Query Song") ) assert self.tidal.api.search_results.called assert results[0].title == "Query Track" def test_track_search_handles_empty_response(self): self.tidal.api.search_results = Mock(return_value={"data": []}) candidates = list(self.tidal.search_tracks_by_query("missing track")) assert candidates == [] class TestStaticHelpers: """Tests for static helper methods.""" @pytest.mark.parametrize( "attrs, expected", [ ( { "externalLinks": [ {"href": "https://tidal.com/b/123", "meta": ""} ] }, "https://tidal.com/b/123", ), ({}, None), ], ) def test_parse_data_url(self, attrs, expected): assert TidalPlugin._parse_data_url(attrs) == expected @pytest.mark.parametrize( "attrs, expected", [({"copyright": {"text": "(P) 2024 Tidal"}}, "Tidal"), ({}, None)], ) def test_parse_label(self, attrs, expected): assert TidalPlugin._parse_label(attrs) == expected @pytest.mark.parametrize( "text, expected", [ # marker prefixes ("© 2017 Blackened Recordings", "Blackened Recordings"), ("(C) 2019 Ghosteen Ltd", "Ghosteen"), ("(P) 2007 Century Media Records Ltd.", "Century Media Records"), ("â„— 2024 Tidal", "Tidal"), # plain label name ("Lightning Bolt", "Lightning Bolt"), # under exclusive license to ( "Kim Gordon under exclusive license to Matador Records", "Matador Records", ), # issue #6796's own examples, verbatim — cover the corporate-relationship # clause, the territorial split, and the bare trailing suffix ( "© 2011 Motown Records, a Division of UMG Recordings, Inc.", "Motown Records", ), ( ( "© 2019 Atlantic Recording Corporation for the United States and " "WEA International Inc. for the world outside of the United States" ), "Atlantic Recording Corporation", ), ("(P) 1992 Zomba Recording LLC", "Zomba Recording"), ], ) def test_normalize_label(self, text, expected): assert TidalPlugin._normalize_label(text) == expected @pytest.mark.parametrize( "attrs, expected", [ ({"releaseDate": "2024-01-15"}, (2024, 1, 15)), ({}, None), ({"releaseDate": "2024"}, None), ], ) def test_parse_release_date(self, attrs, expected): assert TidalPlugin._parse_release_date(attrs) == expected @pytest.mark.parametrize( "duration,expected", [ ("PT30S", 30), ("PT3M30S", 210), ("PT4M", 240), ("PT1H", 3600), ("PT1H30M", 5400), ], ) def test_duration_conversions(self, duration, expected): assert TidalPlugin._duration_to_seconds(duration) == expected def test_duration_invalid_raises(self, caplog): with caplog.at_level(logging.WARNING): TidalPlugin._duration_to_seconds("invalid") assert "Invalid ISO 8601 duration: invalid" in caplog.text def test_popularity_with_float(self): assert TidalPlugin._parse_popularity({"popularity": 0.5}) == 50 assert TidalPlugin._parse_popularity({"popularity": 1.0}) == 100 assert TidalPlugin._parse_popularity({"popularity": 0.0}) == 0 @pytest.mark.parametrize( "artwork_data, artwork_by_id, expected", [ ( [{"id": "ca1", "type": "artworks"}], { "ca1": { "id": "ca1", "type": "artworks", "attributes": { "mediaType": "IMAGE", "files": [ { "href": "https://example.com/cover.jpg", "meta": {"width": 1280, "height": 1280}, } ], }, } }, "https://example.com/cover.jpg", ), ( [{"id": "ca1", "type": "artworks"}], { "ca1": { "id": "ca1", "type": "artworks", "attributes": {"mediaType": "IMAGE", "files": []}, } }, None, ), # No artworks in relationship data ([{"id": "ca1", "type": "coverArts"}], {}, None), # No cover art lookup ([{"id": "ca1", "type": "artworks"}], {}, None), # Empty relationships ({}, {}, None), ], ) def test_parse_artwork_url(self, artwork_data, artwork_by_id, expected): album: TidalAlbum = { "id": "al1", "type": "albums", "attributes": { "albumType": "ALBUM", "barcodeId": "123", "duration": "PT45M", "explicit": False, "mediaTags": [], "numberOfItems": 1, "numberOfVolumes": 1, "popularity": 0.5, "title": "Album", }, "relationships": {"coverArt": {"data": artwork_data, "links": {}}} if artwork_data else {}, } assert TidalPlugin._parse_artwork_url(album, artwork_by_id) == expected class TestTidalsync(TidalPluginTest): """Tests for the tidalsync command.""" def _run_tidalsync(self, *args: str) -> None: command = next( cmd for cmd in self.tidal.commands() if cmd.name == "tidalsync" ) opts, subargs = command.parser.parse_args(list(args)) command.func(self.lib, opts, subargs) def test_sync_updates_popularity(self): """Test sync_item_popularity fetches and stores popularity.""" item = self.add_item( tidal_track_id=490839595, title="Test Track", artist="Test Artist" ) track = _make_track( "490839595", "Test Track", "PT3M", "ISRC001", ["1001"] ) artist = _make_artist("1001", "Test Artist") self.tidal.api.get_tracks = Mock( return_value={"data": [track], "included": [artist]} ) self.tidal.sync_item_popularity([item], write=False) assert item["tidal_track_popularity"] == 50 assert item["tidal_updated"] is not None assert isinstance(item["tidal_updated"], (int, float)) def test_sync_skips_existing(self): """Test sync_item_popularity skips items with existing popularity.""" item = self.add_item( tidal_track_id=490839595, tidal_track_popularity=42, tidal_updated=time.time(), title="Test Track", artist="Test Artist", ) self.tidal.sync_item_popularity([item], write=False) assert item["tidal_track_popularity"] == 42 def test_sync_force_updates_existing(self): """Test sync_item_popularity with force re-fetches.""" item = self.add_item( tidal_track_id=490839595, tidal_track_popularity=42, tidal_updated=time.time(), title="Test Track", artist="Test Artist", ) track = _make_track( "490839595", "Test Track", "PT3M", "ISRC001", ["1001"] ) artist = _make_artist("1001", "Test Artist") self.tidal.api.get_tracks = Mock( return_value={"data": [track], "included": [artist]} ) self.tidal.sync_item_popularity([item], write=False, force=True) assert item["tidal_track_popularity"] == 50 def test_sync_skips_items_without_track_id(self): """Test sync_item_popularity skips items without tidal_track_id.""" item = self.add_item(title="No ID Track", artist="No ID Artist") self.tidal.sync_item_popularity([item], write=False) assert item.get("tidal_track_popularity") is None def test_sync_does_not_update_when_lookup_is_missing(self): """Test sync_item_popularity leaves stale data untouched on miss.""" item = self.add_item( tidal_track_id="490839595", title="Missing Track", artist="Missing Artist", ) self.tidal.api.get_tracks = Mock( return_value={"data": [], "included": []} ) self.tidal.sync_item_popularity([item], write=False) assert item.get("tidal_track_popularity") is None assert item.get("tidal_updated") is None def test_sync_updates_album_popularity(self): """Test sync_album_popularity fetches and stores album popularity.""" item = self.add_item( tidal_track_id="490839595", tidal_album_id="251380836", title="Test Track", artist="Test Artist", ) track = _make_track( "490839595", "Test Track", "PT3M", "ISRC001", ["1001"] ) artist = _make_artist("1001", "Test Artist") album_track = _make_track( "101", "Album Track", "PT3M", "ISRC001", ["1001"] ) album_data, _, artist_lookup = _make_album( "251380836", "Test Album", [album_track], ["1001"] ) album = self.lib.add_album([item]) album["tidal_album_id"] = "251380836" album.store() self.tidal.api.get_tracks = Mock( return_value={"data": [track], "included": [artist]} ) self.tidal.api.get_albums = Mock( return_value={ "data": [album_data], "included": [*artist_lookup.values()], } ) self.tidal.sync_item_popularity([item], write=False) self.tidal.sync_album_popularity([album], write=False) assert item["tidal_track_popularity"] == 50 assert album["tidal_album_popularity"] == 50 assert item["tidal_updated"] is not None def test_tidalsync_uses_first_query_argument(self): self.lib.items = Mock(return_value=["items"]) self.tidal.sync_item_popularity = Mock() self._run_tidalsync("path::aaa") self.lib.items.assert_called_once_with( ["data_source:tidal", "path::aaa"] ) self.tidal.sync_item_popularity.assert_called_once_with( ["items"], write=False, force=False ) def test_tidalsync_defaults_to_items(self): self.lib.items = Mock(return_value=["items"]) self.tidal.sync_item_popularity = Mock() self.tidal.sync_album_popularity = Mock() self._run_tidalsync() self.lib.items.assert_called_once_with(["data_source:tidal"]) self.tidal.sync_item_popularity.assert_called_once_with( ["items"], write=False, force=False ) self.tidal.sync_album_popularity.assert_not_called() def test_tidalsync_album_mode_uses_album_query(self): self.lib.albums = Mock(return_value=["albums"]) self.tidal.sync_item_popularity = Mock() self.tidal.sync_album_popularity = Mock() self._run_tidalsync("-a", "artist:Test") self.lib.albums.assert_called_once_with( ["data_source:tidal", "artist:Test"] ) self.tidal.sync_album_popularity.assert_called_once_with( ["albums"], write=False, force=False ) self.tidal.sync_item_popularity.assert_not_called() beetbox-beets-00724b7/test/plugins/test_metasync.py0000664000175000017500000000705515253035401021756 0ustar pieterpieterimport os import platform import time from datetime import datetime from beets.library import Item from beets.test import _common from beets.test.helper import IOMixin, PluginTestCase def _parsetime(s): return time.mktime(datetime.strptime(s, "%Y-%m-%d %H:%M:%S").timetuple()) def _is_windows(): return platform.system() == "Windows" class MetaSyncTest(IOMixin, PluginTestCase): plugin = "metasync" itunes_library_unix = _common.RSRC / "itunes_library_unix.xml" itunes_library_windows = _common.RSRC / "itunes_library_windows.xml" def setUp(self): super().setUp() self.config["metasync"]["source"] = "itunes" if _is_windows(): self.config["metasync"]["itunes"]["library"] = os.fsdecode( self.itunes_library_windows ) else: self.config["metasync"]["itunes"]["library"] = os.fsdecode( self.itunes_library_unix ) self._set_up_data() def _set_up_data(self): items = [_common.item() for _ in range(2)] items[0].title = "Tessellate" items[0].artist = "alt-J" items[0].albumartist = "alt-J" items[0].album = "An Awesome Wave" items[0].itunes_rating = 60 items[1].title = "Breezeblocks" items[1].artist = "alt-J" items[1].albumartist = "alt-J" items[1].album = "An Awesome Wave" if _is_windows(): items[ 0 ].path = "G:\\Music\\Alt-J\\An Awesome Wave\\03 Tessellate.mp3" items[ 1 ].path = "G:\\Music\\Alt-J\\An Awesome Wave\\04 Breezeblocks.mp3" else: items[0].path = "/Music/Alt-J/An Awesome Wave/03 Tessellate.mp3" items[1].path = "/Music/Alt-J/An Awesome Wave/04 Breezeblocks.mp3" for item in items: self.lib.add(item) def test_load_item_types(self): # This test also verifies that the MetaSources have loaded correctly assert "amarok_score" in Item._types assert "itunes_rating" in Item._types def test_pretend_sync_from_itunes(self): out = self.run_with_output("metasync", "-p") assert "itunes_rating: 60 -> 80" in out assert "itunes_rating: 100" in out assert "itunes_playcount: 31" in out assert "itunes_skipcount: 3" in out assert "itunes_lastplayed: 2015-05-04 12:20:51" in out assert "itunes_lastskipped: 2015-02-05 15:41:04" in out assert "itunes_dateadded: 2014-04-24 09:28:38" in out assert self.lib.items()[0].itunes_rating == 60 def test_sync_from_itunes(self): self.run_command("metasync") assert self.lib.items()[0].itunes_rating == 80 assert self.lib.items()[0].itunes_playcount == 0 assert self.lib.items()[0].itunes_skipcount == 3 assert not hasattr(self.lib.items()[0], "itunes_lastplayed") assert self.lib.items()[0].itunes_lastskipped == _parsetime( "2015-02-05 15:41:04" ) assert self.lib.items()[0].itunes_dateadded == _parsetime( "2014-04-24 09:28:38" ) assert self.lib.items()[1].itunes_rating == 100 assert self.lib.items()[1].itunes_playcount == 31 assert self.lib.items()[1].itunes_skipcount == 0 assert self.lib.items()[1].itunes_lastplayed == _parsetime( "2015-05-04 12:20:51" ) assert self.lib.items()[1].itunes_dateadded == _parsetime( "2014-04-24 09:28:38" ) assert not hasattr(self.lib.items()[1], "itunes_lastskipped") beetbox-beets-00724b7/test/plugins/test_ftintitle.py0000664000175000017500000005026315253035401022134 0ustar pieterpieter"""Tests for the 'ftintitle' plugin.""" from __future__ import annotations from typing import cast import pytest from beets import plugins from beets.autotag import AlbumInfo, TrackInfo from beets.importer import ImportSession, SingletonImportTask from beets.library import Album from beets.test.helper import PluginTestHelper from beetsplug import ftintitle class TestFtInTitlePluginFunctional(PluginTestHelper): plugin = "ftintitle" preload_plugin = False @pytest.mark.parametrize( "cfg, cmd_args, given, expected", [ pytest.param( {}, ("ftintitle",), ("Alice", "Song 1", "Alice"), ("Alice", "Song 1"), id="no-featured-artist", ), pytest.param( {"format": "feat {0}"}, ("ftintitle",), ("Alice ft. Bob", "Song 1", None), ("Alice", "Song 1 feat Bob"), id="no-albumartist-custom-format", ), pytest.param( {}, ("ftintitle",), ("Alice", "Song 1", None), ("Alice", "Song 1"), id="no-albumartist-no-feature", ), pytest.param( {"format": "featuring {0}"}, ("ftintitle",), ("Alice ft Bob", "Song 1", "George"), ("Alice", "Song 1 featuring Bob"), id="guest-artist-custom-format", ), pytest.param( {}, ("ftintitle",), ("Alice", "Song 1", "George"), ("Alice", "Song 1"), id="guest-artist-no-feature", ), # ---- drop (-d) variants ---- pytest.param( {}, ("ftintitle", "-d"), ("Alice ft Bob", "Song 1", "Alice"), ("Alice", "Song 1"), id="drop-self-ft", ), pytest.param( {}, ("ftintitle", "-d"), ("Alice", "Song 1", "Alice"), ("Alice", "Song 1"), id="drop-self-no-ft", ), pytest.param( {}, ("ftintitle", "-d"), ("Alice ft Bob", "Song 1", "George"), ("Alice", "Song 1"), id="drop-guest-ft", ), pytest.param( {}, ("ftintitle", "-d"), ("Alice", "Song 1", "George"), ("Alice", "Song 1"), id="drop-guest-no-ft", ), # ---- custom format variants ---- pytest.param( {"format": "feat. {}"}, ("ftintitle",), ("Alice ft Bob", "Song 1", "Alice"), ("Alice", "Song 1 feat. Bob"), id="custom-format-feat-dot", ), pytest.param( {"format": "featuring {}"}, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice"), ("Alice", "Song 1 featuring Bob"), id="custom-format-featuring", ), pytest.param( {"format": "with {}"}, ("ftintitle",), ("Alice feat Bob", "Song 1", "Alice"), ("Alice", "Song 1 with Bob"), id="custom-format-with", ), pytest.param( {"format": "ft. {}"}, ("ftintitle",), ("Alice (ft. Bob)", "Song 1", "Alice"), ("Alice", "Song 1 ft. Bob"), id="featured-artist-in-parentheses", ), # ---- keep_in_artist variants ---- pytest.param( {"format": "feat. {}", "keep_in_artist": True}, ("ftintitle",), ("Alice ft Bob", "Song 1", "Alice"), ("Alice ft Bob", "Song 1 feat. Bob"), id="keep-in-artist-add-to-title", ), pytest.param( {"format": "feat. {}", "keep_in_artist": True}, ("ftintitle", "-d"), ("Alice ft Bob", "Song 1", "Alice"), ("Alice ft Bob", "Song 1"), id="keep-in-artist-drop-from-title", ), # ---- custom_words variants ---- pytest.param( {"format": "featuring {}", "custom_words": ["med"]}, ("ftintitle",), ("Alice med Bob", "Song 1", "Alice"), ("Alice", "Song 1 featuring Bob"), id="custom-feat-words", ), pytest.param( { "format": "featuring {}", "keep_in_artist": True, "custom_words": ["med"], }, ("ftintitle",), ("Alice med Bob", "Song 1", "Alice"), ("Alice med Bob", "Song 1 featuring Bob"), id="custom-feat-words-keep-in-artists", ), pytest.param( { "format": "featuring {}", "keep_in_artist": True, "custom_words": ["med"], }, ("ftintitle", "-d"), ("Alice med Bob", "Song 1", "Alice"), ("Alice med Bob", "Song 1"), id="custom-feat-words-keep-in-artists-drop-from-title", ), # ---- preserve_album_artist variants ---- pytest.param( {"format": "feat. {}", "preserve_album_artist": True}, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice"), ("Alice", "Song 1 feat. Bob"), id="skip-if-artist-and-album-artists-is-the-same-different-match", ), pytest.param( {"format": "feat. {}", "preserve_album_artist": False}, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice"), ("Alice", "Song 1 feat. Bob"), id="skip-if-artist-and-album-artists-is-the-same-different-match-b", ), pytest.param( {"format": "feat. {}", "preserve_album_artist": True}, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice feat. Bob"), ("Alice feat. Bob", "Song 1"), id="skip-if-artist-and-album-artists-is-the-same-matching-match", ), pytest.param( {"format": "feat. {}", "preserve_album_artist": False}, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice feat. Bob"), ("Alice", "Song 1 feat. Bob"), id="skip-if-artist-and-album-artists-is-the-same-matching-match-b", ), # ---- titles with brackets/parentheses ---- pytest.param( {"format": "ft. {}", "bracket_keywords": ["mix"]}, ("ftintitle",), ("Alice ft. Bob", "Song 1 (Club Mix)", "Alice"), ("Alice", "Song 1 ft. Bob (Club Mix)"), id="ft-inserted-before-matching-bracket-keyword", ), pytest.param( {"format": "ft. {}", "bracket_keywords": ["nomatch"]}, ("ftintitle",), ("Alice ft. Bob", "Song 1 (Club Remix)", "Alice"), ("Alice", "Song 1 (Club Remix) ft. Bob"), id="ft-inserted-at-end-no-bracket-keyword-match", ), ], ) def test_ftintitle_functional( self, cfg: dict[str, str | bool | list[str]], cmd_args: tuple[str, ...], given: tuple[str, str, str | None], expected: tuple[str, str], ) -> None: config = { "drop": False, "auto": True, "keep_in_artist": False, "custom_words": [], **cfg, } artist, title, albumartist = given item = self.add_item( path="/", artist=artist, artist_sort=artist, title=title, albumartist=albumartist, ) with self.configure_plugin(config): self.run_command(*cmd_args) item.load() expected_artist, expected_title = expected assert item["artist"] == expected_artist assert item["title"] == expected_title def test_trackinfo_received_rewrites_artist_when_artist_credit_enabled( self, ) -> None: self.config["artist_credit"] = True info = TrackInfo( artist="Alice feat. Bob", artist_credit="Alice", artist_sort="Alice feat. Bob", artists=["Alice", "Bob"], artists_credit=["Alice"], title="Song", ) with self.configure_plugin({"auto": True}): plugins.send("trackinfo_received", info=info) assert info.artist == "Alice" assert info.artist_credit == "Alice" assert info.artist_sort == "Alice" assert info.artists == ["Alice", "Bob"] assert info.artists_credit == ["Alice"] assert info.title == "Song feat. Bob" assert info.item_data["title"] == "Song feat. Bob" @pytest.mark.parametrize( "config, artist, title, expected_artist, expected_title", [ pytest.param( {"auto": False}, "Alice feat. Bob", "Song", "Alice feat. Bob", "Song", id="auto-disabled", ), pytest.param( {"auto": True}, "Alice", "Song", "Alice", "Song", id="no-feature", ), pytest.param( {"auto": True}, "Alice feat. Bob", "Song feat. Bob", "Alice", "Song feat. Bob", id="existing-title-feature", ), ], ) def test_trackinfo_received_rewrites_or_skips_simple_cases( self, config: dict[str, bool], artist: str, title: str, expected_artist: str, expected_title: str, ) -> None: info = TrackInfo(artist=artist, title=title) with self.configure_plugin(config): plugins.send("trackinfo_received", info=info) assert info.artist == expected_artist assert info.title == expected_title def test_ft_in_title_reports_no_change_for_info_drop_keep_noop( self, ) -> None: info = TrackInfo(artist="Alice feat. Bob", title="Song") with self.configure_plugin({"drop": True, "keep_in_artist": True}): plugin = next(iter(plugins.find_plugins())) assert isinstance(plugin, ftintitle.FtInTitlePlugin) assert plugin.ft_in_title(info, "") is False assert info.artist == "Alice feat. Bob" assert info.title == "Song" def test_trackinfo_received_preserves_artist_credit_when_disabled( self, ) -> None: self.config["artist_credit"] = False info = TrackInfo( artist="Alice feat. Bob", artist_credit="Alice feat. Bobby", title="Song", ) with self.configure_plugin({"auto": True}): plugins.send("trackinfo_received", info=info) assert info.artist == "Alice" assert info.artist_credit == "Alice feat. Bobby" assert info.title == "Song feat. Bob" assert info.item_data["artist_credit"] == "Alice feat. Bobby" def test_ft_in_title_reports_no_change_for_item_drop_keep_noop( self, ) -> None: item = self.add_item( path="/", artist="Alice feat. Bob", artist_sort="", title="Song", albumartist="Alice", ) with self.configure_plugin({"drop": True, "keep_in_artist": True}): plugin = next(iter(plugins.find_plugins())) assert isinstance(plugin, ftintitle.FtInTitlePlugin) assert ( plugin.ft_in_title(item, item.get("albumartist") or "") is False ) assert item.artist == "Alice feat. Bob" assert item.title == "Song" def test_imported_stage_rewrites_imported_items(self) -> None: item = self.add_item( path="/", artist="Alice feat. Bob", title="Song", albumartist="Alice", ) with self.configure_plugin({"auto": True}): plugin = next(iter(plugins.find_plugins())) assert isinstance(plugin, ftintitle.FtInTitlePlugin) plugin.imported( cast(ImportSession, None), SingletonImportTask(None, item) ) item.load() assert item.artist == "Alice" assert item.title == "Song feat. Bob" def test_albuminfo_received_rewrites_tracks_with_album_artist(self) -> None: track_info = TrackInfo( artist="Alice & Bob", artist_sort="Alice & Bob", title="Song" ) info = AlbumInfo(artist="Alice", album="Album", tracks=[track_info]) with self.configure_plugin({"auto": True}): plugins.send("albuminfo_received", info=info) assert track_info.artist == "Alice" assert track_info.artist_sort == "Alice" assert track_info.title == "Song feat. Bob" assert track_info.item_data["artist"] == "Alice" assert track_info.item_data["title"] == "Song feat. Bob" @pytest.mark.parametrize( "artist,albumartist,expected", [ ("Alice ft. Bob", "Alice", "Bob"), ("Alice feat Bob", "Alice", "Bob"), ("Alice featuring Bob", "Alice", "Bob"), ("Alice & Bob", "Alice", "Bob"), ("Alice and Bob", "Alice", "Bob"), ("Alice With Bob", "Alice", "Bob"), ("Alice (ft. Bob)", "Alice", "Bob"), ("Alice [ft. Bob]", "Bob", "Alice"), ("Alice defeat Bob", "Alice", None), ("Alice & Bob", "Bob", "Alice"), ("Alice ft. Bob", "Bob", "Alice"), ("Alice ft. Carol", "Bob", "Carol"), ], ) def test_find_feat_part( artist: str, albumartist: str, expected: str | None ) -> None: assert ftintitle.find_feat_part(artist, albumartist) == expected @pytest.mark.parametrize( "given,expected", [ ("Alice ft. Bob", ("Alice", "Bob")), ("Alice feat Bob", ("Alice", "Bob")), ("Alice feat. Bob", ("Alice", "Bob")), ("Alice featuring Bob", ("Alice", "Bob")), ("Alice & Bob", ("Alice", "Bob")), ("Alice, Bob & Charlie", ("Alice", "Bob & Charlie")), ( "Alice, Bob & Charlie feat. Xavier", ("Alice, Bob & Charlie", "Xavier"), ), ("Alice and Bob", ("Alice", "Bob")), ("Alice With Bob", ("Alice", "Bob")), ("Alice defeat Bob", ("Alice defeat Bob", None)), ("Alice & Bob feat Charlie", ("Alice & Bob", "Charlie")), ("Alice & Bob ft. Charlie", ("Alice & Bob", "Charlie")), ("Alice & Bob featuring Charlie", ("Alice & Bob", "Charlie")), ("Alice and Bob feat Charlie", ("Alice and Bob", "Charlie")), ("Alice (ft. Bob)", ("Alice", "Bob")), ("Alice [& Bob]", ("Alice", "Bob")), ], ) def test_split_on_feat(given: str, expected: tuple[str, str | None]) -> None: assert ftintitle.split_on_feat(given) == expected @pytest.mark.parametrize( "given,keywords,expected", [ ## default keywords # different braces and keywords ("Song (Remix)", None, "Song ft. Bob (Remix)"), ("Song [Version]", None, "Song ft. Bob [Version]"), ("Song {Extended Mix}", None, "Song ft. Bob {Extended Mix}"), ("Song ", None, "Song ft. Bob "), # two keyword clauses ("Song (Remix) (Live)", None, "Song ft. Bob (Remix) (Live)"), # brace insensitivity ("Song (Live) [Remix]", None, "Song ft. Bob (Live) [Remix]"), ("Song [Edit] (Remastered)", None, "Song ft. Bob [Edit] (Remastered)"), # negative cases ("Song", None, "Song ft. Bob"), # no clause ("Song (Arbitrary)", None, "Song (Arbitrary) ft. Bob"), # no keyword ("Song (", None, "Song ( ft. Bob"), # no matching brace or keyword ("Song (Live", None, "Song (Live ft. Bob"), # no matching brace with keyword # one keyword clause, one non-keyword clause ("Song (Live) (Arbitrary)", None, "Song ft. Bob (Live) (Arbitrary)"), ("Song (Arbitrary) (Remix)", None, "Song (Arbitrary) ft. Bob (Remix)"), # nested brackets - same type ("Song (Remix (Extended))", None, "Song ft. Bob (Remix (Extended))"), ("Song [Arbitrary [Description]]", None, "Song [Arbitrary [Description]] ft. Bob"), # nested brackets - different types ("Song (Remix [Extended])", None, "Song ft. Bob (Remix [Extended])"), # nested - returns outer start position despite inner keyword ("Song [Arbitrary {Extended}]", None, "Song ft. Bob [Arbitrary {Extended}]"), ("Song {Live }", None, "Song ft. Bob {Live }"), ("Song ", None, "Song ft. Bob "), ("Song [Live]", None, "Song ft. Bob [Live]"), ("Song (Version) ", None, "Song ft. Bob (Version) "), ("Song (Arbitrary [Description])", None, "Song (Arbitrary [Description]) ft. Bob"), ("Song [Description (Arbitrary)]", None, "Song [Description (Arbitrary)] ft. Bob"), ## custom keywords ("Song (Live)", ["live"], "Song ft. Bob (Live)"), ("Song (Concert)", ["concert"], "Song ft. Bob (Concert)"), ("Song (Remix)", ["custom"], "Song (Remix) ft. Bob"), ("Song (Custom)", ["custom"], "Song ft. Bob (Custom)"), ("Song", [], "Song ft. Bob"), ("Song (", [], "Song ( ft. Bob"), # Multi-word keyword tests ("Song (Club Mix)", ["club mix"], "Song ft. Bob (Club Mix)"), # Positive: matches multi-word ("Song (Club Remix)", ["club mix"], "Song (Club Remix) ft. Bob"), # Negative: no match ], ) # fmt: skip def test_insert_ft_into_title( given: str, keywords: list[str] | None, expected: str ) -> None: assert ( ftintitle.FtInTitlePlugin.insert_ft_into_title( given, "ft. Bob", keywords ) == expected ) @pytest.mark.parametrize( "given,expected", [ ("Alice ft. Bob", True), ("Alice feat. Bob", True), ("Alice feat Bob", True), ("Alice featuring Bob", True), ("Alice (ft. Bob)", True), ("Alice (feat. Bob)", True), ("Alice [ft. Bob]", True), ("Alice [feat. Bob]", True), ("Alice defeat Bob", False), ("Aliceft.Bob", False), ("Alice (defeat Bob)", False), ("Live and Let Go", False), ("Come With Me", False), ], ) def test_contains_feat(given: str, expected: bool) -> None: assert ftintitle.contains_feat(given) is expected @pytest.mark.parametrize( "given,custom_words,expected", [ ("Alice ft. Bob", [], True), ("Alice feat. Bob", [], True), ("Alice feat Bob", [], True), ("Alice featuring Bob", [], True), ("Alice (ft. Bob)", [], True), ("Alice (feat. Bob)", [], True), ("Alice [ft. Bob]", [], True), ("Alice [feat. Bob]", [], True), ("Alice defeat Bob", [], False), ("Aliceft.Bob", [], False), ("Alice (defeat Bob)", [], False), ("Live and Let Go", [], False), ("Come With Me", [], False), ("Alice x Bob", ["x"], True), ("Alice x Bob", ["X"], True), ("Alice och Xavier", ["x"], False), ("Alice ft. Xavier", ["x"], True), ("Alice med Carol", ["med"], True), ("Alice med Carol", [], False), ], ) def test_custom_words( given: str, custom_words: list[str], expected: bool ) -> None: assert ftintitle.contains_feat(given, custom_words) is expected def test_album_template_value(config): config["ftintitle"]["custom_words"] = [] album = Album() album["albumartist"] = "Foo ft. Bar" assert ftintitle._album_artist_no_feat(album) == "Foo" album["albumartist"] = "Foobar" assert ftintitle._album_artist_no_feat(album) == "Foobar" beetbox-beets-00724b7/test/plugins/test_types_plugin.py0000664000175000017500000001262115253035401022650 0ustar pieterpieterimport time from datetime import datetime import pytest from confuse import ConfigValueError from beets.test.helper import IOMixin, PluginTestCase class TypesPluginTest(IOMixin, PluginTestCase): plugin = "types" def test_integer_modify_and_query(self): self.config["types"] = {"myint": "int"} item = self.add_item(artist="aaa") # Do not match unset values out = self.list("myint:1..3") assert "" == out self.modify("myint=2") item.load() assert item["myint"] == 2 # Match in range out = self.list("myint:1..3") assert "aaa" in out def test_album_integer_modify_and_query(self): self.config["types"] = {"myint": "int"} album = self.add_album(albumartist="aaa") # Do not match unset values out = self.list_album("myint:1..3") assert "" == out self.modify("-a", "myint=2") album.load() assert album["myint"] == 2 # Match in range out = self.list_album("myint:1..3") assert "aaa" in out def test_float_modify_and_query(self): self.config["types"] = {"myfloat": "float"} item = self.add_item(artist="aaa") # Do not match unset values out = self.list("myfloat:10..0") assert "" == out self.modify("myfloat=-9.1") item.load() assert item["myfloat"] == -9.1 # Match in range out = self.list("myfloat:-10..0") assert "aaa" in out def test_bool_modify_and_query(self): self.config["types"] = {"mybool": "bool"} true = self.add_item(artist="true") false = self.add_item(artist="false") self.add_item(artist="unset") # Do not match unset values out = self.list("mybool:true, mybool:false") assert "" == out # Set true self.modify("mybool=1", "artist:true") true.load() assert true["mybool"] # Set false self.modify("mybool=false", "artist:false") false.load() assert not false["mybool"] # Query bools out = self.list("mybool:true", "$artist $mybool") assert "true True" == out out = self.list("mybool:false", "$artist $mybool") # Dealing with unset fields? # assert 'false False' == out # out = self.list('mybool:', '$artist $mybool') # assert 'unset $mybool' in out def test_date_modify_and_query(self): self.config["types"] = {"mydate": "date"} # FIXME parsing should also work with default time format self.config["time_format"] = "%Y-%m-%d" old = self.add_item(artist="prince") new = self.add_item(artist="britney") # Do not match unset values out = self.list("mydate:..2000") assert "" == out self.modify("mydate=1999-01-01", "artist:prince") old.load() assert old["mydate"] == mktime(1999, 1, 1) self.modify("mydate=1999-12-30", "artist:britney") new.load() assert new["mydate"] == mktime(1999, 12, 30) # Match in range out = self.list("mydate:..1999-07", "$artist $mydate") assert "prince 1999-01-01" == out # FIXME some sort of timezone issue here # out = self.list('mydate:1999-12-30', '$artist $mydate') # assert 'britney 1999-12-30' == out def test_unknown_type_error(self): self.config["types"] = {"flex": "unkown type"} with pytest.raises(ConfigValueError): self.add_item(flex="test") def test_template_if_def(self): # Tests for a subtle bug when using %ifdef in templates along with # types that have truthy default values (e.g. '0', '0.0', 'False') # https://github.com/beetbox/beets/issues/3852 self.config["types"] = { "playcount": "int", "rating": "float", "starred": "bool", } with_fields = self.add_item(artist="prince") self.modify("playcount=10", "artist=prince") self.modify("rating=5.0", "artist=prince") self.modify("starred=yes", "artist=prince") with_fields.load() without_fields = self.add_item(artist="britney") int_template = "%ifdef{playcount,Play count: $playcount,Not played}" assert with_fields.evaluate_template(int_template) == "Play count: 10" assert without_fields.evaluate_template(int_template) == "Not played" float_template = "%ifdef{rating,Rating: $rating,Not rated}" assert with_fields.evaluate_template(float_template) == "Rating: 5.0" assert without_fields.evaluate_template(float_template) == "Not rated" bool_template = "%ifdef{starred,Starred: $starred,Not starred}" assert with_fields.evaluate_template(bool_template).lower() in ( "starred: true", "starred: yes", "starred: y", ) assert without_fields.evaluate_template(bool_template) == "Not starred" def modify(self, *args): return self.run_with_output( "modify", "--yes", "--nowrite", "--nomove", *args ) def list(self, query, fmt="$artist - $album - $title"): return self.run_with_output("ls", "-f", fmt, query).strip() def list_album(self, query, fmt="$albumartist - $album - $title"): return self.run_with_output("ls", "-a", "-f", fmt, query).strip() def mktime(*args): return time.mktime(datetime(*args).timetuple()) beetbox-beets-00724b7/test/plugins/lyrics_pages.py0000664000175000017500000005244515253035401021563 0ustar pieterpieterfrom __future__ import annotations import os import textwrap from typing import NamedTuple from urllib.parse import urlparse import pytest def xfail_on_ci(msg: str) -> pytest.MarkDecorator: return pytest.mark.xfail( bool(os.environ.get("GITHUB_ACTIONS")), reason=msg, raises=AssertionError, ) class LyricsPage(NamedTuple): """Lyrics page representation for integrated tests.""" url: str lyrics: str artist: str = "The Beatles" track_title: str = "Lady Madonna" language: str = "EN" url_title: str | None = None # only relevant to the Google backend marks: list[str] = [] # markers for pytest.param # noqa: RUF012 def __str__(self) -> str: """Return name of this test case.""" return f"{self.backend}-{self.source}" @classmethod def make(cls, url, lyrics, *args, **kwargs): return cls(url, textwrap.dedent(lyrics).strip(), *args, **kwargs) @property def root_url(self) -> str: return urlparse(self.url).netloc @property def source(self) -> str: return ( self.root_url.replace("www.", "").replace("api.", "").split(".")[0] ) @property def backend(self) -> str: if (source := self.source) in { "genius", "tekstowo", "lrclib", "lrcmux", }: return source return "google" lyrics_pages = [ LyricsPage.make( "http://www.absolutelyrics.com/lyrics/view/the_beatles/lady_madonna", """ The Beatles - Lady Madonna Lady Madonna, children at your feet. Wonder how you manage to make ends meet. Who finds the money? When you pay the rent? Did you think that money was heaven sent? Friday night arrives without a suitcase. Sunday morning creep in like a nun. Monday's child has learned to tie his bootlace. See how they run. Lady Madonna, baby at your breast. Wonder how you manage to feed the rest. See how they run. Lady Madonna, lying on the bed, Listen to the music playing in your head. Tuesday afternoon is never ending. Wednesday morning papers didn't come. Thursday night you stockings needed mending. See how they run. Lady Madonna, children at your feet. Wonder how you manage to make ends meet. """, url_title="Lady Madonna Lyrics :: The Beatles - Absolute Lyrics", ), LyricsPage.make( "https://www.azlyrics.com/lyrics/beatles/ladymadonna.html", """ Lady Madonna, children at your feet Wonder how you manage to make ends meet Who finds the money when you pay the rent Did you think that money was Heaven sent? Friday night arrives without a suitcase Sunday morning creeping like a nun Monday's child has learned to tie his bootlace See how they run Lady Madonna, baby at your breast Wonders how you manage to feed the rest? See how they run Lady Madonna lying on the bed Listen to the music playing in your head Tuesday afternoon is never ending Wednesday morning papers didn't come Thursday night your stockings needed mending See how they run Lady Madonna, children at your feet Wonder how you manage to make ends meet """, url_title="The Beatles - Lady Madonna Lyrics | AZLyrics.com", marks=[xfail_on_ci("AZLyrics is blocked by Cloudflare")], ), LyricsPage.make( "https://www.dainuzodziai.lt/m/mergaites-nori-mylet-atlanta/", """ Jos nesuspÄ—ja skriet paskui vÄ—jÄ… Bangos į krantÄ… grąžina jas vÄ—l Jos karÅ¡tÄ… saulÄ™ paliesti norÄ—jo Ant kranto palikÄ™ visas negandas Bet jos nori mylÄ—t Jos nenori liÅ«dÄ—t Leisk mergaitÄ—ms mylÄ—t Kaip jos moka mylÄ—t Koks vakaras Å¡iltas ir nieko nestinga Veidus apÅ¡vieÄ�ia žaisminga Å¡viesa Jos buvo laimingos prie jÅ«ros kur liko Tik vÄ—jas iÅ¡mokÄ™s visas jų dainas """, artist="Atlanta", track_title="MergaitÄ—s Nori MylÄ—t", language="LT", url_title="MergaitÄ—s nori mylÄ—t – Atlanta | Dainų Žodžiai", marks=[xfail_on_ci("Expired SSL certificate")], ), LyricsPage.make( "https://genius.com/The-beatles-lady-madonna-lyrics", """ [Verse 1: Paul McCartney] Lady Madonna, children at your feet Wonder how you manage to make ends meet Who finds the money when you pay the rent? Did you think that money was heaven sent? [Bridge: Paul McCartney, Paul McCartney, John Lennon & George Harrison] Friday night arrives without a suitcase Sunday morning creeping like a nun Monday's child has learned to tie his bootlace See how they run [Verse 2: Paul McCartney] Lady Madonna, baby at your breast Wonders how you manage to feed the rest [Tenor Saxophone Solo: Ronnie Scott] [Bridge: John Lennon & George Harrison, Paul McCartney, John Lennon & George Harrison] Pa-pa-pa-pa, pa-pa-pa-pa-pa Pa-pa-pa-pa-pa, pa-pa-pa, pa-pa, pa-pa Pa-pa-pa-pa, pa-pa-pa-pa-pa See how they run [Verse 3: Paul McCartney] Lady Madonna, lying on the bed Listen to the music playing in your head [Bridge: Paul McCartney, John Lennon & George Harrison, Paul McCartney, John Lennon & George Harrison] Tuesday afternoon is never ending (Pa-pa-pa-pa, pa-pa-pa-pa-pa) Wednesday morning, papers didn't come (Pa-pa-pa-pa-pa, pa-pa-pa, pa-pa, pa-pa) Thursday night, your stockings needed mending (Pa-pa-pa-pa, pa-pa-pa-pa-pa) See how they run [Verse 4: Paul McCartney] Lady Madonna, children at your feet Wonder how you manage to make ends meet """, # noqa: E501 marks=[xfail_on_ci("Genius returns 403 FORBIDDEN in CI")], ), LyricsPage.make( "https://www.lacoccinelle.net/259956-the-beatles-lady-madonna.html", """ Lady Madonna Mademoiselle Madonna Lady Madonna, children at your feet. Mademoiselle Madonna, les enfants à vos pieds Wonder how you manage to make ends meet. Je me demande comment vous vous débrouillez pour joindre les deux bouts Who finds the money, when you pay the rent ? Qui trouve l'argent pour payer le loyer ? Did you think that money was heaven sent ? Pensiez-vous que ça allait être envoyé du ciel ? Friday night arrives without a suitcase. Le vendredi soir arrive sans bagages Sunday morning creeping like a nun. Le dimanche matin elle se traine comme une nonne Monday's child has learned to tie his bootlace. Lundi l'enfant a appris à lacer ses chaussures See how they run. Regardez comme ils courent Lady Madonna, baby at your breast. Mademoiselle Madonna, le bébé a votre sein Wonder how you manage to feed the rest. Je me demande comment vous faites pour nourrir le reste Lady Madonna, lying on the bed, Mademoiselle Madonna, couchée sur votre lit Listen to the music playing in your head. Vous écoutez la musique qui joue dans votre tête Tuesday afternoon is never ending. Le mardi après-midi n'en finit pas Wednesday morning papers didn't come. Le mercredi matin les journaux ne sont pas arrivés Thursday night you stockings needed mending. Jeudi soir, vos bas avaient besoin d'être réparés See how they run. Regardez comme ils filent Lady Madonna, children at your feet. Mademoiselle Madonna, les enfants à vos pieds Wonder how you manage to make ends meet. Je me demande comment vous vous débrouillez pour joindre les deux bouts """, url_title="Paroles et traduction The Beatles : Lady Madonna - paroles de chanson", # noqa: E501 language="FR", ), LyricsPage.make( # note that this URL needs to be followed with a slash, otherwise it # redirects to the same URL with a slash "https://www.letras.mus.br/the-beatles/275/", """ Lady Madonna Children at your feet Wonder how you manage To make ends meet Who finds the money When you pay the rent? Did you think that money Was Heaven sent? Friday night arrives without a suitcase Sunday morning creeping like a nun Monday's child has learned To tie his bootlace See how they run Lady Madonna Baby at your breast Wonders how you manage To feed the rest See how they run Lady Madonna Lying on the bed Listen to the music Playing in your head Tuesday afternoon is neverending Wednesday morning papers didn't come Thursday night your stockings Needed mending See how they run Lady Madonna Children at your feet Wonder how you manage To make ends meet """, url_title="Lady Madonna - The Beatles - LETRAS.MUS.BR", ), LyricsPage.make( "https://lrclib.net/api/get/23863037", """ [00:08.35] Lady Madonna, children at your feet [00:12.85] Wonder how you manage to make ends meet [00:17.56] Who finds the money when you pay the rent [00:21.78] Did you think that money was heaven sent [00:26.22] Friday night arrives without a suitcase [00:30.02] Sunday morning creeping like a nun [00:34.53] Monday's child has learned to tie his bootlace [00:39.18] See how they run [00:43.33] Lady Madonna, baby at your breast [00:48.50] Wonders how you manage to feed the rest [00:52.54] [01:01.32] Ba-ba, ba-ba, ba-ba, ba-ba-ba [01:05.03] Ba-ba, ba-ba, ba-ba, ba, ba-ba, ba-ba [01:09.58] Ba-ba, ba-ba, ba-ba, ba-ba-ba [01:14.27] See how they run [01:19.05] Lady Madonna, lying on the bed [01:22.99] Listen to the music playing in your head [01:27.92] [01:36.33] Tuesday afternoon is never ending [01:40.47] Wednesday morning papers didn't come [01:44.76] Thursday night your stockings needed mending [01:49.35] See how they run [01:53.73] Lady Madonna, children at your feet [01:58.65] Wonder how you manage to make ends meet [02:06.04] """, ), LyricsPage.make( "https://api.lrcmux.dev/get?artist=The+Beatles&title=Lady+Madonna&duration=186&format=lrc&level=line&sources=ytmusic", """ [00:00.00] [00:08.71] Lady Madonna, children at your feet [00:13.08] Wonder how you manage to make ends meet [00:17.43] Who finds the money when you pay the rent? [00:21.92] Did you think that money was Heaven-sent? [00:26.21] Friday night arrives without a suitcase [00:30.54] Sunday morning creeping like a nun [00:35.07] Monday's child has learned to tie his bootlace [00:39.37] See how they run [00:43.80] Lady Madonna, baby at your breast [00:48.23] Wonders how you manage to feed the rest [00:55.32] [01:01.30] Pa-pa-pa-pa, pa-pa-pa-pa-pa [01:05.68] Pa-pa-pa-pa, pa-pa-pa-pa-pa-pa-pa [01:09.86] Pa-pa-pa-pa, pa-pa-pa-pa-pa [01:14.40] See how they run [01:18.81] Lady Madonna lying on the bed [01:23.25] Listen to the music playing in your head [01:30.21] [01:36.40] Tuesday afternoon is never ending [01:40.78] Wednesday morning papers didn't come [01:45.06] Thursday night you stocking needed mending [01:49.48] See how they run [01:53.90] Lady Madonna, children at your feet [01:58.42] Wonder how you manage to make ends meet """, ), LyricsPage.make( "https://www.lyricsmania.com/lady_madonna_lyrics_the_beatles.html", """ Lady Madonna, children at your feet. Wonder how you manage to make ends meet. Who finds the money? When you pay the rent? Did you think that money was heaven sent? Friday night arrives without a suitcase. Sunday morning creep in like a nun. Monday's child has learned to tie his bootlace. See how they run. Lady Madonna, baby at your breast. Wonder how you manage to feed the rest. See how they run. Lady Madonna, lying on the bed, Listen to the music playing in your head. Tuesday afternoon is never ending. Wednesday morning papers didn't come. Thursday night you stockings needed mending. See how they run. Lady Madonna, children at your feet. Wonder how you manage to make ends meet. """, url_title="The Beatles - Lady Madonna Lyrics", ), LyricsPage.make( "https://www.lyricsmode.com/lyrics/b/beatles/mother_natures_son.html", """ Born a poor young country boy, Mother Nature's son All day long I'm sitting singing songs for everyone Sit beside a mountain stream, see her waters rise Listen to the pretty sound of music as she flies Doo doo doo doo doo doo doo doo doo doo doo Doo doo doo doo doo doo doo doo doo Doo doo doo Find me in my field of grass, Mother Nature's son Swaying daises sing a lazy song beneath the sun Doo doo doo doo doo doo doo doo doo doo doo Doo doo doo doo doo doo doo doo doo Doo doo doo doo doo doo Yeah yeah yeah Mm mm mm mm mm mm mm Mm mm mm, ooh ooh ooh Mm mm mm mm mm mm mm Mm mm mm mm, wah wah wah Wah, Mother Nature's son """, artist="The Beatles", track_title="Mother Nature's Son", url_title=( "Mother Nature's Son lyrics by The Beatles - original song full" " text. Official Mother Nature's Son lyrics, 2025 version" " | LyricsMode.com" ), ), LyricsPage.make( "https://www.lyricsontop.com/amy-winehouse-songs/jazz-n-blues-lyrics.html", """ It's all gone within two days, Follow my father His extravagant ways So, if I got it out I'll spend it all. Heading In parkway, til I hit the wall. I cross my fingers at the cash machine, As I check my balance I kiss the screen, I love it when it says I got the main's To got o Miss Sixty and pick up my jeans. Money ever last long Had to fight what's wrong, Blow it all on bags and shoes, Jazz n' blues. Money ever last long, Had to fight what's wrong, Blow it all on bags and shoes, Jazz n' blues. Standing to the … bar today, Waiting impatient to throw my cash away, For that Russian JD and coke Had the drinks all night, and now I am bold But that's cool, cause I can buy more from you. And I didn't forgot about that 50 Compton, Tell you what? My fancy's coming through I'll take you at shopping, can you wait til next June? Yeah, Money ever last long Had to fight what's wrong, Blow it all on bags and shoes, Jazz n' blues. Money ever last long, Had to fight what's wrong, Blow it all on bags and shoes, Jazz n' blues. (Instrumental Break) Money ever last long Had to fight what's wrong, Blow it all on bags and shoes, Jazz n' blues. Money ever last long, Had to fight what's wrong, Blow it all on bags and shoes, Jazz n' blues. Money ever last long, Had to fight what's wrong, Blow it all on bags and shoes, Jazz n' blues. """, artist="Amy Winehouse", track_title="Jazz N' Blues", url_title="Amy Winehouse - Jazz N' Blues lyrics complete", ), LyricsPage.make( "https://www.musica.com/letras.asp?letra=59862", """ Lady Madonna, children at your feet Wonder how you manage to make ends meet Who finds the money when you pay the rent? Did you think that money was heaven sent? Friday night arrives without a suitcase Sunday morning creeping like a nun Monday's child has learned to tie his bootlace See how they run Lady Madonna, baby at your breast Wonders how you manage to feed the rest See how they run Lady Madonna lying on the bed Listen to the music playing in your head Tuesday afternoon is never ending Wednesday morning papers didn't come Thursday night your stockings needed mending See how they run Lady Madonna, children at your feet Wonder how you manage to make ends meet """, url_title="Lady Madonna - Letra - The Beatles - Musica.com", ), LyricsPage.make( "https://www.paroles.net/the-beatles/paroles-lady-madonna", """ Lady Madonna, children at your feet. Wonder how you manage to make ends meet. Who finds the money? When you pay the rent? Did you think that money was heaven sent? Friday night arrives without a suitcase. Sunday morning creep in like a nun. Monday's child has learned to tie his bootlace. See how they run. Lady Madonna, baby at your breast. Wonders how you manage to feed the rest. See how they run. Lady Madonna, lying on the bed, Listen to the music playing in your head. Tuesday afternoon is never ending. Wednesday morning papers didn't come. Thursday night your stockings needed mending. See how they run. Lady Madonna, children at your feet. Wonder how you manage to make ends meet. """, url_title="Paroles Lady Madonna par The Beatles - Lyrics - Paroles.net", ), LyricsPage.make( "https://www.songlyrics.com/the-beatles/lady-madonna-lyrics", """ Lady Madonna, children at your feet Wonder how you manage to make ends meet Who finds the money? When you pay the rent? Did you think that money was Heaven sent? Friday night arrives without a suitcase Sunday morning creep in like a nun Monday's child has learned to tie his bootlace See how they run Lady Madonna, baby at your breast Wonder how you manage to feed the rest See how they run Lady Madonna, lying on the bed Listen to the music playing in your head Tuesday afternoon is never ending Wednesday morning papers didn't come Thursday night you stockings needed mending See how they run Lady Madonna, children at your feet Wonder how you manage to make ends meet """, url_title="THE BEATLES - LADY MADONNA LYRICS", marks=[xfail_on_ci("Songlyrics is blocked by Cloudflare")], ), LyricsPage.make( "https://sweetslyrics.com/the-beatles/lady-madonna-lyrics", """ Lady Madonna, children at your feet. Wonder how you manage to make ends meet. Who finds the money when you pay the rent? Did you think that money was heaven sent? Friday night arrives without a suitcase. Sunday morning creeping like a nun. Monday's child has learned to tie his bootlace. See how they run... Lady Madonna, baby at your breast. Wonders how you manage to feed the rest. (Sax solo) See how they run... Lady Madonna, lying on the bed. Listen to the music playing in your head. Tuesday afternoon is never ending. Wednesday morning papers didn't come. Thursday night your stockings needed mending. See how they run... Lady Madonna, children at your feet. Wonder how you manage to make ends meet. """, url_title="The Beatles - Lady Madonna", marks=[xfail_on_ci("Sweetslyrics also fails with 403 FORBIDDEN in CI")], ), LyricsPage.make( "https://www.tekstowo.pl/piosenka,the_beatles,lady_madonna.html", """ Lady Madonna, Children at your feet Wonder how you manage to make ends meet. Who find the money When you pay the rent? Did you think that money was Heaven sent? Friday night arrives without a suitcase Sunday morning creeping like a nun Monday's child has learned to tie his bootlace See how they run Lady Madonna Baby at your breast Wonders how you manage to feed the rest See how they run Lady Madonna Lying on the bed Listen to the music playing in your head Tuesday afternoon is neverending Wednesday morning papers didn't come Thursday night your stockings needed mending See how they run Lady Madonna, Children at your feet Wonder how you manage to make ends meet """, marks=[pytest.mark.xfail(reason="Tekstowo seems to be broken again")], ), ] beetbox-beets-00724b7/test/plugins/conftest.py0000664000175000017500000000101015253035401020702 0ustar pieterpieterfrom __future__ import annotations from typing import TYPE_CHECKING import pytest import requests if TYPE_CHECKING: from requests_mock import Mocker @pytest.fixture def requests_mock(requests_mock, monkeypatch) -> Mocker: """Use plain session wherever MB requests are mocked. This avoids rate limiting requests to speed up tests. """ monkeypatch.setattr( "beetsplug._utils.musicbrainz.MusicBrainzAPI.create_session", lambda _: requests.Session(), ) return requests_mock beetbox-beets-00724b7/test/plugins/test_duplicates.py0000664000175000017500000000351315253035401022263 0ustar pieterpieterimport pytest from beets.test.helper import IOMixin, PluginMixin, TestHelper class TestDuplicatesPlugin(PluginMixin, TestHelper, IOMixin): plugin = "duplicates" @pytest.fixture(autouse=True) def setup(self): self.setup_beets() self.dup_item = self.create_item( album="Pretend Album", albumartist="Pretend Artist", artist="Pretend Artist", title="Pretend Track", genres=["Original Genre"], mb_trackid="abc", mb_albumid="def", ) try: yield finally: self.teardown_beets() self.dup_item = None def run_cmd(self, count=False, path=False) -> str: args = ["duplicates"] if count: args.append("--count") if path: args.append("--path") return self.run_with_output(*args).strip() def create_dups(self, count: int): for _ in range(count): self.lib.add(self.dup_item) def test_duplicate(self): self.create_dups(2) out = self.run_cmd() assert self.dup_item.artist in out assert self.dup_item.album in out assert self.dup_item.title in out def test_duplicate_path(self): self.create_dups(2) out = self.run_cmd(path=True) assert str(self.dup_item.filepath) in out def test_duplicate_with_count(self): self.create_dups(4) out = self.run_cmd(count=True) assert self.dup_item.artist in out assert self.dup_item.album in out assert self.dup_item.title in out assert out.endswith("3") def test_duplicate_path_with_count(self): self.create_dups(6) out = self.run_cmd(count=True, path=True) assert str(self.dup_item.filepath) in out assert out.endswith("5") beetbox-beets-00724b7/test/plugins/test_mpdstats.py0000664000175000017500000000466415253035401021775 0ustar pieterpieterfrom typing import Any, ClassVar from unittest.mock import ANY, Mock, call, patch from beets import util from beets.library import Item from beets.test.helper import PluginTestHelper from beetsplug.mpdstats import MPDStats, mpd_config class TestMPDStats(PluginTestHelper): plugin = "mpdstats" def test_update_rating(self): item = Item(title="title", path="", id=1) item.add(self.lib) log = Mock() mpdstats = MPDStats(self.lib, log) assert not mpdstats.update_rating(item, True) assert not mpdstats.update_rating(None, True) def test_get_item(self): item_path = util.normpath("/foo/bar.flac") item = Item(title="title", path=item_path, id=1) item.add(self.lib) log = Mock() mpdstats = MPDStats(self.lib, log) assert str(mpdstats.get_item(item_path)) == str(item) assert mpdstats.get_item("/some/non-existing/path") is None assert "item not found:" in log.info.call_args[0][0] STATUSES: ClassVar[list[dict[str, Any]]] = [ {"state": "pause"}, {"state": "play", "songid": 1, "time": "0:1"}, {"state": "stop"}, ] EVENTS = [["player"]] * (len(STATUSES) - 1) + [KeyboardInterrupt] item_path = util.normpath("/foo/bar.flac") songid = 1 @patch( "beetsplug.mpdstats.MPDClientWrapper", return_value=Mock( **{ "events.side_effect": EVENTS, "status.side_effect": STATUSES, "currentsong.return_value": (item_path, songid), } ), ) def test_run_mpdstats(self, mpd_mock): item = Item(title="title", path=self.item_path, id=1) item.add(self.lib) log = Mock() try: MPDStats(self.lib, log).run() except KeyboardInterrupt: pass log.info.assert_has_calls( [call("pause"), call("playing {}", ANY), call("stop")] ) @patch("beetsplug.mpdstats.MPDStats.run") def test_cli_options_override_config(self, run_mock): self.run_command( "mpdstats", "--host", "somehost", "--port", "5000", "--password", "secret", ) assert mpd_config["host"].as_str() == "somehost" assert mpd_config["port"].get(int) == 5000 assert mpd_config["password"].as_str() == "secret" run_mock.assert_called_once_with() beetbox-beets-00724b7/test/plugins/test_filefilter.py0000664000175000017500000000513315253035401022253 0ustar pieterpieter"""Tests for the `filefilter` plugin.""" from beets.test.helper import ImportHelper, PluginMixin class FileFilterPluginHelper(PluginMixin, ImportHelper): plugin = "filefilter" preload_plugin = False def setup_beets(self): super().setup_beets() self.prepare_tracks_for_import() def prepare_tracks_for_import(self): self.album_track, self.other_album_track, self.single_track = ( self.prepare_album_for_import(1, album_path=p)[0] for p in [ self.import_path / "album", self.import_path / "other_album", self.import_path, ] ) self.all_tracks = { self.album_track, self.other_album_track, self.single_track, } def _run(self, config, expected_album_count, expected_paths): with self.configure_plugin(config): self.importer.run() assert len(self.lib.albums()) == expected_album_count assert {i.filepath for i in self.lib.items()} == expected_paths class TestFileFilterPluginNonSingleton(FileFilterPluginHelper): def setup_beets(self): super().setup_beets() self.importer = self.setup_importer(autotag=False, copy=False) def test_import_default(self): """The default configuration should import everything.""" self._run({}, 3, self.all_tracks) def test_import_nothing(self): self._run({"path": "not_there"}, 0, set()) def test_global_config(self): self._run( {"path": ".*album.*"}, 2, {self.album_track, self.other_album_track} ) def test_album_config(self): self._run( {"album_path": ".*other_album.*"}, 1, {self.other_album_track} ) def test_singleton_config(self): """Check that singleton configuration is ignored for album import.""" self._run({"singleton_path": ".*other_album.*"}, 3, self.all_tracks) class TestFileFilterPluginSingleton(FileFilterPluginHelper): def setup_beets(self): super().setup_beets() self.importer = self.setup_singleton_importer(autotag=False, copy=False) def test_global_config(self): self._run( {"path": ".*album.*"}, 0, {self.album_track, self.other_album_track} ) def test_album_config(self): """Check that album configuration is ignored for singleton import.""" self._run({"album_path": ".*other_album.*"}, 0, self.all_tracks) def test_singleton_config(self): self._run( {"singleton_path": ".*other_album.*"}, 0, {self.other_album_track} ) beetbox-beets-00724b7/test/plugins/test_smartplaylist.py0000664000175000017500000003542715253035401023047 0ustar pieterpieter# TODO: Tests in this fire are very bad. Stop using Mocks in this module. from __future__ import annotations import os from typing import TYPE_CHECKING from unittest.mock import MagicMock, Mock, PropertyMock import pytest from beets import config from beets.dbcore.sort import FixedFieldSort, MultipleSort, NullSort from beets.library import Album, Item, parse_query_string from beets.test._common import item from beets.test.helper import BeetsTestCase, IOMixin, PathsMixin, PluginTestCase from beets.ui import UserError from beets.util import CHAR_REPLACE from beetsplug.smartplaylist import SmartPlaylistPlugin if TYPE_CHECKING: from pathlib import Path _p = pytest.param class PlaylistDirMixin(PathsMixin): @property def playlist_dir(self) -> Path: return self.temp_path / "playlists" class SmartPlaylistTest(PlaylistDirMixin, BeetsTestCase): def test_build_queries(self): spl = SmartPlaylistPlugin() assert spl._matched_playlists == set() assert spl._unmatched_playlists == set() config["smartplaylist"]["playlists"].set([]) spl.build_queries() assert spl._matched_playlists == set() assert spl._unmatched_playlists == set() config["smartplaylist"]["playlists"].set( [ {"name": "foo", "query": "FOO foo"}, {"name": "bar", "album_query": ["BAR bar1", "BAR bar2"]}, {"name": "baz", "query": "BAZ baz", "album_query": "BAZ baz"}, ] ) spl.build_queries() assert spl._matched_playlists == set() foo_foo = parse_query_string("FOO foo", Item) baz_baz = parse_query_string("BAZ baz", Item) baz_baz2 = parse_query_string("BAZ baz", Album) # Multiple queries are now stored as a tuple of (query, sort) tuples bar_queries = tuple( [ parse_query_string("BAR bar1", Album), parse_query_string("BAR bar2", Album), ] ) assert spl._unmatched_playlists == { ("foo", foo_foo, (None, None)), ("baz", baz_baz, baz_baz2), ("bar", (None, None), (bar_queries, None)), } def test_build_queries_with_sorts(self): spl = SmartPlaylistPlugin() config["smartplaylist"]["playlists"].set( [ {"name": "no_sort", "query": "foo"}, {"name": "one_sort", "query": "foo year+"}, {"name": "only_empty_sorts", "query": ["foo", "bar"]}, {"name": "one_non_empty_sort", "query": ["foo year+", "bar"]}, { "name": "multiple_sorts", "query": ["foo year+", "bar genres-"], }, { "name": "mixed", "query": ["foo year+", "bar", "baz genres+ id-"], }, ] ) spl.build_queries() # Multiple queries now return a tuple of (query, sort) tuples, not combined sorts = {} for name, (query_data, sort), _ in spl._unmatched_playlists: if isinstance(query_data, tuple): # Tuple of queries - each has its own sort sorts[name] = [s for _, s in query_data] else: sorts[name] = sort sort = FixedFieldSort # short cut since we're only dealing with this assert sorts["no_sort"] == NullSort() assert sorts["one_sort"] == sort("year") # Multiple queries store individual sorts in the tuple assert all(isinstance(x, NullSort) for x in sorts["only_empty_sorts"]) assert sorts["one_non_empty_sort"] == [sort("year"), NullSort()] assert sorts["multiple_sorts"] == [sort("year"), sort("genres", False)] assert sorts["mixed"] == [ sort("year"), NullSort(), MultipleSort([sort("genres"), sort("id", False)]), ] def test_matches(self): spl = SmartPlaylistPlugin() a = MagicMock(Album) i = MagicMock(Item) assert not spl.matches(i, None, None) assert not spl.matches(a, None, None) query = Mock() query.match.side_effect = {i: True}.__getitem__ assert spl.matches(i, query, None) assert not spl.matches(a, query, None) a_query = Mock() a_query.match.side_effect = {a: True}.__getitem__ assert not spl.matches(i, None, a_query) assert spl.matches(a, None, a_query) assert spl.matches(i, query, a_query) assert spl.matches(a, query, a_query) # Test with list of queries q1 = Mock() q1.match.return_value = False q2 = Mock() q2.match.side_effect = {i: True}.__getitem__ queries_list = [(q1, None), (q2, None)] assert spl.matches(i, queries_list, None) assert not spl.matches(a, queries_list, None) def test_db_changes(self): spl = SmartPlaylistPlugin() nones = None, None pl1 = "1", ("q1", None), nones pl2 = "2", ("q2", None), nones pl3 = "3", ("q3", None), nones spl._unmatched_playlists = {pl1, pl2, pl3} spl._matched_playlists = set() spl.matches = Mock(return_value=False) spl.db_change(None, "nothing") assert spl._unmatched_playlists == {pl1, pl2, pl3} assert spl._matched_playlists == set() spl.matches.side_effect = lambda _, q, __: q == "q3" spl.db_change(None, "matches 3") assert spl._unmatched_playlists == {pl1, pl2} assert spl._matched_playlists == {pl3} spl.matches.side_effect = lambda _, q, __: q == "q1" spl.db_change(None, "matches 3") assert spl._matched_playlists == {pl1, pl3} assert spl._unmatched_playlists == {pl2} def test_playlist_update(self): spl = SmartPlaylistPlugin() i = Mock(path=b"/tagada.mp3") i.evaluate_template.side_effect = lambda pl, **__: os.fsdecode( pl ).replace("$title", "ta:ga:da") lib = Mock() lib.replacements = CHAR_REPLACE lib.items.return_value = [i] lib.albums.return_value = [] q = Mock() a_q = Mock() pl = b"$title-my.m3u", (q, None), (a_q, None) spl._matched_playlists = {pl} config["smartplaylist"]["relative_to"] = False config["smartplaylist"]["playlist_dir"] = str(self.playlist_dir) spl.update_playlists(lib) lib.items.assert_called_once_with(q, None) lib.albums.assert_called_once_with(a_q, None) m3u_filepath = self.playlist_dir / "ta_ga_da-my_playlist_.m3u" assert m3u_filepath.exists() content = m3u_filepath.read_bytes() assert content == b"/tagada.mp3\n" def test_playlist_update_output_extm3u(self): spl = SmartPlaylistPlugin() i = MagicMock() type(i).artist = PropertyMock(return_value="fake artist") type(i).title = PropertyMock(return_value="fake title") type(i).length = PropertyMock(return_value=300.123) type(i).path = PropertyMock(return_value=b"/tagada.mp3") i.evaluate_template.side_effect = lambda pl, **__: os.fsdecode( pl ).replace("$title", "ta:ga:da") lib = Mock() lib.replacements = CHAR_REPLACE lib.items.return_value = [i] lib.albums.return_value = [] q = Mock() a_q = Mock() pl = b"$title-my.m3u", (q, None), (a_q, None) spl._matched_playlists = {pl} config["smartplaylist"]["output"] = "extm3u" config["smartplaylist"]["prefix"] = "http://beets:8337/files" config["smartplaylist"]["relative_to"] = False config["smartplaylist"]["playlist_dir"] = str(self.playlist_dir) spl.update_playlists(lib) lib.items.assert_called_once_with(q, None) lib.albums.assert_called_once_with(a_q, None) m3u_filepath = self.playlist_dir / "ta_ga_da-my_playlist_.m3u" assert m3u_filepath.exists() content = m3u_filepath.read_bytes() assert content == ( b"#EXTM3U\n" b"#EXTINF:300,fake artist - fake title\n" b"http://beets:8337/files/tagada.mp3\n" ) def test_playlist_update_output_extm3u_fields(self): spl = SmartPlaylistPlugin() i = MagicMock() type(i).artist = PropertyMock(return_value="Fake Artist") type(i).title = PropertyMock(return_value="fake Title") type(i).length = PropertyMock(return_value=300.123) type(i).path = PropertyMock(return_value=b"/tagada.mp3") a = {"id": 456, "genres": ["Rock", "Pop"]} i.__getitem__.side_effect = a.__getitem__ i.evaluate_template.side_effect = lambda pl, **__: os.fsdecode( pl ).replace("$title", "ta:ga:da") lib = Mock() lib.replacements = CHAR_REPLACE lib.items.return_value = [i] lib.albums.return_value = [] q = Mock() a_q = Mock() pl = b"$title-my.m3u", (q, None), (a_q, None) spl._matched_playlists = {pl} config["smartplaylist"]["output"] = "extm3u" config["smartplaylist"]["relative_to"] = False config["smartplaylist"]["playlist_dir"] = str(self.playlist_dir) config["smartplaylist"]["fields"] = ["id", "genres"] spl.update_playlists(lib) lib.items.assert_called_once_with(q, None) lib.albums.assert_called_once_with(a_q, None) m3u_filepath = self.playlist_dir / "ta_ga_da-my_playlist_.m3u" assert m3u_filepath.exists() content = m3u_filepath.read_bytes() assert content == ( b"#EXTM3U\n" b'#EXTINF:300 id="456" genres="Rock%3B%20Pop",Fake Artist - fake Title\n' b"/tagada.mp3\n" ) def test_get_playlist_items(self): """Test get playlist items. - Items preserve their order in the playlist - There are no duplicates when items match multiple queries """ self.add_item(path=b"/item1.mp3", id=1) self.add_item(path=b"/item2.mp3", id=2) self.add_item(path=b"/item3.mp3", id=3) queries_and_sorts = (("path::item id-", None), ("path::item3", None)) actual_items = SmartPlaylistPlugin.get_playlist_items( self.lib, (queries_and_sorts, None), (None, None) ) assert [i.id for i in actual_items] == [3, 2, 1] class TestGetItemURI: @pytest.fixture def plugin(self, config, plugin_config): plugin_config = {"prefix": "http://beets:8337/files", **plugin_config} config["smartplaylist"].set(plugin_config) return SmartPlaylistPlugin() @pytest.fixture(autouse=True) def _setup(self, monkeypatch): monkeypatch.setattr(Item, "destination", lambda _: b"/tagada.mp3") @pytest.fixture def item(self): return item( id=3, artist="fake artist", title="fake title", length=300.123, path=b"/imported/path/with/dont/move/tagada.mp3", ) @pytest.mark.parametrize( "plugin_config, expected_uri", [ _p( {}, b"http://beets:8337/files/imported/path/with/dont/move/tagada.mp3", id="path by default", ), _p( {"dest_regen": True}, b"http://beets:8337/files/tagada.mp3", id="dest_regen uses item destination", ), _p( { "uri_format": "http://beets:8337/item/$id/file", "dest_regen": True, }, b"http://beets:8337/item/3/file", id="uri_format takes precedence", ), ], ) def test_get_item_uri(self, plugin, item, expected_uri): assert plugin.get_item_uri(item) == expected_uri class SmartPlaylistCLITest(PlaylistDirMixin, IOMixin, PluginTestCase): plugin = "smartplaylist" def setUp(self): super().setUp() self.item = self.add_item() config["smartplaylist"]["playlists"].set( [ {"name": "my_playlist.m3u", "query": self.item.title}, {"name": "all.m3u", "query": ""}, ] ) config["smartplaylist"]["playlist_dir"] = str(self.playlist_dir) def test_splupdate(self): with pytest.raises(UserError): self.run_with_output("splupdate", "tagada") self.run_with_output("splupdate", "my_playlist") m3u_path = self.playlist_dir / "my_playlist.m3u" assert m3u_path.exists() assert m3u_path.read_bytes() == self.item.path + b"\n" m3u_path.unlink() self.run_with_output("splupdate", "my_playlist.m3u") assert m3u_path.read_bytes() == self.item.path + b"\n" m3u_path.unlink() self.run_with_output("splupdate") for name in ("my_playlist.m3u", "all.m3u"): assert ( self.playlist_dir / name ).read_bytes() == self.item.path + b"\n" def test_splupdate_unknown_playlist_error_is_sorted_and_quoted(self): config["smartplaylist"]["playlists"].set( [ {"name": "z last.m3u", "query": self.item.title}, {"name": "rock'n roll.m3u", "query": self.item.title}, {"name": "a one.m3u", "query": self.item.title}, ] ) with pytest.raises(UserError) as exc_info: self.run_with_output("splupdate", "tagada") assert str(exc_info.value) == ( "No playlist matching any of " "'a one.m3u' 'rock'\"'\"'n roll.m3u' 'z last.m3u' found" ) def test_splupdate_log_output(self): with self.assertLogs("beets.smartplaylist", level="INFO") as logs: self.run_with_output("splupdate", "my_playlist") output = "\n".join(logs.output) assert "Updating 1 smart playlists..." in output assert "Creating playlist my_playlist.m3u: 1 tracks." in output assert "1 playlists updated" in output def test_splupdate_verbose_log_output(self): with self.assertLogs("beets.smartplaylist", level="DEBUG") as logs: self.run_with_output("splupdate", "my_playlist") output = "\n".join(logs.output) assert "Updating 1 smart playlists..." in output assert "Creating playlist my_playlist.m3u: 1 tracks." in output assert "the ärtist - " in output assert "1 playlists updated" in output def test_splupdate_pretend_log_output(self): with self.assertLogs("beets.smartplaylist", level="INFO") as logs: self.run_with_output("splupdate", "--pretend", "my_playlist") output = "\n".join(logs.output) assert "Updating 1 smart playlists..." in output assert "Creating playlist my_playlist.m3u: 1 tracks." in output assert "1 playlists would be updated" in output beetbox-beets-00724b7/test/test_plugins.py0000664000175000017500000004304015253035401020125 0ustar pieterpieterimport importlib import itertools import logging import pkgutil import sys from typing import ClassVar from unittest.mock import ANY, Mock, patch import pytest from mediafile import MediaFile from beets import config, plugins, ui from beets.dbcore import types from beets.importer import Action, SingletonImportTask from beets.library import Item from beets.test.helper import ( RUNNING_IN_CI, AutotagStub, ImportHelper, IOMixin, PluginMixin, PluginTestHelper, TerminalImportMixin, ) from beets.util import PromptChoice, displayable_path class TestPluginRegistration(IOMixin, PluginTestHelper): class RatingPlugin(plugins.BeetsPlugin): item_types: ClassVar[dict[str, types.Type]] = { "rating": types.Float(), "multi_value": types.MULTI_VALUE_DSV, } def __init__(self): super().__init__() self.register_listener("write", self.on_write) @staticmethod def on_write(item=None, path=None, tags=None): if tags["artist"] == "XXX": tags["artist"] = "YYY" @pytest.fixture(autouse=True) def _setup(self): self.register_plugin(self.RatingPlugin) def test_field_type_registered(self): assert isinstance(Item._types.get("rating"), types.Float) def test_duplicate_type(self): class DuplicateTypePlugin(plugins.BeetsPlugin): item_types: ClassVar[dict[str, types.Type]] = { "rating": types.INTEGER } self.register_plugin(DuplicateTypePlugin) with pytest.raises( plugins.PluginConflictError, match="already been defined" ): Item._types def test_listener_registered(self): self.RatingPlugin() item = self.add_item_fixture(artist="XXX") item.write() assert MediaFile(item.filepath).artist == "YYY" def test_multi_value_flex_field_type(self): item = Item(path="apath", artist="aaa") item.multi_value = ["one", "two", "three"] item.add(self.lib) out = self.run_with_output("ls", "-f", "$multi_value") assert out == "one; two; three\n" class PluginImportHelper(PluginMixin, ImportHelper): def setup_beets(self): super().setup_beets() self.prepare_album_for_import(2) class TestEvents(PluginImportHelper): def test_import_task_created(self, caplog): self.importer = self.setup_importer(pretend=True) with caplog.at_level("DEBUG"): self.importer.run() # Exactly one event should have been imported (for the album). # Sentinels do not get emitted. assert caplog.text.count("Sending event: import_task_created") == 1 logs = [ msg for msg in caplog.messages if not msg.startswith("Sending event:") ] assert logs == [ f"Album: {self.import_path / 'album'}", f" {displayable_path(self.import_media[0].path)}", f" {displayable_path(self.import_media[1].path)}", ] def test_import_task_created_with_plugin(self, caplog): class ToSingletonPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener( "import_task_created", self.import_task_created_event ) def import_task_created_event(self, session, task): return [ SingletonImportTask(task.toppath, i) for i in task.items ] to_singleton_plugin = ToSingletonPlugin self.register_plugin(to_singleton_plugin) self.importer = self.setup_importer(pretend=True) with caplog.at_level("DEBUG"): self.importer.run() # Exactly one event should have been imported (for the album). # Sentinels do not get emitted. assert caplog.text.count("Sending event: import_task_created") == 1 logs = [ msg for msg in caplog.messages if not msg.startswith("Sending event:") ] assert logs == [ f"Singleton: {displayable_path(self.import_media[0].path)}", f"Singleton: {displayable_path(self.import_media[1].path)}", ] class TestListeners(PluginTestHelper): def test_register(self): class DummyPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener("cli_exit", self.dummy) self.register_listener("cli_exit", self.dummy) def dummy(self): pass d = DummyPlugin() assert DummyPlugin._raw_listeners["cli_exit"] == [d.dummy] d2 = DummyPlugin() assert DummyPlugin._raw_listeners["cli_exit"] == [d.dummy, d2.dummy] d.register_listener("cli_exit", d2.dummy) assert DummyPlugin._raw_listeners["cli_exit"] == [d.dummy, d2.dummy] def test_events_called(self): class DummyPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.foo = Mock(__name__="foo") self.register_listener("event_foo", self.foo) self.bar = Mock(__name__="bar") self.register_listener("event_bar", self.bar) d = DummyPlugin() plugins.send("event") d.foo.assert_has_calls([]) d.bar.assert_has_calls([]) plugins.send("event_foo", var="tagada") d.foo.assert_called_once_with(var="tagada") d.bar.assert_has_calls([]) def test_listener_params(self): class DummyPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() for i in itertools.count(1): try: meth = getattr(self, f"dummy{i}") except AttributeError: break self.register_listener(f"event{i}", meth) def dummy1(self, foo): assert foo == 5 def dummy2(self, foo=None): assert foo == 5 def dummy3(self): # argument cut off pass def dummy4(self, bar=None): # argument cut off pass def dummy5(self, bar): assert not True # more complex examples def dummy6(self, foo, bar=None): assert foo == 5 assert bar is None def dummy7(self, foo, **kwargs): assert foo == 5 assert kwargs == {} def dummy8(self, foo, bar, **kwargs): assert not True def dummy9(self, **kwargs): assert kwargs == {"foo": 5} DummyPlugin() plugins.send("event1", foo=5) plugins.send("event2", foo=5) plugins.send("event3", foo=5) plugins.send("event4", foo=5) with pytest.raises(TypeError): plugins.send("event5", foo=5) plugins.send("event6", foo=5) plugins.send("event7", foo=5) with pytest.raises(TypeError): plugins.send("event8", foo=5) plugins.send("event9", foo=5) class TestPromptChoices(TerminalImportMixin, PluginImportHelper): @pytest.fixture(autouse=True) def setup_prompt_choice(self, io): self.setup_importer() self.matcher = AutotagStub(AutotagStub.IDENT).install() # keep track of ui.input_option() calls self.input_options_patcher = patch( "beets.ui.input_options", side_effect=ui.input_options ) self.mock_input_options = self.input_options_patcher.start() yield self.input_options_patcher.stop() self.matcher.restore() def test_plugin_choices_in_ui_input_options_album(self): """Test the presence of plugin choices on the prompt (album).""" class DummyPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener( "before_choose_candidate", self.return_choices ) def return_choices(self, session, task): return [ PromptChoice("f", "Foo", None), PromptChoice("z", "baZ", None), ] self.register_plugin(DummyPlugin) # Default options + extra choices by the plugin ('Foo', 'Bar') opts = ( "Apply", "More candidates", "Skip", "Use as-is", "as Tracks", "Group albums", "Rescan directory", "Enter search", "enter Id", "aBort", "Foo", "baZ", ) self.importer.add_choice(Action.SKIP) self.importer.run() self.mock_input_options.assert_called_once_with( opts, default="a", require=ANY ) def test_plugin_choices_in_ui_input_options_singleton(self): """Test the presence of plugin choices on the prompt (singleton).""" class DummyPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener( "before_choose_candidate", self.return_choices ) def return_choices(self, session, task): return [ PromptChoice("f", "Foo", None), PromptChoice("r", "baR", None), ] self.register_plugin(DummyPlugin) # Default options + extra choices by the plugin ('Foo', 'Bar') opts = ( "Apply", "More candidates", "Skip", "Use as-is", "Enter search", "enter Id", "aBort", "Foo", "baR", ) config["import"]["singletons"] = True self.importer.add_choice(Action.SKIP) self.importer.run() self.mock_input_options.assert_called_with( opts, default="a", require=ANY ) def test_choices_conflicts(self): """Test the short letter conflict solving.""" class DummyPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener( "before_choose_candidate", self.return_choices ) def return_choices(self, session, task): return [ PromptChoice("a", "A foo", None), # dupe PromptChoice("z", "baZ", None), # ok PromptChoice("z", "Zupe", None), # dupe PromptChoice("z", "Zoo", None), ] # dupe self.register_plugin(DummyPlugin) # Default options + not dupe extra choices by the plugin ('baZ') opts = ( "Apply", "More candidates", "Skip", "Use as-is", "as Tracks", "Group albums", "Rescan directory", "Enter search", "enter Id", "aBort", "baZ", ) self.importer.add_choice(Action.SKIP) self.importer.run() self.mock_input_options.assert_called_once_with( opts, default="a", require=ANY ) def test_plugin_callback(self): """Test that plugin callbacks are being called upon user choice.""" class DummyPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener( "before_choose_candidate", self.return_choices ) def return_choices(self, session, task): return [PromptChoice("f", "Foo", self.foo)] def foo(self, session, task): pass self.register_plugin(DummyPlugin) # Default options + extra choices by the plugin ('Foo', 'Bar') opts = ( "Apply", "More candidates", "Skip", "Use as-is", "as Tracks", "Group albums", "Rescan directory", "Enter search", "enter Id", "aBort", "Foo", ) # DummyPlugin.foo() should be called once with patch.object(DummyPlugin, "foo", autospec=True) as mock_foo: self.io.addinput("f") self.io.addinput("n") self.importer.run() assert mock_foo.call_count == 1 # input_options should be called twice, as foo() returns None assert self.mock_input_options.call_count == 2 self.mock_input_options.assert_called_with( opts, default="a", require=ANY ) def test_plugin_callback_return(self): """Test that plugin callbacks that return a value exit the loop.""" class DummyPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener( "before_choose_candidate", self.return_choices ) def return_choices(self, session, task): return [PromptChoice("f", "Foo", self.foo)] def foo(self, session, task): return Action.SKIP self.register_plugin(DummyPlugin) # Default options + extra choices by the plugin ('Foo', 'Bar') opts = ( "Apply", "More candidates", "Skip", "Use as-is", "as Tracks", "Group albums", "Rescan directory", "Enter search", "enter Id", "aBort", "Foo", ) # DummyPlugin.foo() should be called once self.io.addinput("f") self.importer.run() # input_options should be called once, as foo() returns SKIP self.mock_input_options.assert_called_once_with( opts, default="a", require=ANY ) def get_available_plugins(): """Get all available plugins in the beetsplug namespace.""" namespace_pkg = importlib.import_module("beetsplug") return [ m.name for m in pkgutil.iter_modules(namespace_pkg.__path__) if not m.name.startswith("_") ] class TestImportPlugin(PluginMixin): @pytest.fixture(params=get_available_plugins()) def plugin_name(self, request): """Fixture to provide the name of each available plugin.""" name = request.param # skip gstreamer plugins on windows gstreamer_plugins = {"bpd", "replaygain"} if sys.platform == "win32" and name in gstreamer_plugins: pytest.skip(f"GStreamer is not available on Windows: {name}") return name def unload_plugins(self): """Unimport plugins before each test to avoid conflicts.""" super().unload_plugins() for mod in list(sys.modules): if mod.startswith("beetsplug."): del sys.modules[mod] @pytest.fixture(autouse=True) def cleanup(self): """Ensure plugins are unimported before and after each test.""" self.unload_plugins() yield self.unload_plugins() @pytest.mark.skipif( not RUNNING_IN_CI, reason=( "Requires all dependencies to be installed, which we can't" " guarantee in the local environment." ), ) def test_import_plugin(self, caplog, plugin_name): """Test that a plugin is importable without an error.""" caplog.set_level(logging.WARNING) self.load_plugins(plugin_name) assert "PluginImportError" not in caplog.text, ( f"Plugin '{plugin_name}' has issues during import." ) class TestDeprecationCopy: # TODO: remove this test in Beets 3.0.0 def test_legacy_metadata_plugin_deprecation(self): """Test that a MetadataSourcePlugin with 'legacy' data_source raises a deprecation warning and all function and properties are copied from the base class. """ with pytest.warns(DeprecationWarning, match="LegacyMetadataPlugin"): class LegacyMetadataPlugin(plugins.BeetsPlugin): data_source = "legacy" # Assert all methods are present assert hasattr(LegacyMetadataPlugin, "albums_for_ids") assert hasattr(LegacyMetadataPlugin, "tracks_for_ids") assert hasattr(LegacyMetadataPlugin, "data_source_mismatch_penalty") assert hasattr(LegacyMetadataPlugin, "_extract_id") assert hasattr(LegacyMetadataPlugin, "get_artist") class TestMusicBrainzPluginLoading: @pytest.fixture(autouse=True) def config(self): _config = config _config.sources = [] _config.read(user=False, defaults=True) return _config def test_default(self): assert "musicbrainz" in plugins.get_plugin_names() def test_other_plugin_enabled(self, config): config["plugins"] = ["anything"] assert "musicbrainz" not in plugins.get_plugin_names() def test_deprecated_enabled(self, config, caplog): config["plugins"] = ["anything"] config["musicbrainz"]["enabled"] = True assert "musicbrainz" in plugins.get_plugin_names() assert ( "musicbrainz.enabled' configuration option is deprecated" in caplog.text ) def test_deprecated_disabled(self, config, caplog): config["musicbrainz"]["enabled"] = False assert "musicbrainz" not in plugins.get_plugin_names() assert ( "musicbrainz.enabled' configuration option is deprecated" in caplog.text ) beetbox-beets-00724b7/test/__init__.py0000664000175000017500000000004215253035401017137 0ustar pieterpieter# Make python -m testall.py work. beetbox-beets-00724b7/test/test_logging.py0000664000175000017500000003036015253035401020073 0ustar pieterpieter"""Stupid tests that ensure logging works as expected""" import logging as log import sys import threading from types import ModuleType import pytest import beets.logging as blog from beets import plugins, ui from beets.test.helper import AsIsImporterMixin, ImportHelper, PluginMixin class TestStrFormatLogger: """Tests for the custom str-formatting logger.""" def test_logger_creation(self): l1 = log.getLogger("foo123") l2 = blog.getLogger("foo123") assert l1 == l2 assert l1.__class__ == log.Logger l3 = blog.getLogger("bar123") l4 = log.getLogger("bar123") assert l3 == l4 assert l3.__class__ == blog.BeetsLogger assert isinstance( l3, (blog.StrFormatLogger, blog.ThreadLocalLevelLogger) ) l5 = l3.getChild("shalala") assert l5.__class__ == blog.BeetsLogger l6 = blog.getLogger() assert l1 != l6 @pytest.mark.parametrize( "level", [log.DEBUG, log.INFO, log.WARNING, log.ERROR] ) @pytest.mark.parametrize( "msg, args, kwargs, expected", [ ("foo {} bar {}", ("oof", "baz"), {}, "foo oof bar baz"), ( "foo {bar} baz {foo}", (), {"foo": "oof", "bar": "baz"}, "foo baz baz oof", ), ("no args", (), {}, "no args"), ("foo {} bar {baz}", ("oof",), {"baz": "baz"}, "foo oof bar baz"), ], ) def test_str_format_logging( self, level, msg, args, kwargs, expected, caplog ): logger = blog.getLogger("test_logger") logger.setLevel(level) with caplog.at_level(level, logger="test_logger"): logger.log(level, msg, *args, **kwargs) assert caplog.records, "No log records were captured" assert str(caplog.records[0].msg) == expected class TestLogSanitization: """Log messages should have control characters removed from: - String arguments - Keyword argument values - Bytes arguments (which get decoded first) """ @pytest.mark.parametrize( "msg, args, kwargs, expected", [ # Valid UTF-8 bytes are decoded and preserved ( "foo {} bar {bar}", (b"oof \xc3\xa9",), {"bar": b"baz \xc3\xa9"}, "foo oof é bar baz é", ), # Invalid UTF-8 bytes are decoded with replacement characters ( "foo {} bar {bar}", (b"oof \xff",), {"bar": b"baz \xff"}, "foo oof � bar baz �", ), # Control characters should be removed ( "foo {} bar {bar}", ("oof \x9e",), {"bar": "baz \x9e"}, "foo oof � bar baz �", ), # Whitespace control characters should be preserved ( "foo {} bar {bar}", ("foo\t\n",), {"bar": "bar\r"}, "foo foo\t\n bar bar\r", ), ], ) def test_sanitization(self, msg, args, kwargs, expected, caplog): level = log.INFO logger = blog.getLogger("test_logger") logger.setLevel(level) with caplog.at_level(level, logger="test_logger"): logger.log(level, msg, *args, **kwargs) assert caplog.records, "No log records were captured" assert str(caplog.records[0].msg) == expected class DummyModule(ModuleType): class DummyPlugin(plugins.BeetsPlugin): def __init__(self): plugins.BeetsPlugin.__init__(self, "dummy") self.import_stages = [self.import_stage] self.register_listener("dummy_event", self.listener) def log_all(self, name): self._log.debug("debug {}", name) self._log.info("info {}", name) self._log.warning("warning {}", name) def commands(self): cmd = ui.Subcommand("dummy") cmd.func = lambda _, __, ___: self.log_all("cmd") return (cmd,) def import_stage(self, session, task): self.log_all("import_stage") def listener(self): self.log_all("listener") def __init__(self, *_, **__): module_name = "beetsplug.dummy" super().__init__(module_name) self.DummyPlugin.__module__ = module_name self.DummyPlugin = self.DummyPlugin class TestLoggingLevel(AsIsImporterMixin, PluginMixin, ImportHelper): plugin = "dummy" @pytest.fixture(autouse=True) def _patch_dummy_module(self, monkeypatch): monkeypatch.setitem(sys.modules, "beetsplug.dummy", DummyModule()) def test_command_level0(self, caplog): self.config["verbose"] = 0 with caplog.at_level("DEBUG"): self.run_command("dummy") assert "warning cmd" in caplog.messages assert "info cmd" in caplog.messages assert "debug cmd" not in caplog.messages def test_command_level1(self, caplog): self.config["verbose"] = 1 with caplog.at_level("DEBUG"): self.run_command("dummy") assert "warning cmd" in caplog.messages assert "info cmd" in caplog.messages assert "debug cmd" in caplog.messages def test_command_level2(self, caplog): self.config["verbose"] = 2 with caplog.at_level("DEBUG"): self.run_command("dummy") assert "warning cmd" in caplog.messages assert "info cmd" in caplog.messages assert "debug cmd" in caplog.messages def test_listener_level0(self, caplog): self.config["verbose"] = 0 with caplog.at_level("DEBUG"): plugins.send("dummy_event") assert "warning listener" in caplog.messages assert "info listener" not in caplog.messages assert "debug listener" not in caplog.messages def test_listener_level1(self, caplog): self.config["verbose"] = 1 with caplog.at_level("DEBUG"): plugins.send("dummy_event") assert "warning listener" in caplog.messages assert "info listener" in caplog.messages assert "debug listener" not in caplog.messages def test_listener_level2(self, caplog): self.config["verbose"] = 2 with caplog.at_level("DEBUG"): plugins.send("dummy_event") assert "warning listener" in caplog.messages assert "info listener" in caplog.messages assert "debug listener" in caplog.messages def test_import_stage_level0(self, caplog): self.config["verbose"] = 0 with caplog.at_level("DEBUG"): self.run_asis_importer() assert "warning import_stage" in caplog.messages assert "info import_stage" not in caplog.messages assert "debug import_stage" not in caplog.messages def test_import_stage_level1(self, caplog): self.config["verbose"] = 1 with caplog.at_level("DEBUG"): self.run_asis_importer() assert "warning import_stage" in caplog.messages assert "info import_stage" in caplog.messages assert "debug import_stage" not in caplog.messages def test_import_stage_level2(self, caplog): self.config["verbose"] = 2 with caplog.at_level("DEBUG"): self.run_asis_importer() assert "warning import_stage" in caplog.messages assert "info import_stage" in caplog.messages assert "debug import_stage" in caplog.messages class TestConcurrentEvents(AsIsImporterMixin, ImportHelper): """Similar to LoggingLevelTest but lower-level and focused on multiple events interaction. Since this is a bit heavy we don't do it in LoggingLevelTest. """ db_on_disk = True class DummyPlugin(plugins.BeetsPlugin): def __init__(self, test_case): plugins.BeetsPlugin.__init__(self, "dummy") self.register_listener("dummy_event1", self.listener1) self.register_listener("dummy_event2", self.listener2) self.lock1 = threading.Lock() self.lock2 = threading.Lock() self.test_case = test_case self.exc = None self.t1_step = self.t2_step = 0 def listener1(self): try: assert self._log.level == log.INFO self.t1_step = 1 self.lock1.acquire() assert self._log.level == log.INFO self.t1_step = 2 except Exception as e: self.exc = e def listener2(self): try: assert self._log.level == log.DEBUG self.t2_step = 1 self.lock2.acquire() assert self._log.level == log.DEBUG self.t2_step = 2 except Exception as e: self.exc = e def test_concurrent_events(self): dp = self.DummyPlugin(self) def check_dp_exc(): if dp.exc: raise dp.exc try: dp.lock1.acquire() dp.lock2.acquire() assert dp._log.level == log.NOTSET self.config["verbose"] = 1 t1 = threading.Thread(target=dp.listeners["dummy_event1"][0]) t1.start() # blocked. t1 tested its log level while dp.t1_step != 1: check_dp_exc() assert t1.is_alive() assert dp._log.level == log.NOTSET self.config["verbose"] = 2 t2 = threading.Thread(target=dp.listeners["dummy_event2"][0]) t2.start() # blocked. t2 tested its log level while dp.t2_step != 1: check_dp_exc() assert t2.is_alive() assert dp._log.level == log.NOTSET dp.lock1.release() # dummy_event1 tests its log level + finishes while dp.t1_step != 2: check_dp_exc() t1.join(0.1) assert not t1.is_alive() assert t2.is_alive() assert dp._log.level == log.NOTSET dp.lock2.release() # dummy_event2 tests its log level + finishes while dp.t2_step != 2: check_dp_exc() t2.join(0.1) assert not t2.is_alive() except Exception: print("Alive threads:", threading.enumerate()) if dp.lock1.locked(): print("Releasing lock1 after exception in test") dp.lock1.release() if dp.lock2.locked(): print("Releasing lock2 after exception in test") dp.lock2.release() print("Alive threads:", threading.enumerate()) raise def test_root_logger_levels(self, caplog): """Root logger level should be shared between threads.""" self.config["threaded"] = True blog.getLogger("beets").set_global_level(blog.WARNING) with caplog.at_level("DEBUG"): self.run_asis_importer() assert caplog.messages == [] blog.getLogger("beets").set_global_level(blog.INFO) with caplog.at_level("DEBUG"): self.run_asis_importer() for line in caplog.messages: assert "import" in line assert "album" in line blog.getLogger("beets").set_global_level(blog.DEBUG) with caplog.at_level("DEBUG"): self.run_asis_importer() assert "Sending event: database_change" in caplog.messages class TestLegacyFormatter: """Tests for ``LegacyFormatter``, which strips the ``beets.`` prefix from logger names and prepends the remainder to the message. """ @pytest.mark.parametrize( "logger_name, expected", [ ("beets", "hello world"), ("beets.musicbrainz", "musicbrainz: hello world"), ("beets.musicbrainz.sub", "musicbrainz.sub: hello world"), ("root.foobar", "foobar: hello world"), ], ) def test_format(self, logger_name, expected): """Root logger passes message unchanged; child loggers get ``prefix: msg`` format after the ``beets.`` prefix is stripped. """ formatter = blog.LegacyFormatter("%(legacy_prefix)s%(message)s") record = log.LogRecord( logger_name, log.INFO, __file__, 0, "hello world", (), None ) assert formatter.format(record) == expected beetbox-beets-00724b7/test/test_metadata_plugins.py0000664000175000017500000001317415253035401021772 0ustar pieterpieterfrom collections.abc import Iterable from concurrent.futures import ThreadPoolExecutor as BaseThreadPoolExecutor from threading import Event import pytest from beets import metadata_plugins from beets.test.helper import PluginMixin class ErrorMetadataMockPlugin(metadata_plugins.MetadataSourcePlugin): """A metadata source plugin that raises errors in all its methods.""" def candidates(self, *args, **kwargs): raise ValueError("Mocked error") def item_candidates(self, *args, **kwargs): for i in range(3): raise ValueError("Mocked error") yield # This is just to make this a generator def album_for_id(self, *args, **kwargs): raise ValueError("Mocked error") def track_for_id(self, *args, **kwargs): raise ValueError("Mocked error") class TestMetadataPluginsException(PluginMixin): """Check that errors during the metadata plugins do not crash beets. They should be logged as errors instead. """ @pytest.fixture(autouse=True) def setup(self): metadata_plugins.find_metadata_source_plugins.cache_clear() metadata_plugins.get_metadata_source.cache_clear() self.register_plugin(ErrorMetadataMockPlugin) yield self.unload_plugins() @pytest.fixture def call_method(self, method_name, args): def _call(): result = getattr(metadata_plugins, method_name)(*args) return list(result) if isinstance(result, Iterable) else result return _call @pytest.mark.parametrize( "method_name,args", [ ("candidates", ()), ("item_candidates", ()), ("albums_for_ids", (["some_id"],)), ("tracks_for_ids", (["some_id"],)), ("album_for_id", ("some_id", "ErrorMetadataMock")), ("track_for_id", ("some_id", "ErrorMetadataMock")), ], ) def test_logging(self, caplog, call_method, method_name): self.config["raise_on_error"] = False call_method() assert ( f"Error in 'ErrorMetadataMock.{method_name}': Mocked error" in caplog.text ) @pytest.mark.parametrize( "method_name,args", [ ("candidates", ()), ("item_candidates", ()), ("albums_for_ids", (["some_id"],)), ("tracks_for_ids", (["some_id"],)), ("album_for_id", ("some_id", "ErrorMetadataMock")), ("track_for_id", ("some_id", "ErrorMetadataMock")), ], ) def test_raising(self, call_method): self.config["raise_on_error"] = True with pytest.raises(ValueError, match="Mocked error"): call_method() class TestSearchApiMetadataSourcePlugin(PluginMixin): plugin = "none" preload_plugin = False class RaisingSearchApiMetadataMockPlugin( metadata_plugins.SearchApiMetadataSourcePlugin[ metadata_plugins.IDResponse ] ): def get_search_query_with_filters(self, _): return "", {} def get_search_response(self, _): raise ValueError("Search failure") def album_for_id(self, _): return None def track_for_id(self, _): return None @pytest.fixture def search_plugin(self): return self.RaisingSearchApiMetadataMockPlugin() def test_search_api_returns_empty_when_raise_on_error_disabled( self, config, search_plugin, caplog ): config["raise_on_error"] = False assert search_plugin._search_api("track", "query", {}) == () assert "Search failure" in caplog.text def test_search_api_raises_when_raise_on_error_enabled( self, config, search_plugin ): config["raise_on_error"] = True with pytest.raises(ValueError, match="Search failure"): search_plugin._search_api("track", "query", {}) def test_search_api_skips_request_without_query_and_filters( self, config, search_plugin ): """Empty searches are rejected by APIs, so do not send them.""" config["raise_on_error"] = True assert search_plugin._search_api("track", "", {}) == () def test_albums_for_ids_calls_each_plugin_once(monkeypatch): start_workers = Event() class Plugin: def __init__(self, name): self.data_source = name self.calls: list[list[str]] = [] def albums_for_ids(self, ids): self.calls.append(list(ids)) return [self.data_source] plugins = [Plugin("discogs"), Plugin("musicbrainz"), Plugin("tidal")] class PluginSequence: def __iter__(self): yield from plugins start_workers.set() class DelayedStartExecutor: def __init__(self): self._executor = BaseThreadPoolExecutor(max_workers=1) def submit(self, fn, *args, **kwargs): return self._executor.submit(self._run, fn, args, kwargs) def _run(self, fn, args, kwargs): start_workers.wait() return fn(*args, **kwargs) def __enter__(self): return self def __exit__(self, exc_type, exc, tb): self._executor.shutdown(wait=True) return False monkeypatch.setattr( metadata_plugins, "find_metadata_source_plugins", lambda: PluginSequence(), ) monkeypatch.setattr( metadata_plugins, "ThreadPoolExecutor", DelayedStartExecutor ) assert set(metadata_plugins.albums_for_ids(["42"])) == { "discogs", "musicbrainz", "tidal", } assert [plugin.calls for plugin in plugins] == [ [["42"]], [["42"]], [["42"]], ] beetbox-beets-00724b7/test/util/0000775000175000017500000000000015253035401016007 5ustar pieterpieterbeetbox-beets-00724b7/test/util/test_config.py0000664000175000017500000000233215253035401020665 0ustar pieterpieterimport pytest from beets.util.config import UnknownPairError, sanitize_choices, sanitize_pairs @pytest.mark.parametrize( "input_choices, valid_choices, expected", [ (["A", "Z"], ("A", "B"), ["A"]), (["A", "A"], ("A"), ["A"]), (["D", "*", "A"], ("A", "B", "C", "D"), ["D", "B", "C", "A"]), ], ) def test_sanitize_choices(input_choices, valid_choices, expected): assert sanitize_choices(input_choices, valid_choices) == expected def test_sanitize_pairs(): assert sanitize_pairs( [ ("foo", "baz bar"), ("foo", "baz bar"), ("key", "*"), ("*", "*"), ("discard", "bye"), ], [("foo", "bar"), ("foo", "baz"), ("foo", "foobar"), ("key", "value")], ) == [("foo", "baz"), ("foo", "bar"), ("key", "value"), ("foo", "foobar")] def test_sanitize_pairs_unknown_key(): with pytest.raises(UnknownPairError): sanitize_pairs( [("bar", "foo")], [("key", "value")], raise_on_unknown=True ) def test_sanitize_pairs_unknown_key_wildcard_value(): with pytest.raises(UnknownPairError): sanitize_pairs( [("foo", "*")], [("key", "value")], raise_on_unknown=True ) beetbox-beets-00724b7/test/util/test_pipeline.py0000664000175000017500000001560115253035401021230 0ustar pieterpieter"""Test the "pipeline.py" restricted parallel programming library.""" import unittest import pytest from beets.util import pipeline # Some simple pipeline stages for testing. def _produce(num=5): yield from range(num) def _work(): i = None while True: i = yield i i *= 2 def _consume(result): while True: i = yield result.append(i) # Pipeline stages that raise an exception. class PipelineError(Exception): pass def _exc_produce(num=5): yield from range(num) raise PipelineError() def _exc_work(num=3): i = None while True: i = yield i if i == num: raise PipelineError() i *= 2 def _exc_consume(result, num=4): while True: i = yield if i == num: raise PipelineError() result.append(i) # A worker that yields a bubble. def _bub_work(num=3): i = None while True: i = yield i if i == num: i = pipeline.BUBBLE else: i *= 2 # Yet another worker that yields multiple messages. def _multi_work(): i = None while True: i = yield i i = pipeline.multiple([i, -i]) class SimplePipelineTest(unittest.TestCase): def setUp(self): self.result = [] self.pl = pipeline.Pipeline( (_produce(), _work(), _consume(self.result)) ) def test_run_sequential(self): self.pl.run_sequential() assert self.result == [0, 2, 4, 6, 8] def test_run_parallel(self): self.pl.run_parallel() assert self.result == [0, 2, 4, 6, 8] def test_pull(self): pl = pipeline.Pipeline((_produce(), _work())) assert list(pl.pull()) == [0, 2, 4, 6, 8] def test_pull_chain(self): pl = pipeline.Pipeline((_produce(), _work())) pl2 = pipeline.Pipeline((pl.pull(), _work())) assert list(pl2.pull()) == [0, 4, 8, 12, 16] class ParallelStageTest(unittest.TestCase): def setUp(self): self.result = [] self.pl = pipeline.Pipeline( (_produce(), (_work(), _work()), _consume(self.result)) ) def test_run_sequential(self): self.pl.run_sequential() assert self.result == [0, 2, 4, 6, 8] def test_run_parallel(self): self.pl.run_parallel() # Order possibly not preserved; use set equality. assert set(self.result) == {0, 2, 4, 6, 8} def test_pull(self): pl = pipeline.Pipeline((_produce(), (_work(), _work()))) assert list(pl.pull()) == [0, 2, 4, 6, 8] class ExceptionTest(unittest.TestCase): def setUp(self): self.result = [] def run_sequential(self, *stages): pl = pipeline.Pipeline(stages) with pytest.raises(PipelineError): pl.run_sequential() def run_parallel(self, *stages): pl = pipeline.Pipeline(stages) with pytest.raises(PipelineError): pl.run_parallel() def test_run_sequential(self): """Test that exceptions from various stages of the pipeline are properly propagated when running sequentially. """ self.run_sequential(_exc_produce(), _work(), _consume(self.result)) self.run_sequential(_produce(), _exc_work(), _consume(self.result)) self.run_sequential(_produce(), _work(), _exc_consume(self.result)) def test_run_parallel(self): """Test that exceptions from various stages of the pipeline are properly propagated when running in parallel. """ self.run_parallel(_exc_produce(), _work(), _consume(self.result)) self.run_parallel(_produce(), _exc_work(), _consume(self.result)) self.run_parallel(_produce(), _work(), _exc_consume(self.result)) def test_pull(self): pl = pipeline.Pipeline((_produce(), _exc_work())) pull = pl.pull() for i in range(3): next(pull) with pytest.raises(PipelineError): next(pull) class ParallelExceptionTest(unittest.TestCase): def setUp(self): self.result = [] self.pl = pipeline.Pipeline( (_produce(), (_exc_work(), _exc_work()), _consume(self.result)) ) def test_run_parallel(self): with pytest.raises(PipelineError): self.pl.run_parallel() class ConstrainedThreadedPipelineTest(unittest.TestCase): def setUp(self): self.result = [] def test_constrained(self): # Do a "significant" amount of work... self.pl = pipeline.Pipeline( (_produce(1000), _work(), _consume(self.result)) ) # ... with only a single queue slot. self.pl.run_parallel(1) assert self.result == [i * 2 for i in range(1000)] def test_constrained_exception(self): # Raise an exception in a constrained pipeline. self.pl = pipeline.Pipeline( (_produce(1000), _exc_work(), _consume(self.result)) ) with pytest.raises(PipelineError): self.pl.run_parallel(1) def test_constrained_parallel(self): self.pl = pipeline.Pipeline( (_produce(1000), (_work(), _work()), _consume(self.result)) ) self.pl.run_parallel(1) assert set(self.result) == {i * 2 for i in range(1000)} class BubbleTest(unittest.TestCase): def setUp(self): self.result = [] self.pl = pipeline.Pipeline( (_produce(), _bub_work(), _consume(self.result)) ) def test_run_sequential(self): self.pl.run_sequential() assert self.result == [0, 2, 4, 8] def test_run_parallel(self): self.pl.run_parallel() assert self.result == [0, 2, 4, 8] def test_pull(self): pl = pipeline.Pipeline((_produce(), _bub_work())) assert list(pl.pull()) == [0, 2, 4, 8] class MultiMessageTest(unittest.TestCase): def setUp(self): self.result = [] self.pl = pipeline.Pipeline( (_produce(), _multi_work(), _consume(self.result)) ) def test_run_sequential(self): self.pl.run_sequential() assert self.result == [0, 0, 1, -1, 2, -2, 3, -3, 4, -4] def test_run_parallel(self): self.pl.run_parallel() assert self.result == [0, 0, 1, -1, 2, -2, 3, -3, 4, -4] def test_pull(self): pl = pipeline.Pipeline((_produce(), _multi_work())) assert list(pl.pull()) == [0, 0, 1, -1, 2, -2, 3, -3, 4, -4] class StageDecoratorTest(unittest.TestCase): def test_stage_decorator(self): @pipeline.stage def add(n, i): return i + n pl = pipeline.Pipeline([iter([1, 2, 3]), add(2)]) assert list(pl.pull()) == [3, 4, 5] def test_mutator_stage_decorator(self): @pipeline.mutator_stage def setkey(key, item): item[key] = True pl = pipeline.Pipeline( [iter([{"x": False}, {"a": False}]), setkey("x")] ) assert list(pl.pull()) == [{"x": True}, {"a": False, "x": True}] beetbox-beets-00724b7/test/util/test_diff.py0000664000175000017500000000656415253035401020343 0ustar pieterpieterfrom textwrap import dedent import pytest from beets.library import Item from beets.util.diff import _field_diff p = pytest.param class TestFieldDiff: @pytest.fixture(autouse=True) def configure_color(self, config, color): config["ui"]["color"] = color @pytest.fixture(autouse=True) def patch_colorize(self, monkeypatch): """Patch to return a deterministic string format instead of ANSI codes.""" monkeypatch.setattr( "beets.util.color._colorize", lambda color_name, text: f"[{color_name}]{text}[/]", ) @staticmethod def diff_fmt(old, new): return f"[text_diff_removed]{old}[/] -> [text_diff_added]{new}[/]" @pytest.mark.parametrize( "old_data, new_data, field, expected_diff", [ p({"title": "foo"}, {"title": "foo"}, "title", None, id="no_change"), p({"bpm": 120.0}, {"bpm": 120.005}, "bpm", None, id="float_close_enough"), p({"bpm": 120.0}, {"bpm": 121.0}, "bpm", f"bpm: {diff_fmt('120', '121')}", id="float_changed"), p({"title": "foo"}, {"title": "bar"}, "title", f"title: {diff_fmt('foo', 'bar')}", id="string_full_replace"), p({"title": "prefix foo"}, {"title": "prefix bar"}, "title", "title: prefix [text_diff_removed]foo[/] -> prefix [text_diff_added]bar[/]", id="string_partial_change"), p({"year": 2000}, {"year": 2001}, "year", f"year: {diff_fmt('2000', '2001')}", id="int_changed"), p({}, {"artist": "Artist"}, "artist", "artist: -> [text_diff_added]Artist[/]", id="field_added"), p({"artist": "Artist"}, {}, "artist", "artist: [text_diff_removed]Artist[/] -> ", id="field_removed"), p({"track": 1}, {"track": 2}, "track", f"track: {diff_fmt('01', '02')}", id="formatted_value_changed"), p({"mb_trackid": None}, {"mb_trackid": "1234"}, "mb_trackid", "mb_trackid: -> [text_diff_added]1234[/]", id="none_to_value"), p({}, {"new_flex": "foo"}, "new_flex", "[text_diff_added]new_flex: foo[/]", id="flex_field_added"), p({"old_flex": "foo"}, {}, "old_flex", "[text_diff_removed]old_flex: foo[/]", id="flex_field_removed"), p({"albumtypes": ["album", "ep"]}, {"albumtypes": ["ep", "album"]}, "albumtypes", None, id="multi_value_unchanged"), p( {"albumtypes": ["ep"]}, {"albumtypes": ["album", "compilation"]}, "albumtypes", dedent(""" albumtypes: [text_diff_removed] - ep[/] [text_diff_added] + album[/] [text_diff_added] + compilation[/] """).strip(), id="multi_value_changed" ), ], ) # fmt: skip @pytest.mark.parametrize("color", [True], ids=["color_enabled"]) def test_field_diff_colors(self, old_data, new_data, field, expected_diff): old_item = Item(**old_data) new_item = Item(**new_data) diff = _field_diff(field, old_item.formatted(), new_item.formatted()) assert diff == expected_diff @pytest.mark.parametrize("color", [False], ids=["color_disabled"]) def test_field_diff_no_color(self): old_item = Item(title="foo") new_item = Item(title="bar") diff = _field_diff("title", old_item.formatted(), new_item.formatted()) assert diff == "title: foo -> bar" beetbox-beets-00724b7/test/util/test_id_extractors.py0000664000175000017500000000652415253035401022301 0ustar pieterpieterfrom typing import NamedTuple import pytest from beets.util.id_extractors import extract_release_id @pytest.mark.parametrize( "source, id_string, expected", [ ("spotify", "39WqpoPgZxygo6YQjehLJJ", "39WqpoPgZxygo6YQjehLJJ"), ("spotify", "blah blah", None), ("spotify", "https://open.spotify.com/album/39WqpoPgZxygo6YQjehLJJ", "39WqpoPgZxygo6YQjehLJJ"), ("spotify", "spotify:album:39WqpoPgZxygo6YQjehLJJ", "39WqpoPgZxygo6YQjehLJJ"), ("spotify", "spotify:track:39WqpoPgZxygo6YQjehLJJ", "39WqpoPgZxygo6YQjehLJJ"), ("deezer", "176356382", "176356382"), ("deezer", "blah blah", None), ("deezer", "https://www.deezer.com/album/176356382", "176356382"), ("beatport", "3089651", "3089651"), ("beatport", "blah blah", None), ("beatport", "https://www.beatport.com/release/album-name/3089651", "3089651"), ("discogs", "http://www.discogs.com/G%C3%BCnther-Lause-Meru-Ep/release/4354798", "4354798"), ("discogs", "http://www.discogs.com/release/4354798-G%C3%BCnther-Lause-Meru-Ep", "4354798"), ("discogs", "http://www.discogs.com/G%C3%BCnther-4354798Lause-Meru-Ep/release/4354798", "4354798"), ("discogs", "http://www.discogs.com/release/4354798-G%C3%BCnther-4354798Lause-Meru-Ep/", "4354798"), ("discogs", "[r4354798]", "4354798"), ("discogs", "r4354798", "4354798"), ("discogs", "4354798", "4354798"), ("discogs", "yet-another-metadata-provider.org/foo/12345", None), ("discogs", "005b84a0-ecd6-39f1-b2f6-6eb48756b268", None), ("musicbrainz", "28e32c71-1450-463e-92bf-e0a46446fc11", "28e32c71-1450-463e-92bf-e0a46446fc11"), ("musicbrainz", "blah blah", None), ("musicbrainz", "https://musicbrainz.org/entity/28e32c71-1450-463e-92bf-e0a46446fc11", "28e32c71-1450-463e-92bf-e0a46446fc11"), ("bandcamp", "https://nameofartist.bandcamp.com/album/nameofalbum", "https://nameofartist.bandcamp.com/album/nameofalbum"), ("tidal", "https://tidal.com/browse/album/76699758", "76699758"), ("tidal", "https://tidal.com/track/463928643/u", "463928643"), ("tidal", "blah blah", None), ], ) # fmt: skip def test_extract_release_id(source, id_string, expected): assert extract_release_id(source, id_string) == expected class SourceWithURL(NamedTuple): source: str url: str source_with_urls = [ SourceWithURL("spotify", "https://open.spotify.com/album/39WqpoPgZxygo6YQjehLJJ"), SourceWithURL("deezer", "https://www.deezer.com/album/176356382"), SourceWithURL("beatport", "https://www.beatport.com/release/album-name/3089651"), SourceWithURL("discogs", "http://www.discogs.com/G%C3%BCnther-Lause-Meru-Ep/release/4354798"), SourceWithURL("musicbrainz", "https://musicbrainz.org/entity/28e32c71-1450-463e-92bf-e0a46446fc11"), SourceWithURL("tidal", "https://tidal.com/track/463928643"), ] # fmt: skip @pytest.mark.parametrize("source", [s.source for s in source_with_urls]) @pytest.mark.parametrize("source_with_url", source_with_urls) def test_match_source_url(source, source_with_url): if source == source_with_url.source: assert extract_release_id(source, source_with_url.url) else: assert not extract_release_id(source, source_with_url.url), ( f"Source {source} pattern should not match {source_with_url.source} URL" ) beetbox-beets-00724b7/test/util/test_color.py0000664000175000017500000000151515253035401020540 0ustar pieterpieterfrom unittest import TestCase from beets.util.color import color_split, uncolorize class ColorTestCase(TestCase): def test_uncolorize(self): assert "test" == uncolorize("test") txt = uncolorize("\x1b[31mtest\x1b[39;49;00m") assert "test" == txt txt = uncolorize("\x1b[31mtest\x1b[39;49;00m test") assert "test test" == txt txt = uncolorize("\x1b[31mtest\x1b[39;49;00mtest") assert "testtest" == txt txt = uncolorize("test \x1b[31mtest\x1b[39;49;00m test") assert "test test test" == txt def test_color_split(self): exp = ("test", "") res = color_split("test", 5) assert exp == res exp = ("\x1b[31mtes\x1b[39;49;00m", "\x1b[31mt\x1b[39;49;00m") res = color_split("\x1b[31mtest\x1b[39;49;00m", 3) assert exp == res beetbox-beets-00724b7/test/util/test_art_resize.py0000664000175000017500000000721515253035401021574 0ustar pieterpieter"""Tests for image resizing based on filesize.""" import os import unittest from pathlib import Path from unittest.mock import patch from beets.test import _common from beets.test.fixtures import DummyIMBackend from beets.test.helper import BeetsTestCase, CleanupModulesMixin from beets.util import command_output from beets.util.artresizer import IMBackend, PILBackend class ArtResizerFileSizeTest(CleanupModulesMixin, BeetsTestCase): """Unittest test case for Art Resizer to a specific filesize.""" modules = (IMBackend.__module__,) IMG_225x225 = _common.RSRC / "abbey.jpg" def _test_img_resize(self, backend): """Test resizing based on file size, given a resize_func.""" # Check quality setting unaffected by new parameter im_95_qual = backend.resize( 225, self.IMG_225x225, quality=95, max_filesize=0 ) # check valid path returned - max_filesize hasn't broken resize command assert Path(os.fsdecode(im_95_qual)).exists() # Attempt a lower filesize with same quality im_a = backend.resize( 225, self.IMG_225x225, quality=95, max_filesize=0.9 * os.stat(im_95_qual).st_size, ) assert Path(os.fsdecode(im_a)).exists() # target size was achieved assert os.stat(im_a).st_size < os.stat(im_95_qual).st_size # Attempt with lower initial quality im_75_qual = backend.resize( 225, self.IMG_225x225, quality=75, max_filesize=0 ) assert Path(os.fsdecode(im_75_qual)).exists() im_b = backend.resize( 225, self.IMG_225x225, quality=95, max_filesize=0.9 * os.stat(im_75_qual).st_size, ) assert Path(os.fsdecode(im_b)).exists() # Check high (initial) quality still gives a smaller filesize assert os.stat(im_b).st_size < os.stat(im_75_qual).st_size @unittest.skipUnless(PILBackend.available(), "PIL not available") def test_pil_file_resize(self): """Test PIL resize function is lowering file size.""" self._test_img_resize(PILBackend()) @unittest.skipUnless(IMBackend.available(), "ImageMagick not available") def test_im_file_resize(self): """Test IM resize function is lowering file size.""" self._test_img_resize(IMBackend()) @unittest.skipUnless(PILBackend.available(), "PIL not available") def test_pil_file_deinterlace(self): """Test PIL deinterlace function. Check if the `PILBackend.deinterlace()` function returns images that are non-progressive """ path = PILBackend().deinterlace(self.IMG_225x225) from PIL import Image with Image.open(path) as img: assert "progression" not in img.info @unittest.skipUnless(IMBackend.available(), "ImageMagick not available") def test_im_file_deinterlace(self): """Test ImageMagick deinterlace function. Check if the `IMBackend.deinterlace()` function returns images that are non-progressive. """ im = IMBackend() path = im.deinterlace(self.IMG_225x225) cmd = [*im.identify_cmd, "-format", "%[interlace]", os.fsdecode(path)] out = command_output(cmd).stdout assert out == b"None" @patch("beets.util.artresizer.util") def test_write_metadata_im(self, mock_util): """Test writing image metadata.""" metadata = {"a": "A", "b": "B"} im = DummyIMBackend() im.write_metadata("foo", metadata) command = [*im.convert_cmd, *"foo -set a A -set b B foo".split()] mock_util.command_output.assert_called_once_with(command) beetbox-beets-00724b7/test/util/test_layout.py0000664000175000017500000000231115253035401020732 0ustar pieterpieterfrom unittest import TestCase from beets.util.layout import split_into_lines class LayoutTestCase(TestCase): def test_split_into_lines(self): # Test uncolored text txt = split_into_lines("test test test", 5, 5) assert txt == ["test", "test", "test"] # Test multiple colored texts colored_text = "\x1b[31mtest \x1b[39;49;00m" * 3 split_txt = [ "\x1b[31mtest\x1b[39;49;00m", "\x1b[31mtest\x1b[39;49;00m", "\x1b[31mtest\x1b[39;49;00m", ] txt = split_into_lines(colored_text, 5, 5) assert txt == split_txt # Test single color, multi space text colored_text = "\x1b[31m test test test \x1b[39;49;00m" txt = split_into_lines(colored_text, 5, 5) assert txt == split_txt # Test single color, different spacing colored_text = "\x1b[31mtest\x1b[39;49;00mtest test test" # ToDo: fix color_len to handle mid-text color escapes, and thus # split colored texts over newlines (potentially with dashes?) split_txt = ["\x1b[31mtest\x1b[39;49;00mt", "est", "test", "test"] txt = split_into_lines(colored_text, 5, 5) assert txt == split_txt beetbox-beets-00724b7/test/util/test_units.py0000664000175000017500000000207615253035401020567 0ustar pieterpieterimport pytest from beets.util.units import human_bytes, human_seconds @pytest.mark.parametrize( "input_bytes,expected", [ (0, "0.0 B"), (30, "30.0 B"), (pow(2, 10), "1.0 KiB"), (pow(2, 20), "1.0 MiB"), (pow(2, 30), "1.0 GiB"), (pow(2, 40), "1.0 TiB"), (pow(2, 50), "1.0 PiB"), (pow(2, 60), "1.0 EiB"), (pow(2, 70), "1.0 ZiB"), (pow(2, 80), "1.0 YiB"), (pow(2, 90), "1.0 HiB"), (pow(2, 100), "big"), ], ) def test_human_bytes(input_bytes, expected): assert human_bytes(input_bytes) == expected @pytest.mark.parametrize( "input_seconds,expected", [ (0, "0.0 seconds"), (30, "30.0 seconds"), (60, "1.0 minutes"), (90, "1.5 minutes"), (125, "2.1 minutes"), (3600, "1.0 hours"), (86400, "1.0 days"), (604800, "1.0 weeks"), (31449600, "1.0 years"), (314496000, "1.0 decades"), ], ) def test_human_seconds(input_seconds, expected): assert human_seconds(input_seconds) == expected beetbox-beets-00724b7/test/util/test_lyrics.py0000664000175000017500000000512215253035401020725 0ustar pieterpieterimport textwrap from beets.library import Item from beets.util.lyrics import Lyrics class TestLyrics: def test_instrumental_lyrics(self): lyrics = Lyrics( "[Instrumental]", "lrclib", url="https://lrclib.net/api/1" ) assert lyrics.full_text == "" assert lyrics.instrumental assert lyrics.backend == "lrclib" assert lyrics.url == "https://lrclib.net/api/1" assert lyrics.language is None assert lyrics.translation_language is None def test_from_item_without_lyrics(self): item = Item(lyrics=None) lyrics = Lyrics.from_item(item) assert lyrics.text == "" assert not lyrics.synced assert lyrics.full_text == "" assert lyrics.sylt == [] assert lyrics.text_lines == [] def test_from_legacy_text(self, is_importable): text = textwrap.dedent(""" [00:00.00] Some synced lyrics / Quelques paroles synchronisées [00:00.50] [00:01.00] Some more synced lyrics / Quelques paroles plus synchronisées Source: https://lrclib.net/api/1/""") lyrics = Lyrics.from_legacy_text(text) assert lyrics.full_text == textwrap.dedent( """ [00:00.00] Some synced lyrics / Quelques paroles synchronisées [00:00.50] [00:01.00] Some more synced lyrics / Quelques paroles plus synchronisées""" ) assert lyrics.backend == "lrclib" assert lyrics.url == "https://lrclib.net/api/1/" langdetect_available = is_importable("langdetect") assert lyrics.language == ("EN" if langdetect_available else None) assert lyrics.translation_language == ( "FR" if langdetect_available else None ) assert not lyrics.instrumental def test_timestamp_precision_and_sylt(self): text = textwrap.dedent(""" [00:00.05] Centisecond line [00:01.50] Two decimals [00:02.123] Three decimals [01:00.005] Five milliseconds """).strip() lyrics = Lyrics(text) assert lyrics.synced assert lyrics.timestamps == [ "[00:00.05]", "[00:01.50]", "[00:02.123]", "[01:00.005]", ] assert lyrics.text_lines == [ "Centisecond line", "Two decimals", "Three decimals", "Five milliseconds", ] assert lyrics.sylt == [ ("Centisecond line", 50), ("Two decimals", 1500), ("Three decimals", 2123), ("Five milliseconds", 60005), ] beetbox-beets-00724b7/test/util/test_functemplate.py0000664000175000017500000002116715253035401022116 0ustar pieterpieter"""Tests for template engine.""" import unittest from beets.util import functemplate def _normexpr(expr): """Normalize an Expression object's parts, collapsing multiple adjacent text blocks and removing empty text blocks. Generates a sequence of parts. """ textbuf = [] for part in expr.parts: if isinstance(part, str): textbuf.append(part) else: if textbuf: text = "".join(textbuf) if text: yield text textbuf = [] yield part if textbuf: text = "".join(textbuf) if text: yield text def _normparse(text): """Parse a template and then normalize the resulting Expression.""" return _normexpr(functemplate._parse(text)) class ParseTest(unittest.TestCase): def test_empty_string(self): assert list(_normparse("")) == [] def _assert_symbol(self, obj, ident): """Assert that an object is a Symbol with the given identifier.""" assert isinstance(obj, functemplate.Symbol), f"not a Symbol: {obj}" assert obj.ident == ident, f"wrong identifier: {obj.ident} vs. {ident}" def _assert_call(self, obj, ident, numargs): """Assert that an object is a Call with the given identifier and argument count. """ assert isinstance(obj, functemplate.Call), f"not a Call: {obj}" assert obj.ident == ident, f"wrong identifier: {obj.ident} vs. {ident}" assert len(obj.args) == numargs, ( f"wrong argument count in {obj.ident}: {len(obj.args)} vs. {numargs}" ) def test_plain_text(self): assert list(_normparse("hello world")) == ["hello world"] def test_escaped_character_only(self): assert list(_normparse("$$")) == ["$"] def test_escaped_character_in_text(self): assert list(_normparse("a $$ b")) == ["a $ b"] def test_escaped_character_at_start(self): assert list(_normparse("$$ hello")) == ["$ hello"] def test_escaped_character_at_end(self): assert list(_normparse("hello $$")) == ["hello $"] def test_escaped_function_delim(self): assert list(_normparse("a $% b")) == ["a % b"] def test_escaped_sep(self): assert list(_normparse("a $, b")) == ["a , b"] def test_escaped_close_brace(self): assert list(_normparse("a $} b")) == ["a } b"] def test_bare_value_delim_kept_intact(self): assert list(_normparse("a $ b")) == ["a $ b"] def test_bare_function_delim_kept_intact(self): assert list(_normparse("a % b")) == ["a % b"] def test_bare_opener_kept_intact(self): assert list(_normparse("a { b")) == ["a { b"] def test_bare_closer_kept_intact(self): assert list(_normparse("a } b")) == ["a } b"] def test_bare_sep_kept_intact(self): assert list(_normparse("a , b")) == ["a , b"] def test_symbol_alone(self): parts = list(_normparse("$foo")) assert len(parts) == 1 self._assert_symbol(parts[0], "foo") def test_symbol_in_text(self): parts = list(_normparse("hello $foo world")) assert len(parts) == 3 assert parts[0] == "hello " self._assert_symbol(parts[1], "foo") assert parts[2] == " world" def test_symbol_with_braces(self): parts = list(_normparse("hello${foo}world")) assert len(parts) == 3 assert parts[0] == "hello" self._assert_symbol(parts[1], "foo") assert parts[2] == "world" def test_unclosed_braces_symbol(self): assert list(_normparse("a ${ b")) == ["a ${ b"] def test_empty_braces_symbol(self): assert list(_normparse("a ${} b")) == ["a ${} b"] def test_call_without_args_at_end(self): assert list(_normparse("foo %bar")) == ["foo %bar"] def test_call_without_args(self): assert list(_normparse("foo %bar baz")) == ["foo %bar baz"] def test_call_with_unclosed_args(self): assert list(_normparse("foo %bar{ baz")) == ["foo %bar{ baz"] def test_call_with_unclosed_multiple_args(self): assert list(_normparse("foo %bar{bar,bar baz")) == [ "foo %bar{bar,bar baz" ] def test_call_empty_arg(self): parts = list(_normparse("%foo{}")) assert len(parts) == 1 self._assert_call(parts[0], "foo", 1) assert list(_normexpr(parts[0].args[0])) == [] def test_call_single_arg(self): parts = list(_normparse("%foo{bar}")) assert len(parts) == 1 self._assert_call(parts[0], "foo", 1) assert list(_normexpr(parts[0].args[0])) == ["bar"] def test_call_two_args(self): parts = list(_normparse("%foo{bar,baz}")) assert len(parts) == 1 self._assert_call(parts[0], "foo", 2) assert list(_normexpr(parts[0].args[0])) == ["bar"] assert list(_normexpr(parts[0].args[1])) == ["baz"] def test_call_with_escaped_sep(self): parts = list(_normparse("%foo{bar$,baz}")) assert len(parts) == 1 self._assert_call(parts[0], "foo", 1) assert list(_normexpr(parts[0].args[0])) == ["bar,baz"] def test_call_with_escaped_close(self): parts = list(_normparse("%foo{bar$}baz}")) assert len(parts) == 1 self._assert_call(parts[0], "foo", 1) assert list(_normexpr(parts[0].args[0])) == ["bar}baz"] def test_call_with_symbol_argument(self): parts = list(_normparse("%foo{$bar,baz}")) assert len(parts) == 1 self._assert_call(parts[0], "foo", 2) arg_parts = list(_normexpr(parts[0].args[0])) assert len(arg_parts) == 1 self._assert_symbol(arg_parts[0], "bar") assert list(_normexpr(parts[0].args[1])) == ["baz"] def test_call_with_nested_call_argument(self): parts = list(_normparse("%foo{%bar{},baz}")) assert len(parts) == 1 self._assert_call(parts[0], "foo", 2) arg_parts = list(_normexpr(parts[0].args[0])) assert len(arg_parts) == 1 self._assert_call(arg_parts[0], "bar", 1) assert list(_normexpr(parts[0].args[1])) == ["baz"] def test_nested_call_with_argument(self): parts = list(_normparse("%foo{%bar{baz}}")) assert len(parts) == 1 self._assert_call(parts[0], "foo", 1) arg_parts = list(_normexpr(parts[0].args[0])) assert len(arg_parts) == 1 self._assert_call(arg_parts[0], "bar", 1) assert list(_normexpr(arg_parts[0].args[0])) == ["baz"] def test_sep_before_call_two_args(self): parts = list(_normparse("hello, %foo{bar,baz}")) assert len(parts) == 2 assert parts[0] == "hello, " self._assert_call(parts[1], "foo", 2) assert list(_normexpr(parts[1].args[0])) == ["bar"] assert list(_normexpr(parts[1].args[1])) == ["baz"] def test_sep_with_symbols(self): parts = list(_normparse("hello,$foo,$bar")) assert len(parts) == 4 assert parts[0] == "hello," self._assert_symbol(parts[1], "foo") assert parts[2] == "," self._assert_symbol(parts[3], "bar") def test_newline_at_end(self): parts = list(_normparse("foo\n")) assert len(parts) == 1 assert parts[0] == "foo\n" class EvalTest(unittest.TestCase): def _eval(self, template): values = {"foo": "bar", "baz": "BaR"} functions = {"lower": str.lower, "len": len} return functemplate.Template(template).substitute(values, functions) def test_plain_text(self): assert self._eval("foo") == "foo" def test_subtitute_value(self): assert self._eval("$foo") == "bar" def test_subtitute_value_in_text(self): assert self._eval("hello $foo world") == "hello bar world" def test_not_subtitute_undefined_value(self): assert self._eval("$bar") == "$bar" def test_function_call(self): assert self._eval("%lower{FOO}") == "foo" def test_function_call_with_text(self): assert self._eval("A %lower{FOO} B") == "A foo B" def test_nested_function_call(self): assert self._eval("%lower{%lower{FOO}}") == "foo" def test_symbol_in_argument(self): assert self._eval("%lower{$baz}") == "bar" def test_function_call_exception(self): res = self._eval("%lower{a,b,c,d,e}") assert isinstance(res, str) def test_function_returning_integer(self): assert self._eval("%len{foo}") == "3" def test_not_subtitute_undefined_func(self): assert self._eval("%bar{}") == "%bar{}" def test_not_subtitute_func_with_no_args(self): assert self._eval("%lower") == "%lower" def test_function_call_with_empty_arg(self): assert self._eval("%len{}") == "0" beetbox-beets-00724b7/test/util/test_hidden.py0000664000175000017500000000322715253035401020657 0ustar pieterpieter"""Tests for the 'hidden' utility.""" import ctypes import errno import subprocess import sys import tempfile import unittest from beets.util import hidden class HiddenFileTest(unittest.TestCase): def setUp(self): pass def test_osx_hidden(self): if not sys.platform == "darwin": self.skipTest("sys.platform is not darwin") return with tempfile.NamedTemporaryFile(delete=False) as f: try: command = ["chflags", "hidden", f.name] subprocess.Popen(command).wait() except OSError as e: if e.errno == errno.ENOENT: self.skipTest("unable to find chflags") else: raise e assert hidden.is_hidden(f.name) def test_windows_hidden(self): if not sys.platform == "win32": self.skipTest("sys.platform is not windows") return # FILE_ATTRIBUTE_HIDDEN = 2 (0x2) from GetFileAttributes documentation. hidden_mask = 2 with tempfile.NamedTemporaryFile() as f: # Hide the file using success = ctypes.windll.kernel32.SetFileAttributesW( f.name, hidden_mask ) if not success: self.skipTest("unable to set file attributes") assert hidden.is_hidden(f.name) def test_other_hidden(self): if sys.platform == "darwin" or sys.platform == "win32": self.skipTest("sys.platform is known") return with tempfile.NamedTemporaryFile(prefix=".tmp") as f: fn = f.name assert hidden.is_hidden(fn) beetbox-beets-00724b7/test/util/test_m3ufile.py0000664000175000017500000001055415253035401020771 0ustar pieterpieter"""Testsuite for the M3UFile class.""" import sys from pathlib import Path import pytest from beets.test._common import RSRC from beets.test.helper import PathsMixin from beets.util import bytestring_path from beets.util.m3u import EmptyPlaylistError, M3UFile class TestM3UFile(PathsMixin): """Tests the M3UFile class.""" def test_playlist_write_empty(self): """Test whether saving an empty playlist file raises an error.""" the_playlist_file = self.temp_path / "playlist.m3u8" m3ufile = M3UFile(the_playlist_file) with pytest.raises(EmptyPlaylistError): m3ufile.write() def test_playlist_write(self): """Test saving ascii paths to a playlist file.""" the_playlist_file = self.temp_path / "playlist.m3u8" m3ufile = M3UFile(the_playlist_file) m3ufile.set_contents( [ bytestring_path("/This/is/a/path/to_a_file.mp3"), bytestring_path("/This/is/another/path/to_a_file.mp3"), ] ) m3ufile.write() assert the_playlist_file.exists() def test_playlist_write_unicode(self): """Test saving unicode paths to a playlist file.""" the_playlist_file = self.temp_path / "playlist.m3u8" m3ufile = M3UFile(the_playlist_file) m3ufile.set_contents( [ bytestring_path("/This/is/Ã¥/path/to_a_file.mp3"), bytestring_path("/This/is/another/path/tö_a_file.mp3"), ] ) m3ufile.write() assert the_playlist_file.exists() @pytest.mark.skipif(sys.platform != "win32", reason="win32") def test_playlist_write_and_read_unicode_windows(self): """Test saving unicode paths to a playlist file on Windows.""" the_playlist_file = ( self.temp_path / "playlist_write_and_read_windows.m3u8" ) m3ufile = M3UFile(the_playlist_file) m3ufile.set_contents( [ bytestring_path(r"x:\This\is\Ã¥\path\to_a_file.mp3"), bytestring_path(r"x:\This\is\another\path\tö_a_file.mp3"), ] ) m3ufile.write() assert the_playlist_file.exists() m3ufile_read = M3UFile(the_playlist_file) m3ufile_read.load() assert m3ufile.media_list[0] == bytestring_path( Path("x:\\") / "This" / "is" / "Ã¥" / "path" / "to_a_file.mp3" ) assert m3ufile.media_list[1] == bytestring_path( r"x:\This\is\another\path\tö_a_file.mp3" ), bytestring_path( Path("x:\\") / "This" / "is" / "another" / "path" / "tö_a_file.mp3" ) @pytest.mark.skipif(sys.platform == "win32", reason="win32") def test_playlist_load_ascii(self): """Test loading ascii paths from a playlist file.""" the_playlist_file = RSRC / "playlist.m3u" m3ufile = M3UFile(the_playlist_file) m3ufile.load() assert m3ufile.media_list[0] == bytestring_path( "/This/is/a/path/to_a_file.mp3" ) @pytest.mark.skipif(sys.platform == "win32", reason="win32") def test_playlist_load_unicode(self): """Test loading unicode paths from a playlist file.""" the_playlist_file = RSRC / "playlist.m3u8" m3ufile = M3UFile(the_playlist_file) m3ufile.load() assert m3ufile.media_list[0] == bytestring_path( "/This/is/Ã¥/path/to_a_file.mp3" ) @pytest.mark.skipif(sys.platform != "win32", reason="win32") def test_playlist_load_unicode_windows(self): """Test loading unicode paths from a playlist file.""" the_playlist_file = RSRC / "playlist_windows.m3u8" winpath = bytestring_path( Path("x:\\") / "This" / "is" / "Ã¥" / "path" / "to_a_file.mp3" ) m3ufile = M3UFile(the_playlist_file) m3ufile.load() assert m3ufile.media_list[0] == winpath def test_playlist_load_extm3u(self): """Test loading a playlist with an #EXTM3U header.""" the_playlist_file = RSRC / "playlist.m3u" m3ufile = M3UFile(the_playlist_file) m3ufile.load() assert m3ufile.extm3u def test_playlist_load_non_extm3u(self): """Test loading a playlist without an #EXTM3U header.""" the_playlist_file = RSRC / "playlist_non_ext.m3u" m3ufile = M3UFile(the_playlist_file) m3ufile.load() assert not m3ufile.extm3u beetbox-beets-00724b7/test/util/test_pathformats.py0000664000175000017500000000105615253035401021752 0ustar pieterpieterfrom beets.util.pathformats import get_path_formats def test_get_path_formats(config): """Ensure the function prepends custom and preserves defaults.""" # override the default 'singleton' path and add a new one config["paths"].set({"singleton": "bar", "new": "hello"}) assert get_path_formats(config["paths"]) == [ ("singleton:true", "bar"), ("new", "hello"), # defaults ("default", "$albumartist/$album%aunique{}/$track $title"), ("comp:true", "Compilations/$album%aunique{}/$track $title"), ] beetbox-beets-00724b7/test/test_importer.py0000664000175000017500000026214515253035401020316 0ustar pieterpieter"""Tests for the general importer functionality.""" from __future__ import annotations import os import re import shutil import stat import sys import unicodedata import unittest from contextlib import contextmanager from functools import cached_property from io import StringIO from pathlib import Path from tarfile import TarFile from tempfile import mkstemp from typing import Literal from unittest.mock import Mock, patch from zipfile import ZipFile import pytest from mediafile import MediaFile from beets import config, importer, logging, plugins, ui, util from beets.autotag import AlbumInfo, AlbumMatch, Distance, TrackInfo from beets.importer.state import ImportState from beets.importer.tasks import ( ImportTaskFactory, albums_in_dir, resolve_upgrade, resolve_upgrade_target, ) from beets.library import Item from beets.test import _common from beets.test.helper import ( NEEDS_FFPROBE, NEEDS_REFLINK, AsIsImporterMixin, AutotagImportHelper, AutotagImportTestCase, AutotagStub, BeetsTestCase, ImportHelper, PluginMixin, TerminalImportMixin, TerminalImportSessionFixture, TestHelper, has_program, is_importable, ) from beets.util import bytestring_path, syspath from beets.util.extension import remux_mpeglayer3_wav class PathsMixin: import_media: list[MediaFile] @cached_property def track_import_path(self) -> Path: return Path(self.import_media[0].path) @cached_property def album_path(self) -> Path: return self.track_import_path.parent @cached_property def track_lib_path(self): return self.lib_path / "Tag Artist" / "Tag Album" / "Tag Track 1.mp3" class TestNonAutotaggedImport(PathsMixin, AsIsImporterMixin, ImportHelper): db_on_disk = True def test_album_created_with_track_artist(self): self.run_asis_importer() albums = self.lib.albums() assert len(albums) == 1 assert albums[0].albumartist == "Tag Artist" def test_import_copy_arrives(self): self.run_asis_importer() assert self.track_lib_path.exists() def test_threaded_import_copy_arrives(self): config["threaded"] = True self.run_asis_importer() assert self.track_lib_path.exists() def test_import_with_move_deletes_import_files(self): assert self.album_path.exists() assert self.track_import_path.exists() (self.album_path / "alog.log").touch() config["clutter"] = ["*.log"] self.run_asis_importer(move=True) assert not self.track_import_path.exists() assert not self.album_path.exists() def test_threaded_import_move_arrives(self): self.run_asis_importer(move=True, threaded=True) assert self.track_lib_path.exists() assert not self.track_import_path.exists() def test_import_without_delete_retains_files(self): self.run_asis_importer(delete=False) assert self.track_import_path.exists() def test_import_with_delete_removes_files(self): self.run_asis_importer(delete=True) assert not self.album_path.exists() assert not self.track_import_path.exists() def test_album_mb_albumartistids(self): self.run_asis_importer() album = self.lib.albums()[0] assert album.mb_albumartistids == album.items()[0].mb_albumartistids @pytest.mark.skipif(not _common.HAVE_SYMLINK, reason="need symlinks") def test_import_link_arrives(self): self.run_asis_importer(link=True) assert self.track_lib_path.exists() assert self.track_lib_path.is_symlink() assert self.track_lib_path.resolve() == self.track_import_path.resolve() @pytest.mark.skipif(not _common.HAVE_HARDLINK, reason="need hardlinks") def test_import_hardlink_arrives(self): self.run_asis_importer(hardlink=True) assert self.track_lib_path.exists() media_stat = self.track_import_path.stat() lib_media_stat = self.track_lib_path.stat() assert media_stat[stat.ST_INO] == lib_media_stat[stat.ST_INO] assert media_stat[stat.ST_DEV] == lib_media_stat[stat.ST_DEV] @NEEDS_REFLINK def test_import_reflink_arrives(self): # Detecting reflinks is currently tricky due to various fs # implementations, we'll just check the file exists. self.run_asis_importer(reflink=True) assert self.track_lib_path.exists() def test_import_reflink_auto_arrives(self): # Should pass regardless of reflink support due to fallback. self.run_asis_importer(reflink="auto") assert self.track_lib_path.exists() def create_archive(session): handle, path = mkstemp(dir=session.temp_path) path = bytestring_path(path) os.close(handle) archive = ZipFile(os.fsdecode(path), mode="w") archive.write(_common.RSRC / "full.mp3", "full.mp3") archive.close() return bytestring_path(path) class TestRmTemp(TestHelper): """Tests that temporarily extracted archives are properly removed after usage. """ def setup_beets(self): super().setup_beets() self.want_resume = False self.config["incremental"] = False self.config["copy"] = False self.config["move"] = False self.config["delete"] = False self._old_home = None def test_rm(self): zip_path = create_archive(self) archive_task = importer.ArchiveImportTask(zip_path) archive_task.extract() tmp_path = Path(os.fsdecode(archive_task.toppath)) assert tmp_path.exists() archive_task.finalize(self) assert not tmp_path.exists() def test_archive_removed_on_move_complete(self): zip_path = create_archive(self) archive_task = importer.ArchiveImportTask(zip_path) archive_task.extract() for root, _, files in os.walk(archive_task.toppath): for f in files: os.remove(os.path.join(root, f)) assert Path(os.fsdecode(zip_path)).exists() archive_task.cleanup(move=True) assert not Path(os.fsdecode(zip_path)).exists() def test_archive_preserved_on_move_partial(self): zip_path = create_archive(self) archive_task = importer.ArchiveImportTask(zip_path) archive_task.extract() archive_task.cleanup(move=True) assert Path(os.fsdecode(zip_path)).exists() def test_archive_preserved_on_copy(self): zip_path = create_archive(self) archive_task = importer.ArchiveImportTask(zip_path) archive_task.extract() archive_task.cleanup(copy=True) assert Path(os.fsdecode(zip_path)).exists() def test_tempdir_removed_in_all_modes(self): for cleanup_kwargs in ( {}, {"move": True}, {"copy": True}, {"copy": True, "delete": True}, ): zip_path = create_archive(self) archive_task = importer.ArchiveImportTask(zip_path) archive_task.extract() tmp_path = Path(os.fsdecode(archive_task.toppath)) assert tmp_path.exists(), f"extract failed for {cleanup_kwargs}" archive_task.cleanup(**cleanup_kwargs) assert not tmp_path.exists(), ( f"tempdir {tmp_path} not removed for {cleanup_kwargs}" ) class TestImportZip(AsIsImporterMixin, ImportHelper): def create_archive(self): return create_archive(self) def test_import_zip(self): archive_path = self.create_archive() assert len(self.lib.items()) == 0 assert len(self.lib.albums()) == 0 self.run_asis_importer(import_dir=archive_path) assert len(self.lib.items()) == 1 assert len(self.lib.albums()) == 1 class TestImportTar(TestImportZip): def create_archive(self): (handle, path) = mkstemp(dir=self.temp_path) path = bytestring_path(path) os.close(handle) archive = TarFile(os.fsdecode(path), mode="w") archive.add(_common.RSRC / "full.mp3", "full.mp3") archive.close() return path @pytest.mark.skipif( not (is_importable("rarfile") and has_program("unrar")), reason="rarfile or unrar program not found", ) class TestImportRar(TestImportZip): def create_archive(self): return _common.RSRC / "archive.rar" @pytest.mark.skipif(not is_importable("py7zr"), reason="py7zr is not available") class TestImport7z(TestImportZip): def create_archive(self): return _common.RSRC / "archive.7z" @pytest.mark.skip(reason="Implement me!") class TestImportPasswordRar(TestImportZip): def create_archive(self): return _common.RSRC / "password.rar" class ImportSingletonTest(AutotagImportTestCase): """Test ``APPLY`` and ``ASIS`` choices for an import session with singletons config set to True. """ def setUp(self): super().setUp() self.prepare_album_for_import(1) self.importer = self.setup_singleton_importer() def test_apply_asis_adds_only_singleton_track(self): self.importer.add_choice(importer.Action.ASIS) self.importer.run() # album not added assert not self.lib.albums() assert self.lib.items().get().title == "Tag Track 1" assert (self.lib_path / "singletons" / "Tag Track 1.mp3").exists() def test_apply_candidate_adds_track(self): self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert not self.lib.albums() assert self.lib.items().get().title == "Applied Track 1" assert (self.lib_path / "singletons" / "Applied Track 1.mp3").exists() def test_apply_from_scratch_removes_other_metadata(self): config["import"]["from_scratch"] = True for mediafile in self.import_media: mediafile.comments = "Tag Comment" mediafile.save() self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.items().get().comments == "" def test_skip_does_not_add_track(self): self.importer.add_choice(importer.Action.SKIP) self.importer.run() assert not self.lib.items() def test_skip_first_add_second_asis(self): self.prepare_album_for_import(2) self.importer.add_choice(importer.Action.SKIP) self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert len(self.lib.items()) == 1 def test_import_single_files(self): resource_path = _common.RSRC / "empty.mp3" single_path = self.import_path / "track_2.mp3" util.copy(resource_path, single_path) import_files = [self.import_path / "album", single_path] self.setup_importer() self.importer.paths = list(map(os.fsencode, import_files)) self.importer.add_choice(importer.Action.ASIS) self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert len(self.lib.items()) == 2 assert len(self.lib.albums()) == 2 def test_set_fields(self): genres = ["\U0001f3b7 Jazz", "Rock"] collection = "To Listen" disc = 0 config["import"]["set_fields"] = { "genres": "; ".join(genres), "collection": collection, "disc": disc, "title": "$title - formatted", } # As-is item import. assert self.lib.albums().get() is None self.importer.add_choice(importer.Action.ASIS) self.importer.run() for item in self.lib.items(): item.load() # TODO: Not sure this is necessary. assert item.genres == genres assert item.collection == collection assert item.title == "Tag Track 1 - formatted" assert item.disc == disc # Remove item from library to test again with APPLY choice. item.remove() # Autotagged. assert not self.lib.albums() self.importer.clear_choices() self.importer.add_choice(importer.Action.APPLY) self.importer.run() for item in self.lib.items(): item.load() assert item.genres == genres assert item.collection == collection assert item.title == "Applied Track 1 - formatted" assert item.disc == disc @pytest.mark.skipif( not has_program("ffprobe", ["-L"]), reason="need ffprobe for format recognition", ) class TestImportFormat(ImportHelper): """Test fix_extension during import.""" def test_recognize_format(self): resource_src = _common.RSRC / "no_ext" resource_path = self.import_path / "no_ext" util.copy(resource_src, resource_path) self.setup_importer(autotag=False) self.importer.paths = [os.fsencode(resource_path)] self.importer.run() assert self.lib.items().get().path.endswith(b".mp3") def test_recognize_format_already_exist(self, caplog): resource_path = _common.RSRC / "no_ext" temp_resource_path = self.temp_path / "no_ext" util.copy(resource_path, temp_resource_path) new_path = self.temp_path / "no_ext.mp3" util.copy(temp_resource_path, new_path) self.setup_importer(autotag=False) self.importer.paths = [os.fsencode(temp_resource_path)] with caplog.at_level("DEBUG"): self.importer.run() assert ( "Import file with matching format to original target" in caplog.messages ) assert self.lib.items().get().path.endswith(b".mp3") def test_recognize_format_not_music(self): resource_path = _common.RSRC / "no_ext_not_music" self.setup_importer(autotag=False) self.importer.paths = [os.fsencode(resource_path)] self.importer.run() assert len(self.lib.items()) == 0 def test_recognize_format_change_original(self): config["import"]["fix_ext_inplace"] = True resource_src = _common.RSRC / "no_ext" resource_path = self.temp_path / "no_ext" util.copy(resource_src, resource_path) self.setup_importer(autotag=False) self.importer.paths = [os.fsencode(resource_path)] self.importer.run() assert not Path(self.temp_path / "no_ext").exists() def test_recognize_format_keep_original(self): config["import"]["fix_ext_inplace"] = False resource_src = _common.RSRC / "no_ext" resource_path = self.temp_path / "no_ext" util.copy(resource_src, resource_path) self.setup_importer(autotag=False) self.importer.paths = [os.fsencode(resource_path)] self.importer.run() assert Path(self.temp_path / "no_ext").exists() class TestImport(PathsMixin, AutotagImportHelper): """Test APPLY, ASIS and SKIP choices.""" def setup_beets(self): super().setup_beets() self.prepare_album_for_import(1) self.setup_importer() def test_asis_moves_album_and_track(self): self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert self.lib.albums().get().album == "Tag Album" item = self.lib.items().get() assert item.title == "Tag Track 1" assert item.filepath.exists() def test_apply_moves_album_and_track(self): self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.albums().get().album == "Applied Album" item = self.lib.items().get() assert item.title == "Applied Track 1" assert item.filepath.exists() def test_apply_from_scratch_removes_other_metadata(self): config["import"]["from_scratch"] = True for mediafile in self.import_media: mediafile.genres = ["Tag Genre"] mediafile.save() self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert not self.lib.items().get().genres def test_apply_from_scratch_keeps_format(self): config["import"]["from_scratch"] = True self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.items().get().format == "MP3" def test_apply_from_scratch_keeps_bitrate(self): config["import"]["from_scratch"] = True bitrate = 80000 self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.items().get().bitrate == bitrate def test_apply_with_move_deletes_import(self): assert self.track_import_path.exists() config["import"]["move"] = True self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert not self.track_import_path.exists() def test_apply_with_delete_deletes_import(self): assert self.track_import_path.exists() config["import"]["delete"] = True self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert not self.track_import_path.exists() def test_skip_does_not_add_track(self): self.importer.add_choice(importer.Action.SKIP) self.importer.run() assert not self.lib.items() @NEEDS_FFPROBE def test_skip_non_album_dirs(self): assert (self.import_path / "album").exists() (self.import_path / "cruft").touch() self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert len(self.lib.albums()) == 1 def test_unmatched_tracks_not_added(self): self.prepare_album_for_import(2) self.matcher.matching = self.matcher.MISSING self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert len(self.lib.items()) == 1 @NEEDS_FFPROBE def test_empty_directory_warning(self, caplog): import_dir = self.temp_path / "empty" import_dir.mkdir() (import_dir / "non-audio").touch() self.setup_importer(import_dir=import_dir) with caplog.at_level("DEBUG"): self.importer.run() assert f"No files imported from {import_dir}" in caplog.messages @NEEDS_FFPROBE def test_empty_directory_singleton_warning(self, caplog): import_dir = self.temp_path / "empty" import_dir.mkdir() (import_dir / "non-audio").touch() self.setup_singleton_importer(import_dir=import_dir) with caplog.at_level("DEBUG"): self.importer.run() assert f"No files imported from {import_dir}" in caplog.messages def test_asis_no_data_source(self): assert self.lib.items().get() is None self.importer.add_choice(importer.Action.ASIS) self.importer.run() with pytest.raises(AttributeError): self.lib.items().get().data_source def test_set_fields(self): genres = ["\U0001f3b7 Jazz", "Rock"] collection = "To Listen" disc = 0 comments = "managed by beets" config["import"]["set_fields"] = { "genres": "; ".join(genres), "collection": collection, "disc": disc, "comments": comments, "album": "$album - formatted", } # As-is album import. assert self.lib.albums().get() is None self.importer.add_choice(importer.Action.ASIS) self.importer.run() for album in self.lib.albums(): assert album.genres == genres assert album.comments == comments for item in album.items(): assert item.get("genres", with_album=False) == genres assert item.get("collection", with_album=False) == collection assert item.get("comments", with_album=False) == comments assert ( item.get("album", with_album=False) == "Tag Album - formatted" ) assert item.disc == disc # Remove album from library to test again with APPLY choice. album.remove() # Autotagged. assert self.lib.albums().get() is None self.importer.clear_choices() self.importer.add_choice(importer.Action.APPLY) self.importer.run() for album in self.lib.albums(): assert album.genres == genres assert album.comments == comments for item in album.items(): assert item.get("genres", with_album=False) == genres assert item.get("collection", with_album=False) == collection assert item.get("comments", with_album=False) == comments assert ( item.get("album", with_album=False) == "Applied Album - formatted" ) assert item.disc == disc class ImportTracksTest(AutotagImportTestCase): """Test TRACKS and APPLY choice.""" def setUp(self): super().setUp() self.prepare_album_for_import(1) self.setup_importer() def test_apply_tracks_adds_singleton_track(self): self.importer.add_choice(importer.Action.TRACKS) self.importer.add_choice(importer.Action.APPLY) self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.items().get().title == "Applied Track 1" assert not self.lib.albums() def test_apply_tracks_adds_singleton_path(self): self.importer.add_choice(importer.Action.TRACKS) self.importer.add_choice(importer.Action.APPLY) self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert (self.lib_path / "singletons" / "Applied Track 1.mp3").exists() class ImportRescanTest(AutotagImportTestCase): """Test the Rescan directory action. Directory mutations must land when the first prompt is answered, not before ``run()`` -- an edit made earlier would be visible to the initial scan too and wouldn't exercise rescanning. Hence ``_run_with_cleanup_before_first_prompt``. """ def setUp(self): super().setUp() self.album_path = self.prepare_album_for_import(2)[0].parent self.setup_importer() def _run_with_cleanup_before_first_prompt(self, cleanup): """Run the importer, calling `cleanup` as the first prompt is answered -- the user editing the directory while paused there. """ original_choose_match = self.importer.choose_match state = {"done": False} def choose_match_and_cleanup(task): if not state["done"]: state["done"] = True cleanup() return original_choose_match(task) with patch.object( self.importer, "choose_match", side_effect=choose_match_and_cleanup ): self.importer.run() def test_rescan_picks_up_file_added_after_initial_scan(self): self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt( lambda: self.prepare_track_for_import(3, self.album_path) ) assert len(self.lib.items()) == 3 def test_rescan_picks_up_file_removed_after_initial_scan(self): self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt( lambda: (self.album_path / "track_2.mp3").unlink() ) assert len(self.lib.items()) == 1 def test_rescan_of_emptied_directory_imports_nothing(self): self.importer.add_choice(importer.Action.RESCAN) def cleanup(): for track in self.album_path.glob("*.mp3"): track.unlink() self._run_with_cleanup_before_first_prompt(cleanup) assert not self.lib.items() def test_rescan_with_only_unreadable_files_imports_nothing(self): self.importer.add_choice(importer.Action.RESCAN) def cleanup(): # Directory still has a music file by extension, but it can't # actually be read as an item. for track in self.album_path.glob("*.mp3"): track.unlink() (self.album_path / "track_1.mp3").write_bytes(b"not a real mp3") self._run_with_cleanup_before_first_prompt(cleanup) assert not self.lib.items() def test_rescan_with_multiple_subdirectories_finds_all_albums(self): self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self.importer.add_choice(importer.Action.APPLY) def cleanup(): # Simulate the user splitting the messy directory into two # proper album subdirectories. for track in self.album_path.glob("*.mp3"): track.unlink() self.prepare_album_for_import(2, album_path=self.album_path / "one") self.prepare_album_for_import(2, album_path=self.album_path / "two") self._run_with_cleanup_before_first_prompt(cleanup) assert len(self.lib.albums()) == 2 def test_rescan_of_multidisc_album_does_not_duplicate_tasks(self): """`task.paths` for a multi-disc album holds the album root and each disc subdirectory. Rescanning must not walk each independently -- that produced three tasks for a two-disc album. """ for track in self.album_path.glob("*.mp3"): track.unlink() self.prepare_album_for_import(1, album_path=self.album_path / "CD1") self.prepare_album_for_import(1, album_path=self.album_path / "CD2") self.setup_importer() self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt(lambda: None) assert len(self.lib.albums()) == 1 assert len(self.lib.items()) == 2 def test_rescan_preserves_multidisc_album_grouping(self): for track in self.album_path.glob("*.mp3"): track.unlink() self.prepare_album_for_import(1, album_path=self.album_path / "CD1") self.prepare_album_for_import(1, album_path=self.album_path / "CD2") self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt(lambda: None) assert len(self.lib.albums()) == 1 def test_rescan_preserves_flat_album_grouping(self): self.prepare_album_for_import(2, album_id=2) self.setup_importer(flat=True) self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt(lambda: None) assert len(self.lib.albums()) == 1 def test_rescan_of_single_file_import(self): """When the import path is a single file, rescanning must still find it (walking a file with `albums_in_dir` finds no music). """ track_path = self.prepare_album_for_import(1)[0] self.setup_importer(import_dir=track_path) self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt(lambda: None) assert len(self.lib.items()) == 1 def test_rescan_preserves_toppath_for_move_pruning(self): """Rescanned tasks must keep the original `toppath`. Pruning stops at `toppath`, so using the album directory itself would leave it behind, empty and un-pruned, after a move. """ self.setup_importer(move=True) self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt(lambda: None) assert not self.album_path.exists() def test_rescan_preserves_toppath_for_resume_state(self): """Rescanned tasks must keep the original `toppath`. Resume progress is keyed by `toppath`, so using the album directory itself would leave stale, never-reset progress behind. """ self.setup_importer(resume=True) self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt(lambda: None) # A completed import resets progress for its toppath at the end. assert not ImportState().tagprogress def test_rescan_of_sibling_multidisc_album_does_not_duplicate_tasks(self): """Sibling disc directories with no wrapping album directory can only be reconstructed by walking their shared parent, which also finds an unrelated sibling album. The rescan must regroup the discs into one task and leave the sibling alone. """ for track in self.album_path.glob("*.mp3"): track.unlink() self.album_path.rmdir() self.prepare_album_for_import( 1, album_path=self.import_path / "Set Disc 1" ) self.prepare_album_for_import( 1, album_path=self.import_path / "Set Disc 2" ) self.prepare_album_for_import( 1, album_path=self.import_path / "Other Album" ) self.setup_importer() # "Other Album" sorts first; leave it as-is, then no-op rescan # the two-disc album. self.importer.add_choice(importer.Action.ASIS) self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) self._run_with_cleanup_before_first_prompt(lambda: None) albums = self.lib.albums() assert len(albums) == 2 assert sorted(len(list(a.items())) for a in albums) == [1, 2] def test_rescan_of_normal_album_scans_only_its_own_directory(self): """A plain album under a larger toppath must be rediscovered from its own directory, not from `toppath` -- otherwise every rescan walks far more of the filesystem than necessary. """ self.importer.add_choice(importer.Action.RESCAN) self.importer.add_choice(importer.Action.APPLY) with patch( "beets.importer.stages.ImportTaskFactory", wraps=ImportTaskFactory ) as mock_factory: self._run_with_cleanup_before_first_prompt(lambda: None) scanned_toppaths = [ call.args[0] for call in mock_factory.call_args_list ] album_path_bytes = os.fsencode(str(self.album_path)) import_path_bytes = os.fsencode(str(self.import_path)) # Discovery is scoped to the album's own directory; `toppath` is # only touched by the initial scan and the task-emitting factory # (see `rescan_tasks`), never by a discovery walk. assert scanned_toppaths.count(album_path_bytes) == 1 assert scanned_toppaths.count(import_path_bytes) == 2 class TestRescanChoiceAvailability( TerminalImportMixin, PluginMixin, AutotagImportHelper ): """The "Rescan directory" choice must not be offered for tasks with no directory scope to rescan: "Group albums" output, toppath-less query tasks, singletons. """ @pytest.fixture(autouse=True) def setup_prompt_choice(self, io): self.prepare_album_for_import(2) self.setup_importer() self.input_options_patcher = patch( "beets.ui.input_options", side_effect=ui.input_options ) self.mock_input_options = self.input_options_patcher.start() yield self.input_options_patcher.stop() def test_rescan_choice_withheld_after_group_albums(self): self.importer.add_choice(importer.Action.ALBUMS) self.importer.add_choice(importer.Action.SKIP) self.importer.run() assert self.mock_input_options.call_count >= 2 first_opts, second_opts = ( call.args[0] for call in self.mock_input_options.call_args_list[:2] ) assert "Rescan directory" in first_opts assert "Rescan directory" not in second_opts def test_rescan_choice_forced_by_plugin_on_singleton_task_is_ignored(self): """A singleton task's `paths` is a single item file, not an album directory. A plugin forcing Rescan there must not wrap it back into a mismatched album-style task. """ class ForceRescanPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener("import_task_choice", self.force_rescan) def force_rescan(self, session, task): if not task.is_album: task.choice_flag = importer.Action.RESCAN self.register_plugin(ForceRescanPlugin) self.importer.add_choice(importer.Action.TRACKS) self.importer.run() assert not self.lib.items() def test_rescan_choice_forced_by_plugin_on_grouped_task_is_ignored(self): """A plugin forcing Rescan onto a Group-albums task must be ignored (falling back to Skip) rather than misbehave. """ class ForceRescanPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener("import_task_choice", self.force_rescan) def force_rescan(self, session, task): if task.is_grouped: task.choice_flag = importer.Action.RESCAN self.register_plugin(ForceRescanPlugin) self.importer.add_choice(importer.Action.ALBUMS) self.importer.run() assert not self.lib.albums() def test_rescan_choice_forced_by_plugin_on_toppathless_task_is_ignored( self, ): """`task.toppath` is None for library-query tasks (`beet import -L`). A plugin forcing Rescan there must not reach `rescan_tasks`'s `assert task.toppath is not None`. """ class ForceRescanPlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() self.register_listener("import_task_choice", self.force_rescan) def force_rescan(self, session, task): task.choice_flag = importer.Action.RESCAN # Get an album into the library first, via the normal importer. self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert len(self.lib.albums()) == 1 self.register_plugin(ForceRescanPlugin) query_session = TerminalImportSessionFixture( self.lib, loghandler=None, query="album:'Tag Album'", io=self.io, paths=None, ) query_session.default_choice = importer.Action.APPLY query_session.run() # Must not raise. assert len(self.lib.albums()) == 1 class ImportCompilationTest(AutotagImportTestCase): """Test ASIS import of a folder containing tracks with different artists.""" def setUp(self): super().setUp() self.prepare_album_for_import(3) self.setup_importer() def test_asis_homogenous_sets_albumartist(self): self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert self.lib.albums().get().albumartist == "Tag Artist" for item in self.lib.items(): assert item.albumartist == "Tag Artist" def test_asis_heterogenous_sets_various_albumartist(self): self.import_media[0].artist = "Other Artist" self.import_media[0].save() self.import_media[1].artist = "Another Artist" self.import_media[1].save() self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert self.lib.albums().get().albumartist == "Various Artists" for item in self.lib.items(): assert item.albumartist == "Various Artists" def test_asis_heterogenous_sets_compilation(self): self.import_media[0].artist = "Other Artist" self.import_media[0].save() self.import_media[1].artist = "Another Artist" self.import_media[1].save() self.importer.add_choice(importer.Action.ASIS) self.importer.run() for item in self.lib.items(): assert item.comp def test_asis_sets_majority_albumartist(self): self.import_media[0].artist = "Other Artist" self.import_media[0].save() self.import_media[1].artist = "Other Artist" self.import_media[1].save() self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert self.lib.albums().get().albumartist == "Other Artist" for item in self.lib.items(): assert item.albumartist == "Other Artist" def test_asis_albumartist_tag_sets_albumartist(self): self.import_media[0].artist = "Other Artist" self.import_media[1].artist = "Another Artist" for mediafile in self.import_media: mediafile.albumartist = "Album Artist" mediafile.mb_albumartistid = "Album Artist ID" mediafile.save() self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert self.lib.albums().get().albumartist == "Album Artist" assert self.lib.albums().get().mb_albumartistid == "Album Artist ID" for item in self.lib.items(): assert item.albumartist == "Album Artist" assert item.mb_albumartistid == "Album Artist ID" def test_asis_albumartists_tag_sets_multi_albumartists(self): self.import_media[0].artist = "Other Artist" self.import_media[0].artists = ["Other Artist", "Other Artist 2"] self.import_media[1].artist = "Another Artist" self.import_media[1].artists = ["Another Artist", "Another Artist 2"] for mediafile in self.import_media: mediafile.albumartist = "Album Artist" mediafile.albumartists = ["Album Artist 1", "Album Artist 2"] mediafile.mb_albumartistid = "Album Artist ID" mediafile.save() self.importer.add_choice(importer.Action.ASIS) self.importer.run() assert self.lib.albums().get().albumartist == "Album Artist" assert self.lib.albums().get().albumartists == [ "Album Artist 1", "Album Artist 2", ] assert self.lib.albums().get().mb_albumartistid == "Album Artist ID" # Make sure both custom media items get tested asserted_multi_artists_0 = False asserted_multi_artists_1 = False for item in self.lib.items(): assert item.albumartist == "Album Artist" assert item.albumartists == ["Album Artist 1", "Album Artist 2"] assert item.mb_albumartistid == "Album Artist ID" if item.artist == "Other Artist": asserted_multi_artists_0 = True assert item.artists == ["Other Artist", "Other Artist 2"] if item.artist == "Another Artist": asserted_multi_artists_1 = True assert item.artists == ["Another Artist", "Another Artist 2"] assert asserted_multi_artists_0 assert asserted_multi_artists_1 class ImportExistingTest(PathsMixin, AutotagImportTestCase): """Test importing files that are already in the library directory.""" def setUp(self): super().setUp() self.prepare_album_for_import(1) self.reimporter = self.setup_importer(import_dir=self.lib_path) self.importer = self.setup_importer() def tearDown(self): super().tearDown() self.matcher.restore() @cached_property def applied_track_path(self) -> Path: return Path(str(self.track_lib_path).replace("Tag", "Applied")) def test_does_not_duplicate_item_nor_album(self): self.importer.run() assert len(self.lib.items()) == 1 assert len(self.lib.albums()) == 1 self.reimporter.add_choice(importer.Action.APPLY) self.reimporter.run() assert len(self.lib.items()) == 1 assert len(self.lib.albums()) == 1 def test_does_not_duplicate_singleton_track(self): self.importer.add_choice(importer.Action.TRACKS) self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert len(self.lib.items()) == 1 self.reimporter.add_choice(importer.Action.TRACKS) self.reimporter.add_choice(importer.Action.APPLY) self.reimporter.run() assert len(self.lib.items()) == 1 def test_asis_updates_metadata_and_moves_file(self): self.importer.run() medium = MediaFile(self.lib.items().get().path) medium.title = "New Title" medium.save() self.reimporter.add_choice(importer.Action.ASIS) self.reimporter.run() assert self.lib.items().get().title == "New Title" assert not self.applied_track_path.exists() assert self.applied_track_path.with_name("New Title.mp3").exists() def test_asis_updated_without_copy_does_not_move_file(self): self.importer.run() medium = MediaFile(self.lib.items().get().path) medium.title = "New Title" medium.save() config["import"]["copy"] = False self.reimporter.add_choice(importer.Action.ASIS) self.reimporter.run() assert self.applied_track_path.exists() assert not self.applied_track_path.with_name("New Title.mp3").exists() def test_outside_file_is_copied(self): config["import"]["copy"] = False self.importer.run() assert self.lib.items().get().filepath == self.track_import_path self.reimporter = self.setup_importer() self.reimporter.add_choice(importer.Action.APPLY) self.reimporter.run() assert self.applied_track_path.exists() assert self.lib.items().get().filepath == self.applied_track_path class GroupAlbumsImportTest(AutotagImportTestCase): matching = AutotagStub.NONE def setUp(self): super().setUp() self.prepare_album_for_import(3) self.setup_importer() # Split tracks into two albums and use both as-is self.importer.add_choice(importer.Action.ALBUMS) self.importer.add_choice(importer.Action.ASIS) self.importer.add_choice(importer.Action.ASIS) def test_add_album_for_different_artist_and_different_album(self): self.import_media[0].artist = "Artist B" self.import_media[0].album = "Album B" self.import_media[0].save() self.importer.run() albums = {album.album for album in self.lib.albums()} assert albums == {"Album B", "Tag Album"} def test_add_album_for_different_artist_and_same_albumartist(self): self.import_media[0].artist = "Artist B" self.import_media[0].albumartist = "Album Artist" self.import_media[0].save() self.import_media[1].artist = "Artist C" self.import_media[1].albumartist = "Album Artist" self.import_media[1].save() self.importer.run() artists = {album.albumartist for album in self.lib.albums()} assert artists == {"Album Artist", "Tag Artist"} def test_add_album_for_same_artist_and_different_album(self): self.import_media[0].album = "Album B" self.import_media[0].save() self.importer.run() albums = {album.album for album in self.lib.albums()} assert albums == {"Album B", "Tag Album"} def test_add_album_for_same_album_and_different_artist(self): self.import_media[0].artist = "Artist B" self.import_media[0].save() self.importer.run() artists = {album.albumartist for album in self.lib.albums()} assert artists == {"Artist B", "Tag Artist"} def test_incremental(self): config["import"]["incremental"] = True self.import_media[0].album = "Album B" self.import_media[0].save() self.importer.run() albums = {album.album for album in self.lib.albums()} assert albums == {"Album B", "Tag Album"} class GlobalGroupAlbumsImportTest(GroupAlbumsImportTest): def setUp(self): super().setUp() self.importer.clear_choices() self.importer.default_choice = importer.Action.ASIS config["import"]["group_albums"] = True class ChooseCandidateTest(AutotagImportTestCase): matching = AutotagStub.BAD def setUp(self): super().setUp() self.prepare_album_for_import(1) self.setup_importer() def test_choose_first_candidate(self): self.importer.add_choice(1) self.importer.run() assert self.lib.albums().get().album == "Applied Album M" def test_choose_second_candidate(self): self.importer.add_choice(2) self.importer.run() assert self.lib.albums().get().album == "Applied Album MM" class InferAlbumDataTest(unittest.TestCase): def setUp(self): super().setUp() i1 = _common.item() i2 = _common.item() i3 = _common.item() i1.title = "first item" i2.title = "second item" i3.title = "third item" i1.comp = i2.comp = i3.comp = False i1.albumartist = i2.albumartist = i3.albumartist = "" i1.mb_albumartistid = i2.mb_albumartistid = i3.mb_albumartistid = "" self.items = [i1, i2, i3] self.task = importer.ImportTask( paths=["a path"], toppath="top path", items=self.items ) def test_asis_homogenous_single_artist(self): self.task.set_choice(importer.Action.ASIS) self.task.align_album_level_fields() assert not self.items[0].comp assert self.items[0].albumartist == self.items[2].artist def test_asis_heterogenous_va(self): self.items[0].artist = "another artist" self.items[1].artist = "some other artist" self.task.set_choice(importer.Action.ASIS) self.task.align_album_level_fields() assert self.items[0].comp assert self.items[0].albumartist == "Various Artists" def test_asis_comp_applied_to_all_items(self): self.items[0].artist = "another artist" self.items[1].artist = "some other artist" self.task.set_choice(importer.Action.ASIS) self.task.align_album_level_fields() for item in self.items: assert item.comp assert item.albumartist == "Various Artists" def test_asis_majority_artist_single_artist(self): self.items[0].artist = "another artist" self.task.set_choice(importer.Action.ASIS) self.task.align_album_level_fields() assert not self.items[0].comp assert self.items[0].albumartist == self.items[2].artist def test_asis_track_albumartist_override(self): self.items[0].artist = "another artist" self.items[1].artist = "some other artist" for item in self.items: item.albumartist = "some album artist" item.mb_albumartistid = "some album artist id" self.task.set_choice(importer.Action.ASIS) self.task.align_album_level_fields() assert self.items[0].albumartist == "some album artist" assert self.items[0].mb_albumartistid == "some album artist id" def test_apply_gets_artist_and_id(self): self.task.set_choice(AlbumMatch(Distance(), None, {})) # APPLY self.task.align_album_level_fields() assert self.items[0].albumartist == self.items[0].artist assert self.items[0].mb_albumartistid == self.items[0].mb_artistid def test_apply_lets_album_values_override(self): for item in self.items: item.albumartist = "some album artist" item.mb_albumartistid = "some album artist id" self.task.set_choice(AlbumMatch(Distance(), None, {})) # APPLY self.task.align_album_level_fields() assert self.items[0].albumartist == "some album artist" assert self.items[0].mb_albumartistid == "some album artist id" def test_small_single_artist_album(self): self.items = [self.items[0]] self.task.items = self.items self.task.set_choice(importer.Action.ASIS) self.task.align_album_level_fields() assert not self.items[0].comp def album_candidates_mock(*args, **kwargs): """Create an AlbumInfo object for testing.""" yield AlbumInfo( artist="artist", album="album", tracks=[TrackInfo(title="new title", track_id="trackid", index=0)], album_id="albumid", artist_id="artistid", flex="flex", ) @patch( "beets.metadata_plugins.candidates", Mock(side_effect=album_candidates_mock) ) class TestImportDuplicateAlbum(PluginMixin, ImportHelper): plugin = "musicbrainz" def setup_beets(self): super().setup_beets() # Original album self.add_album_fixture(albumartist="artist", album="album") # Create import session self.prepare_album_for_import(1) self.importer = self.setup_importer( duplicate_keys={"album": "albumartist album"} ) def test_remove_duplicate_album(self): item = self.lib.items().get() assert item.title == "t\xeftle 0" assert item.filepath.exists() self.config["import"]["duplicate_action"] = "remove" self.importer.run() assert not item.filepath.exists() assert len(self.lib.albums()) == 1 assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.title == "new title" def test_remove_duplicate_album_deletes_art(self): album = self.lib.albums().get() art_source = _common.RSRC / "abbey.jpg" album.set_art(art_source) album.store() old_artpath = album.art_filepath assert old_artpath.exists() self.config["import"]["duplicate_action"] = "remove" self.importer.run() assert not old_artpath.exists() assert len(self.lib.albums()) == 1 def test_no_autotag_removes_duplicate_album(self): config["import"]["autotag"] = False album = self.lib.albums().get() item = self.lib.items().get() assert item.title == "t\xeftle 0" assert item.filepath.exists() # Imported item has the same albumartist and album as the one in the # library album. We use album metadata (not item metadata) since # duplicate detection uses album-level fields. import_file = os.path.join( self.importer.paths[0], b"album", b"track_1.mp3" ) import_file = MediaFile(import_file) import_file.artist = album.albumartist import_file.albumartist = album.albumartist import_file.album = album.album import_file.title = "new title" import_file.save() self.config["import"]["duplicate_action"] = "remove" self.importer.run() # Old duplicate should be removed, new one imported assert len(self.lib.albums()) == 1 assert len(self.lib.items()) == 1 # The new item should be in the library assert self.lib.items().get().title == "new title" def test_keep_duplicate_album(self): self.config["import"]["duplicate_action"] = "keep" self.importer.run() assert len(self.lib.albums()) == 2 assert len(self.lib.items()) == 2 def test_skip_duplicate_album(self): item = self.lib.items().get() assert item.title == "t\xeftle 0" self.config["import"]["duplicate_action"] = "skip" self.importer.run() assert len(self.lib.albums()) == 1 assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.title == "t\xeftle 0" def test_merge_duplicate_album(self): self.config["import"]["duplicate_action"] = "merge" self.importer.run() assert len(self.lib.albums()) == 1 def test_twice_in_import_dir(self): pytest.skip(reason="write me") def test_keep_when_extra_key_is_different(self): config["import"]["duplicate_keys"]["album"] = "albumartist album flex" item = self.lib.items().get() import_file = MediaFile( os.path.join(self.importer.paths[0], b"album", b"track_1.mp3") ) import_file.artist = item["artist"] import_file.albumartist = item["artist"] import_file.album = item["album"] import_file.title = item["title"] import_file.flex = "different" self.config["import"]["duplicate_action"] = "skip" self.importer.run() assert len(self.lib.albums()) == 2 assert len(self.lib.items()) == 2 def add_album_fixture(self, **kwargs): # TODO move this into upstream album = super().add_album_fixture() album.update(kwargs) album.store() return album @patch( "beets.metadata_plugins.candidates", Mock(side_effect=album_candidates_mock) ) class TestImportDuplicateAlbumThreaded(PluginMixin, ImportHelper): """Regression test for #6601: threaded merge must propagate context vars.""" plugin = "musicbrainz" # Each thread gets its own connection; :memory: would give each thread an # empty DB, so we need a real file that all threads share. db_on_disk = True def setup_beets(self): super().setup_beets() self.add_album_fixture(albumartist="artist", album="album") self.prepare_album_for_import(1) self.importer = self.setup_importer( duplicate_keys={"album": "albumartist album"} ) def add_album_fixture(self, **kwargs): album = super().add_album_fixture() album.update(kwargs) album.store() return album def test_merge_duplicate_album_threaded(self): self.config["threaded"] = True self.config["import"]["duplicate_action"] = "merge" self.importer.run() assert len(self.lib.albums()) == 1 for item in self.lib.items(): assert item.filepath.exists(), f"item path not found: {item.path}" # Without the fix, lost context vars cause relative paths to stay # unresolved, so items land in different (duplicate) directories. album_dirs = {item.filepath.parent for item in self.lib.items()} assert len(album_dirs) == 1, ( f"expected single album dir, got {album_dirs}" ) def item_candidates_mock(*args, **kwargs): yield TrackInfo( artist="artist", title="title", track_id="new trackid", index=0 ) @patch( "beets.metadata_plugins.item_candidates", Mock(side_effect=item_candidates_mock), ) class TestImportDuplicateSingleton(ImportHelper): def setup_beets(self): super().setup_beets() # Original file in library self.add_item_fixture( artist="artist", title="title", mb_trackid="old trackid" ) # Import session self.prepare_album_for_import(1) self.importer = self.setup_singleton_importer( duplicate_keys={"album": "artist title"} ) def test_remove_duplicate(self): item = self.lib.items().get() assert item.mb_trackid == "old trackid" assert item.filepath.exists() self.config["import"]["duplicate_action"] = "remove" self.importer.run() assert not item.filepath.exists() assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.mb_trackid == "new trackid" def test_keep_duplicate(self): assert len(self.lib.items()) == 1 self.config["import"]["duplicate_action"] = "keep" self.importer.run() assert len(self.lib.items()) == 2 def test_skip_duplicate(self): item = self.lib.items().get() assert item.mb_trackid == "old trackid" self.config["import"]["duplicate_action"] = "skip" self.importer.run() assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.mb_trackid == "old trackid" def test_keep_when_extra_key_is_different(self): config["import"]["duplicate_keys"]["item"] = "artist title flex" item = self.lib.items().get() item.flex = "different" item.store() assert len(self.lib.items()) == 1 self.config["import"]["duplicate_action"] = "skip" self.importer.run() assert len(self.lib.items()) == 2 def test_no_autotag_removes_duplicate_singleton(self): config["import"]["autotag"] = False item = self.lib.items().get() assert item.mb_trackid == "old trackid" assert item.filepath.exists() # Imported item has the same artist and title as the one in the # library. We use item metadata since duplicate detection uses # item-level fields for singletons. import_file = os.path.join( self.importer.paths[0], b"album", b"track_1.mp3" ) import_file = MediaFile(import_file) import_file.artist = item.artist import_file.title = item.title import_file.mb_trackid = "new trackid" import_file.save() self.config["import"]["duplicate_action"] = "remove" self.importer.run() # Old duplicate should be removed, new one imported assert len(self.lib.items()) == 1 # The new item should be in the library assert self.lib.items().get().mb_trackid == "new trackid" def test_twice_in_import_dir(self): pytest.skip(reason="write me") def add_item_fixture(self, **kwargs): # Move this to TestHelper item = self.add_item_fixtures()[0] item.update(kwargs) item.store() return item @contextmanager def bitrate_overrides(bitrates_by_title): """Force specific per-title bitrates on newly-read import items. The test mp3 fixtures all share one real bitrate, so this patches `ImportTaskFactory.read_item` to simulate different-quality encodes without needing distinct binary fixtures. """ original = ImportTaskFactory.read_item def patched(self, path): item = original(self, path) if item is not None and item.title in bitrates_by_title: item.bitrate = bitrates_by_title[item.title] return item with patch.object(ImportTaskFactory, "read_item", patched): yield DUP_KEYS = ["artist", "title"] def test_duplicate_action_prompt_options(): assert importer.DuplicateAction.strict_options() == [ "Skip new", "Merge all", "Remove old", "Keep all", "Upgrade", ] class ResolveUpgradeTest(unittest.TestCase): """Unit tests for `resolve_upgrade`, the per-track decision algorithm behind `duplicate_action: upgrade`. """ def _item(self, artist="artist", title="title", bitrate=128000): return Item(artist=artist, title=title, bitrate=bitrate) def test_matched_better_bitrate_replaces_old(self): old = self._item(bitrate=128000) new = self._item(bitrate=320000) kept, superseded = resolve_upgrade([new], [old], DUP_KEYS) assert kept == [new] assert superseded == [old] def test_matched_worse_bitrate_keeps_old(self): old = self._item(bitrate=320000) new = self._item(bitrate=128000) kept, superseded = resolve_upgrade([new], [old], DUP_KEYS) assert kept == [] assert superseded == [] def test_matched_equal_bitrate_keeps_old(self): old = self._item(bitrate=128000) new = self._item(bitrate=128000) kept, superseded = resolve_upgrade([new], [old], DUP_KEYS) assert kept == [] assert superseded == [] def test_unmatched_new_item_always_kept(self): old = self._item(title="old title", bitrate=320000) new = self._item(title="new title", bitrate=64000) kept, superseded = resolve_upgrade([new], [old], DUP_KEYS) assert kept == [new] assert superseded == [] def test_mixed_batch(self): old_a = self._item(title="A", bitrate=128000) old_d = self._item(title="D", bitrate=128000) new_a = self._item(title="A", bitrate=320000) # upgrade, wins new_b = self._item(title="B", bitrate=64000) # no old counterpart kept, superseded = resolve_upgrade( [new_a, new_b], [old_a, old_d], DUP_KEYS ) assert kept == [new_a, new_b] assert superseded == [old_a] def test_duplicate_keys_all_old_superseded_when_new_is_best(self): """When multiple old items share a key and the new item beats all of them, every old copy should be superseded.""" old_a = self._item(bitrate=128000) old_b = self._item(bitrate=96000) new = self._item(bitrate=320000) kept, superseded = resolve_upgrade([new], [old_a, old_b], DUP_KEYS) assert kept == [new] assert sorted(superseded, key=lambda i: i.bitrate) == [old_b, old_a] def test_duplicate_keys_rejected_when_new_is_not_best(self): """When an old item with the same key has bitrate >= the new item, the new item should be dropped to prevent a downgrade.""" old_a = self._item(bitrate=128000) old_b = self._item(bitrate=320000) new = self._item(bitrate=256000) kept, superseded = resolve_upgrade([new], [old_a, old_b], DUP_KEYS) assert kept == [] assert superseded == [] class ResolveUpgradeTargetTest(TestHelper): """Unit tests for `resolve_upgrade_target`: when `found_duplicates` implicates more than one distinct old album, only the one it overlaps with the most should be treated as the upgrade target, and every other candidate album must be left untouched. Regression coverage for https://github.com/beetbox/beets/pull/6842#discussion_r3635292074: comparing new tracks against the *best* old candidate pooled across every duplicate album could silently attribute a supersession to the wrong album (or decline an upgrade that only looked bad because of an unrelated album's better copy). """ def setUp(self): self.setup_beets() def tearDown(self): self.teardown_beets() def _item(self, title, bitrate): return self.add_item_fixture( artist="Tag Artist", albumartist="Tag Artist", album="Tag Album", title=title, bitrate=bitrate, ) def test_targets_album_with_most_overlap(self): # Album A: a high-bitrate track (never worth upgrading) plus a # low-bitrate one; Album B: both tracks low-bitrate. a_t1 = self._item("T1", 1400000) a_t2 = self._item("T2", 320000) album_a = self.lib.add_album([a_t1, a_t2]) b_t1 = self._item("T1", 320000) b_t2 = self._item("T2", 320000) album_b = self.lib.add_album([b_t1, b_t2]) new_t1 = Item(artist="Tag Artist", title="T1", bitrate=900000) new_t2 = Item(artist="Tag Artist", title="T2", bitrate=900000) kept, superseded, old_album_ids = resolve_upgrade_target( [new_t1, new_t2], [album_a, album_b], DUP_KEYS ) # Album B overlaps on both tracks and is chosen as the sole # target; Album A (and its higher-bitrate T1) is never touched. assert old_album_ids == [album_b.id] assert kept == [new_t1, new_t2] assert superseded == [b_t1, b_t2] assert a_t1 not in superseded assert a_t2 not in superseded def test_single_duplicate_album_behaves_as_before(self): old_t1 = self._item("T1", 128000) album = self.lib.add_album([old_t1]) new_t1 = Item(artist="Tag Artist", title="T1", bitrate=320000) kept, superseded, old_album_ids = resolve_upgrade_target( [new_t1], [album], DUP_KEYS ) assert kept == [new_t1] assert superseded == [old_t1] assert old_album_ids == [album.id] @patch( "beets.metadata_plugins.candidates", Mock(side_effect=album_candidates_mock) ) class TestImportDuplicateAlbumUpgrade(PluginMixin, ImportHelper): """Album-level `duplicate_action: upgrade`, full track-for-track overlap (the whole album is either replaced or left alone). """ plugin = "musicbrainz" def setup_beets(self): super().setup_beets() # Existing album with one track, matching what the incoming # import will be tagged as (see `album_candidates_mock`). self.old_item = self.add_item_fixture( artist="artist", albumartist="artist", album="album", title="new title", mb_trackid="old trackid", bitrate=128000, ) self.old_album = self.lib.add_album([self.old_item]) self.prepare_album_for_import(1) self.importer = self.setup_importer( duplicate_keys={"album": "albumartist album"} ) self.config["import"]["duplicate_action"] = "upgrade" def test_upgrade_replaces_lower_quality_duplicate(self): with bitrate_overrides({"Tag Track 1": 320000}): self.importer.run() assert len(self.lib.albums()) == 1 assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.title == "new title" assert item.bitrate == 320000 assert self.lib.get_item(self.old_item.id) is None def test_upgrade_skips_lower_quality_new_copy(self): with bitrate_overrides({"Tag Track 1": 64000}): self.importer.run() assert len(self.lib.albums()) == 1 assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.id == self.old_item.id assert item.bitrate == 128000 assert self.old_item.filepath.exists() class TestImportDuplicateAlbumUpgradeMixed(ImportHelper): """Album-level `duplicate_action: upgrade` where the new import mixes a genuine quality upgrade of one existing track with tracks that have no old counterpart at all (e.g. filling in a previously-incomplete album). The surviving old tracks and the kept new tracks must end up in the same album. """ def setup_beets(self): super().setup_beets() self.old_track1 = self.add_item_fixture( artist="Tag Artist", albumartist="Tag Artist", album="Tag Album", title="Tag Track 1", bitrate=64000, ) self.old_track4 = self.add_item_fixture( artist="Tag Artist", albumartist="Tag Artist", album="Tag Album", title="Tag Track 4", bitrate=64000, ) self.old_album = self.lib.add_album([self.old_track1, self.old_track4]) self.prepare_album_for_import(3) # Tag Track 1, 2, 3 self.importer = self.setup_importer(autotag=False) self.config["import"]["duplicate_action"] = "upgrade" def test_upgrade_and_new_tracks_join_existing_album(self): with bitrate_overrides({"Tag Track 1": 320000}): self.importer.run() assert len(self.lib.albums()) == 1 items = list(self.lib.items()) assert len(items) == 4 by_title = {i.title: i for i in items} assert by_title["Tag Track 1"].bitrate == 320000 assert by_title["Tag Track 4"].bitrate == 64000 assert "Tag Track 2" in by_title assert "Tag Track 3" in by_title assert all(i.album_id == self.old_album.id for i in items) assert self.lib.get_item(self.old_track1.id) is None # Untouched old track keeps its original row and file. assert by_title["Tag Track 4"].id == self.old_track4.id assert self.old_track4.filepath.exists() def test_rejected_upgrade_still_adds_new_tracks(self): with bitrate_overrides({"Tag Track 1": 40000}): self.importer.run() assert len(self.lib.albums()) == 1 items = list(self.lib.items()) assert len(items) == 4 by_title = {i.title: i for i in items} assert by_title["Tag Track 1"].id == self.old_track1.id assert by_title["Tag Track 1"].bitrate == 64000 assert "Tag Track 2" in by_title assert "Tag Track 3" in by_title assert all(i.album_id == self.old_album.id for i in items) assert self.old_track1.filepath.exists() @patch( "beets.metadata_plugins.item_candidates", Mock(side_effect=item_candidates_mock), ) class TestImportDuplicateSingletonUpgrade(ImportHelper): def setup_beets(self): super().setup_beets() self.old_item = self.add_item_fixture( artist="artist", title="title", mb_trackid="old trackid", bitrate=128000, ) self.prepare_album_for_import(1) self.importer = self.setup_singleton_importer() self.config["import"]["duplicate_action"] = "upgrade" def test_upgrade_replaces_lower_quality_duplicate(self): with bitrate_overrides({"Tag Track 1": 320000}): self.importer.run() assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.mb_trackid == "new trackid" assert item.bitrate == 320000 assert self.lib.get_item(self.old_item.id) is None def test_upgrade_skips_lower_quality_new_copy(self): with bitrate_overrides({"Tag Track 1": 64000}): self.importer.run() assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.id == self.old_item.id assert item.mb_trackid == "old trackid" assert self.old_item.filepath.exists() class TagLogTest(TestHelper): def test_tag_log_line(self): sio = StringIO() handler = logging.StreamHandler(sio) session = _common.import_session(self.lib, loghandler=handler) session.tag_log("status", "path") assert "status path" in sio.getvalue() def test_tag_log_unicode(self): sio = StringIO() handler = logging.StreamHandler(sio) session = _common.import_session(self.lib, loghandler=handler) session.tag_log("status", "caf\xe9") # send unicode assert "status caf\xe9" in sio.getvalue() class TestResumeImport(ImportHelper): @patch("beets.plugins.send") def test_resume_album(self, plugins_send): self.prepare_albums_for_import(2) self.importer = self.setup_importer(autotag=False, resume=True) # Aborts import after one album. This also ensures that we skip # the first album in the second try. def raise_exception(event, **kwargs): if event == "album_imported": raise importer.ImportAbortError plugins_send.side_effect = raise_exception self.importer.run() assert len(self.lib.albums()) == 1 assert self.lib.albums("album:'Album 1'").get() is not None self.importer.run() assert len(self.lib.albums()) == 2 assert self.lib.albums("album:'Album 2'").get() is not None @patch("beets.plugins.send") def test_resume_singleton(self, plugins_send): self.prepare_album_for_import(2) self.importer = self.setup_singleton_importer( autotag=False, resume=True ) # Aborts import after one track. This also ensures that we skip # the first album in the second try. def raise_exception(event, **kwargs): if event == "item_imported": raise importer.ImportAbortError plugins_send.side_effect = raise_exception self.importer.run() assert len(self.lib.items()) == 1 assert self.lib.items("title:'Track 1'").get() is not None self.importer.run() assert len(self.lib.items()) == 2 assert self.lib.items("title:'Track 1'").get() is not None class TestIncrementalImport(AsIsImporterMixin, ImportHelper): def test_incremental_album(self): importer = self.run_asis_importer(incremental=True) # Change album name so the original file would be imported again # if incremental was off. album = self.lib.albums().get() album["album"] = "edited album" album.store() importer.run() assert len(self.lib.albums()) == 2 def test_incremental_item(self): importer = self.run_asis_importer(incremental=True, singletons=True) # Change track name so the original file would be imported again # if incremental was off. item = self.lib.items().get() item["artist"] = "edited artist" item.store() importer.run() assert len(self.lib.items()) == 2 def test_invalid_state_file(self): self.config["statefile"].as_path().write_bytes(b"000") self.run_asis_importer(incremental=True) assert len(self.lib.albums()) == 1 def _mkmp3(path): shutil.copyfile(_common.RSRC / "min.mp3", path) class AlbumsInDirTest(BeetsTestCase): def setUp(self): super().setUp() # create a directory structure for testing base = (self.temp_path / "tempdir").resolve() base.mkdir() album1_dir = base / "album1" album2_dir = base / "album2" album3_dir = base / "more" / "album3" album4_dir = base / "more" / "album4" album1_dir.mkdir() album2_dir.mkdir() album3_dir.mkdir(parents=True) album4_dir.mkdir(parents=True) _mkmp3(album1_dir / "album1song1.mp3") _mkmp3(album1_dir / "album1song2.mp3") _mkmp3(album2_dir / "album2song.mp3") _mkmp3(album3_dir / "album3song.mp3") _mkmp3(album4_dir / "album4song.mp3") self.base = str(base) def test_finds_all_albums(self): albums = list(albums_in_dir(self.base)) assert len(albums) == 4 def test_separates_contents(self): found = [] for _, album in albums_in_dir(self.base): found.append(re.search(r"album(.)song", album[0]).group(1)) assert "1" in found assert "2" in found assert "3" in found assert "4" in found def test_finds_multiple_songs(self): for _, album in albums_in_dir(self.base): n = re.search(r"album(.)song", album[0]).group(1) if n == "1": assert len(album) == 2 else: assert len(album) == 1 class MultiDiscAlbumsInDirTest(BeetsTestCase): def create_music(self, files=True, ascii_=True): """Create some music in multiple album directories. `files` indicates whether to create the files (otherwise, only directories are made). `ascii_` indicates ACII-only filenames; otherwise, we use Unicode names. """ self.base = (self.temp_path / "tempdir").resolve() self.base.mkdir() name = "CAT" if ascii_ else "C\xc1T" name_alt_case = "CAt" if ascii_ else "C\xc1t" self.dirs = [ # Nested album, multiple subdirs. # Also, false positive marker in root dir, and subtitle for disc 3. self.base / "ABCD1234", self.base / "ABCD1234" / "cd 1", self.base / "ABCD1234" / "cd 3 - bonus", # Nested album, single subdir. # Also, punctuation between marker and disc number. self.base / "album", self.base / "album" / "cd _ 1", # Flattened album, case typo. # Also, false positive marker in parent dir. self.base / "artist [CD5]", self.base / "artist [CD5]" / f"{name} disc 1", self.base / "artist [CD5]" / f"{name_alt_case} disc 2", # Single disc album, sorted between CAT discs. self.base / "artist [CD5]" / f"{name} S", ] deep_dirs = [*self.dirs[:3], self.dirs[4], *self.dirs[6:]] self.files = [d / f"song{i}.mp3" for i, d in enumerate(deep_dirs)] if not ascii_: self.dirs = [self._normalize_path(p) for p in self.dirs] self.files = [self._normalize_path(p) for p in self.files] for path in self.dirs: path.mkdir() if files: for path in self.files: _mkmp3(path) self.dirs = list(map(str, self.dirs)) self.files = list(map(str, self.files)) self.base = str(self.base) def _normalize_path(self, path: Path) -> Path: """Normalize a path's Unicode combining form according to the platform. """ norm_form: Literal["NFD", "NFC"] = ( "NFD" if sys.platform == "darwin" else "NFC" ) return Path(unicodedata.normalize(norm_form, str(path))) def test_coalesce_nested_album_multiple_subdirs(self): self.create_music() albums = list(albums_in_dir(self.base)) assert len(albums) == 4 root, items = albums[0] assert root == self.dirs[0:3] assert len(items) == 3 def test_coalesce_nested_album_single_subdir(self): self.create_music() albums = list(albums_in_dir(self.base)) root, items = albums[1] assert root == self.dirs[3:5] assert len(items) == 1 def test_coalesce_flattened_album_case_typo(self): self.create_music() albums = list(albums_in_dir(self.base)) root, items = albums[2] assert root == self.dirs[6:8] assert len(items) == 2 def test_single_disc_album(self): self.create_music() albums = list(albums_in_dir(self.base)) root, items = albums[3] assert root == self.dirs[8:] assert len(items) == 1 def test_do_not_yield_empty_album(self): self.create_music(files=False) albums = list(albums_in_dir(self.base)) assert len(albums) == 0 def test_single_disc_unicode(self): self.create_music(ascii_=False) albums = list(albums_in_dir(self.base)) root, items = albums[3] assert root == self.dirs[8:] assert len(items) == 1 def test_coalesce_multiple_unicode(self): self.create_music(ascii_=False) albums = list(albums_in_dir(self.base)) assert len(albums) == 4 root, items = albums[0] assert root == self.dirs[0:3] assert len(items) == 3 def test_coalesce_markers(self): for i, (marker, suffix1, suffix2) in enumerate( [ ("Disc", " 1", " 02"), # titlecase, space-separated ("disk 757", " 1", " 02"), # lowercase, numerical suffix ("CD", "01", "02"), # uppercase, no space (e.g. CD01) ("disc", "_1", "_2"), # underscore separator (e.g. disc_1) ("cAsSeTtE", " 1", " 02"), # mixed case ("Digital Media", " 1", " 02"), # multiple spaces ("vinyl", " 1", " 02"), # lowercase ("12 vinyl", " 1", " 02"), # common prefix ] ): with self.subTest(marker=marker, suffix1=suffix1, suffix2=suffix2): base = self.temp_path / f"marker_{i}" base.mkdir() album_dir = base / "Album Name" album_dir.mkdir() discs = [] for suffix in (suffix1, suffix2): disc = album_dir / f"{marker}{suffix}" disc.mkdir() _mkmp3(disc / "song.mp3") discs.append(str(disc)) albums = list(albums_in_dir(str(base))) assert len(albums) == 1 root, items = albums[0] for disc in discs: assert disc in root assert len(items) == 2 def test_no_coalesce_mismatched_prefixes(self): # "CD 02" and "Enhanced CD 01" share the "cd" marker but have # different prefixes, so they should not be collapsed. base = self.temp_path / "mismatched" base.mkdir() album_dir = base / "Album Name" album_dir.mkdir() for subdir in ("CD 02", "Enhanced CD 01"): d = album_dir / subdir d.mkdir() _mkmp3(d / "song.mp3") albums = list(albums_in_dir(str(base))) assert len(albums) == 2 class ReimportTest(AutotagImportTestCase): """Test "re-imports", in which the autotagging machinery is used for music that's already in the library. This works by importing new database entries for the same files and replacing the old data with the new data. We also copy over flexible attributes and the added date. """ matching = AutotagStub.GOOD def setUp(self): super().setUp() # The existing album. album = self.add_album_fixture() album.added = 4242.0 album.foo = "bar" # Some flexible attribute. album.data_source = "original_source" album.store() item = album.items().get() item.baz = "qux" item.added = 4747.0 item.store() def _setup_session(self, singletons=False): self.setup_importer(import_dir=self.lib_path, singletons=singletons) self.importer.add_choice(importer.Action.APPLY) def _album(self): return self.lib.albums().get() def _item(self): return self.lib.items().get() def test_reimported_album_gets_new_metadata(self): self._setup_session() assert self._album().album == "\xe4lbum" self.importer.run() assert self._album().album == "the album" def test_reimported_album_preserves_flexattr(self): self._setup_session() self.importer.run() assert self._album().foo == "bar" def test_reimported_album_preserves_added(self): self._setup_session() self.importer.run() assert self._album().added == 4242.0 def test_reimported_album_preserves_item_flexattr(self): self._setup_session() self.importer.run() assert self._item().baz == "qux" def test_reimported_album_preserves_item_added(self): self._setup_session() self.importer.run() assert self._item().added == 4747.0 def test_reimported_item_gets_new_metadata(self): self._setup_session(True) assert self._item().title == "t\xeftle 0" self.importer.run() assert self._item().title == "full" def test_reimported_item_preserves_flexattr(self): self._setup_session(True) self.importer.run() assert self._item().baz == "qux" def test_reimported_item_preserves_added(self): self._setup_session(True) self.importer.run() assert self._item().added == 4747.0 def test_reimported_item_preserves_art(self): self._setup_session() art_source = _common.RSRC / "abbey.jpg" replaced_album = self._album() replaced_album.set_art(art_source) replaced_album.store() old_artpath = replaced_album.art_filepath self.importer.run() new_album = self._album() new_artpath = new_album.art_destination(art_source) assert new_album.artpath == new_artpath assert new_album.art_filepath.exists() if new_artpath != old_artpath: assert not old_artpath.exists() def test_reimported_album_has_new_flexattr(self): self._setup_session() assert self._album().get("bandcamp_album_id") is None self.importer.run() assert self._album().bandcamp_album_id == "bc_url" def test_reimported_album_not_preserves_flexattr(self): self._setup_session() self.importer.run() assert self._album().data_source == "match_source" class TestImportPretend(ImportHelper): """Test the pretend commandline option.""" def setup_beets(self): super().setup_beets() self.album_track_path = self.prepare_album_for_import(1)[0] self.single_path = self.prepare_track_for_import(2, self.import_path) self.album_path = self.album_track_path.parent def _run(self, importer, caplog): with caplog.at_level("DEBUG"): importer.run() assert len(self.lib.items()) == 0 assert len(self.lib.albums()) == 0 return [ r.message for r in caplog.records if not r.message.startswith("Sending event:") ] def test_import_singletons_pretend(self, caplog): assert self._run( self.setup_singleton_importer(pretend=True), caplog ) == [ f"Singleton: {self.single_path}", f"Singleton: {self.album_track_path}", ] def test_import_album_pretend(self, caplog): assert self._run(self.setup_importer(pretend=True), caplog) == [ f"Album: {self.import_path}", f" {self.single_path}", f"Album: {self.album_path}", f" {self.album_track_path}", ] def test_import_pretend_empty(self, caplog): empty_path = self.temp_path / "empty" empty_path.mkdir() importer = self.setup_importer(pretend=True, import_dir=empty_path) assert self._run(importer, caplog) == [ f"No files imported from {empty_path}" ] def mocked_get_albums_by_ids(ids): """Return album candidate for the given id. The two albums differ only in the release title and artist name, so that ID_RELEASE_0 is a closer match to the items created by ImportHelper.prepare_album_for_import(). """ # Map IDs to (release title, artist), so the distances are different. album_artist_map = { TestImportId.ID_RELEASE_0: ("VALID_RELEASE_0", "TAG ARTIST"), TestImportId.ID_RELEASE_1: ("VALID_RELEASE_1", "DISTANT_MATCH"), } for id_ in ids: album, artist = album_artist_map[id_] yield AlbumInfo( album_id=id_, album=album, artist_id="some-id", artist=artist, albumstatus="Official", tracks=[ TrackInfo( track_id="bar", title="foo", artist_id="some-id", artist=artist, length=59, index=9, track_allt="A2", ) ], ) def mocked_get_tracks_by_ids(ids): """Return track candidate for the given id. The two tracks differ only in the release title and artist name, so that ID_RELEASE_0 is a closer match to the items created by ImportHelper.prepare_album_for_import(). """ # Map IDs to (recording title, artist), so the distances are different. title_artist_map = { TestImportId.ID_RECORDING_0: ("VALID_RECORDING_0", "TAG ARTIST"), TestImportId.ID_RECORDING_1: ("VALID_RECORDING_1", "DISTANT_MATCH"), } for id_ in ids: title, artist = title_artist_map[id_] yield TrackInfo( track_id=id_, title=title, artist_id="some-id", artist=artist, length=59, ) @patch( "beets.metadata_plugins.tracks_for_ids", Mock(side_effect=mocked_get_tracks_by_ids), ) @patch( "beets.metadata_plugins.albums_for_ids", Mock(side_effect=mocked_get_albums_by_ids), ) class TestImportId(ImportHelper): ID_RELEASE_0 = "00000000-0000-0000-0000-000000000000" ID_RELEASE_1 = "11111111-1111-1111-1111-111111111111" ID_RECORDING_0 = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" ID_RECORDING_1 = "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" def setup_beets(self): super().setup_beets() self.prepare_album_for_import(1) def test_one_mbid_one_album(self): self.setup_importer(search_ids=[self.ID_RELEASE_0]) self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.albums().get().album == "VALID_RELEASE_0" def test_several_mbid_one_album(self): self.setup_importer(search_ids=[self.ID_RELEASE_0, self.ID_RELEASE_1]) self.importer.add_choice(2) # Pick the 2nd best match (release 1). self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.albums().get().album == "VALID_RELEASE_1" def test_one_mbid_one_singleton(self): self.setup_singleton_importer(search_ids=[self.ID_RECORDING_0]) self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.items().get().title == "VALID_RECORDING_0" def test_several_mbid_one_singleton(self): self.setup_singleton_importer( search_ids=[self.ID_RECORDING_0, self.ID_RECORDING_1] ) self.importer.add_choice(2) # Pick the 2nd best match (recording 1). self.importer.add_choice(importer.Action.APPLY) self.importer.run() assert self.lib.items().get().title == "VALID_RECORDING_1" def test_candidates_album(self): """Test directly ImportTask.lookup_candidates().""" task = importer.ImportTask( paths=os.fsencode(self.import_path), toppath="top path", items=[_common.item()], ) task.lookup_candidates([self.ID_RELEASE_0, self.ID_RELEASE_1]) assert {"VALID_RELEASE_0", "VALID_RELEASE_1"} == { c.info.album for c in task.candidates } def test_candidates_singleton(self): """Test directly SingletonImportTask.lookup_candidates().""" task = importer.SingletonImportTask( toppath="top path", item=_common.item() ) task.lookup_candidates([self.ID_RECORDING_0, self.ID_RECORDING_1]) assert {"VALID_RECORDING_0", "VALID_RECORDING_1"} == { c.info.title for c in task.candidates } class TestMpeglayerWavImport(AsIsImporterMixin, ImportHelper): """Test remuxing of WAVE_FORMAT_MPEGLAYER3 WAV files.""" def test_remux_mpeglayer3_wav(self): src = _common.RSRC / "mpeglayer3.wav" dest = self.temp_path / "mpeglayer3.wav" shutil.copy(src, syspath(dest)) mp3_path = remux_mpeglayer3_wav(dest) assert mp3_path is not None assert mp3_path.suffix == ".mp3" assert mp3_path.exists() assert not dest.exists() def test_remux_mpeglayer3_wav_disabled(self): """When remux_mp3_in_wav is disabled, WAV file should not be remuxed.""" self.config["import"]["remux_mp3_in_wav"] = False src = _common.RSRC / "mpeglayer3.wav" dest = self.import_path / "mpeglayer3.wav" shutil.copy(src, syspath(dest)) self.run_asis_importer() assert dest.exists() beetbox-beets-00724b7/test/extra/0000775000175000017500000000000015253035401016155 5ustar pieterpieterbeetbox-beets-00724b7/test/extra/test_release.py0000664000175000017500000000704015253035401021207 0ustar pieterpieter"""Tests for the release utils.""" import shutil import sys import pytest from beets.test.helper import RUNNING_IN_CI release = pytest.importorskip("extra.release") pytestmark = pytest.mark.skipif( not ( (RUNNING_IN_CI and sys.platform != "win32") or bool(shutil.which("pandoc")) ), reason="pandoc isn't available", ) @pytest.fixture def rst_changelog(): return """ Unreleased ---------- New features ~~~~~~~~~~~~ - :doc:`/plugins/substitute`: Some substitute multi-line change. :bug:`5467` - :ref:`list-cmd` Update. - |BeetsPlugin| Some plugin change. - See :class:`~beetsplug._utils.musicbrainz.MusicBrainzAPI` for documentation. - See :class:`~nonexisting_ref` for non-existing reference. - See :ref:`Nice title ` for non-existing named reference. You can do something with this command: :: $ do-something Bug fixes ~~~~~~~~~ - Some fix that refers to an issue. :bug:`5467` - Some fix that mentions user :user:`username`. - Some fix thanks to :user:`username`. :bug:`5467` - Some fix with its own bullet points using incorrect indentation: - First nested bullet point with some text that wraps to the next line - Second nested bullet point - Another fix with an enumerated list 1. First and some details 2. Second and some details Long parapgraph naaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmmmmmeeeeeeeeeeeeeee ending with a colon: .. For plugin developers .. ~~~~~~~~~~~~~~~~~~~~~ Other changes ~~~~~~~~~~~~~ - Changed ``bitesize`` label to ``good first issue``. Our `contribute`_ page is now automatically populated with these issues. :bug:`4855` .. _contribute: https://github.com/beetbox/beets/contribute 2.1.0 (November 22, 2024) ------------------------- Bug fixes ~~~~~~~~~ - Fixed something.""" @pytest.fixture def md_changelog(): return r"""# Unreleased ## New features - [beets.plugins.BeetsPlugin](https://beets.readthedocs.io/en/stable/api/generated/beets.plugins.BeetsPlugin.html#beets.plugins.BeetsPlugin) Some plugin change. - [list command](https://beets.readthedocs.io/en/stable/reference/cli.html#list-cmd) Update. - [Substitute Plugin](https://beets.readthedocs.io/en/stable/plugins/substitute.html): Some substitute multi-line change. :bug: (#5467) - See [beetsplug.\_utils.musicbrainz.MusicBrainzAPI](https://beets.readthedocs.io/en/stable/api/generated/beetsplug._utils.musicbrainz.MusicBrainzAPI.html#beetsplug._utils.musicbrainz.MusicBrainzAPI) for documentation. - See `Nice title` for non-existing named reference. - See `nonexisting_ref` for non-existing reference. You can do something with this command: $ do-something ## Bug fixes - Another fix with an enumerated list 1. First and some details 2. Second and some details - Some fix thanks to @username. :bug: (#5467) - Some fix that mentions user @username. - Some fix that refers to an issue. :bug: (#5467) - Some fix with its own bullet points using incorrect indentation: - First nested bullet point with some text that wraps to the next line - Second nested bullet point Long parapgraph naaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmmmmmeeeeeeeeeeeeeee ending with a colon: ## Other changes - Changed `bitesize` label to `good first issue`. Our [contribute](https://github.com/beetbox/beets/contribute) page is now automatically populated with these issues. :bug: (#4855) # 2.1.0 (November 22, 2024) ## Bug fixes - Fixed something.""" # noqa: E501 def test_convert_rst_to_md(rst_changelog, md_changelog): actual = release.changelog_as_markdown(rst_changelog) assert actual == md_changelog beetbox-beets-00724b7/test/extra/__init__.py0000664000175000017500000000000015253035401020254 0ustar pieterpieterbeetbox-beets-00724b7/test/test_library.py0000664000175000017500000014177615253035401020127 0ustar pieterpieter"""Tests for non-query database functions of Item.""" from __future__ import annotations import os import os.path import re import shutil import stat import unittest from pathlib import Path from unittest.mock import patch import pytest from mediafile import MediaFile, UnreadableFileError import beets.dbcore.query import beets.library from beets import config, plugins, util from beets.library import Album from beets.test import _common from beets.test._common import item from beets.test.helper import TestHelper from beets.util import as_string, bytestring_path, normpath # Shortcut to path normalization. np = util.normpath class PytestItemHelper(TestHelper): def get_first_item(self): """Retrieve first item from library.""" return next(iter(self.lib.items())) @pytest.fixture def item(self): return _common.item() @pytest.fixture def item_in_db(self): return _common.item(self.lib) class TestBlobTypeCompatibility: def test_canonical_alias_is_bytes(self): assert beets.dbcore.query.BLOB_TYPE is bytes def test_legacy_alias_warns(self): with pytest.deprecated_call( match="'beets.library.BLOB_TYPE' is deprecated" ): blob_type = beets.library.BLOB_TYPE assert blob_type is bytes class TestLoad(PytestItemHelper): def test_load_restores_data_from_db(self, item_in_db): original_title = item_in_db.title item_in_db.title = "something" item_in_db.load() assert original_title == item_in_db.title def test_load_clears_dirty_flags(self, item_in_db): item_in_db.artist = "something" assert "artist" in item_in_db._dirty item_in_db.load() assert "artist" not in item_in_db._dirty class TestStore(PytestItemHelper): def test_store_changes_database_value(self, item_in_db): new_year = 1987 item_in_db.year = new_year item_in_db.store() assert self.lib.get_item(item_in_db.id).year == new_year def test_store_only_writes_dirty_fields(self, item_in_db): new_year = 1987 item_in_db._values_fixed["year"] = new_year # change w/o dirtying item_in_db.store() assert self.lib.get_item(item_in_db.id).year != new_year def test_store_clears_dirty_flags(self, item_in_db): item_in_db.composers = ["tvp"] item_in_db.store() assert "composers" not in item_in_db._dirty def test_store_album_cascades_flex_deletes(self): album = Album(flex1="Flex-1") self.lib.add(album) item = _common.item() item.album_id = album.id item.flex1 = "Flex-1" self.lib.add(item) del album.flex1 album.store() assert "flex1" not in album assert "flex1" not in album.items()[0] def test_store_does_not_propagate_artpath_to_items(self): item = _common.item() self.lib.add(item) album = self.lib.add_album([item]) assert "artpath" not in Album.item_keys album.artpath = b"/abs/path/to/cover.jpg" album.store() stored = self.lib.get_item(item.id) assert not stored.get("artpath", with_album=False) class TestAdd(PytestItemHelper): def test_item_add_inserts_row(self, item): self.lib.add(item) new_grouping = ( self.lib._connection() .execute( "select grouping from items where composers = ?", (item._type("composers").to_sql(item.composers),), ) .fetchone()["grouping"] ) assert new_grouping == item.grouping def test_library_add_path_inserts_row(self): item = beets.library.Item.from_path(_common.RSRC / "full.mp3") self.lib.add(item) new_grouping = ( self.lib._connection() .execute( "select grouping from items where composers = ?", (item._type("composers").to_sql(item.composers),), ) .fetchone()["grouping"] ) assert new_grouping == item.grouping def test_library_add_one_database_change_event( self, item, caplog: pytest.LogCaptureFixture ): """Test library.add emits only one database_change event.""" item.path = beets.util.normpath(self.temp_path / "a" / "b.mp3") item.album = "a" item.title = "b" with caplog.at_level("DEBUG", logger="beets"): self.lib.add(item) assert caplog.text.count("Sending event: database_change") == 1 class TestRemove(PytestItemHelper): def test_remove_deletes_from_db(self, item_in_db): item_in_db.remove() c = self.lib._connection().execute("select * from items") assert c.fetchone() is None class TestGetSet(PytestItemHelper): def test_set_changes_value(self, item): item.bpm = 4915 assert item.bpm == 4915 def test_set_sets_dirty_flag(self, item): item.comp = not item.comp assert "comp" in item._dirty def test_set_does_not_dirty_if_value_unchanged(self, item): item.title = item.title assert "title" not in item._dirty def test_set_memoryview_path_normalizes_to_bytes(self, item): item.path = memoryview(b"/tmp/song.mp3") assert item.path == b"/tmp/song.mp3" assert isinstance(item.path, bytes) assert item.filepath == Path("/tmp/song.mp3") def test_invalid_field_raises_attributeerror(self, item): with pytest.raises(AttributeError): item.xyzzy def test_album_fallback(self, item_in_db): # integration test of item-album fallback album = self.lib.add_album([item_in_db]) album["flex"] = "foo" album.store() assert "flex" in item_in_db assert "flex" not in item_in_db.keys(with_album=False) assert item_in_db["flex"] == "foo" assert item_in_db.get("flex") == "foo" assert item_in_db.get("flex", with_album=False) is None assert item_in_db.get("flexx") is None class TestDestination(PytestItemHelper): """Confirm tests handle temporary directory path containing '.'""" def create_temp_dir(self, **kwargs): kwargs["prefix"] = "." return super().create_temp_dir(**kwargs) def test_directory_works_with_trailing_slash(self, item_in_db): self.lib.directory = b"one/" self.lib.path_formats = [("default", "two")] assert item_in_db.destination() == np("one/two") def test_directory_works_without_trailing_slash(self, item_in_db): self.lib.directory = b"one" self.lib.path_formats = [("default", "two")] assert item_in_db.destination() == np("one/two") def test_destination_substitutes_metadata_values(self, item_in_db): self.lib.directory = b"base" self.lib.path_formats = [("default", "$album/$artist $title")] item_in_db.title = "three" item_in_db.artist = "two" item_in_db.album = "one" assert item_in_db.destination() == np("base/one/two three") def test_destination_preserves_extension(self, item_in_db): self.lib.directory = b"base" self.lib.path_formats = [("default", "$title")] item_in_db.path = "hey.audioformat" assert item_in_db.destination() == np("base/the title.audioformat") def test_lower_case_extension(self, item_in_db): self.lib.directory = b"base" self.lib.path_formats = [("default", "$title")] item_in_db.path = "hey.MP3" assert item_in_db.destination() == np("base/the title.mp3") def test_destination_pads_some_indices(self, item_in_db): self.lib.directory = b"base" self.lib.path_formats = [ ("default", "$track $tracktotal $disc $disctotal $bpm") ] item_in_db.track = 1 item_in_db.tracktotal = 2 item_in_db.disc = 3 item_in_db.disctotal = 4 item_in_db.bpm = 5 assert item_in_db.destination() == np("base/01 02 03 04 5") def test_destination_pads_date_values(self, item_in_db): self.lib.directory = b"base" self.lib.path_formats = [("default", "$year-$month-$day")] item_in_db.year = 1 item_in_db.month = 2 item_in_db.day = 3 assert item_in_db.destination() == np("base/0001-02-03") def test_destination_escapes_slashes(self, item_in_db): self.lib.path_formats = [("default", "$artist/$album/$track $title")] item_in_db.album = "one/two" dest = item_in_db.destination() assert b"one" in dest assert b"two" in dest assert b"one/two" not in dest def test_destination_escapes_leading_dot(self, item_in_db): self.lib.path_formats = [("default", "$artist/$album/$track $title")] item_in_db.album = ".something" dest = item_in_db.destination() assert b"something" in dest assert b"/.something" not in dest def test_destination_preserves_legitimate_slashes(self, item_in_db): self.lib.path_formats = [("default", "$artist/$album/$track $title")] item_in_db.artist = "one" item_in_db.album = "two" dest = item_in_db.destination() assert os.path.join(b"one", b"two") in dest def test_destination_long_names_truncated(self, item_in_db): item_in_db.title = "X" * 300 item_in_db.artist = "Y" * 300 for c in item_in_db.destination().split(util.PATH_SEP): assert len(c) <= 255 def test_destination_long_names_keep_extension(self, item_in_db): item_in_db.title = "X" * 300 item_in_db.path = b"something.extn" dest = item_in_db.destination() assert dest[-5:] == b".extn" def test_distination_windows_removes_both_separators(self, item_in_db): item_in_db.title = "one \\ two / three.mp3" with _common.platform_windows(): p = item_in_db.destination() assert b"one \\ two" not in p assert b"one / two" not in p assert b"two \\ three" not in p assert b"two / three" not in p def test_path_with_format(self, item_in_db): self.lib.path_formats = [("default", "$artist/$album ($format)")] p = item_in_db.destination() assert b"(FLAC)" in p def test_heterogeneous_album_gets_single_directory(self): i1, i2 = _common.item(self.lib), _common.item(self.lib) self.lib.add_album([i1, i2]) i1.year, i2.year = 2009, 2010 self.lib.path_formats = [("default", "$album ($year)/$track $title")] dest1, dest2 = i1.destination(), i2.destination() assert os.path.dirname(dest1) == os.path.dirname(dest2) def test_default_path_for_non_compilations(self, item_in_db): item_in_db.comp = False self.lib.add_album([item_in_db]) self.lib.directory = b"one" self.lib.path_formats = [("default", "two"), ("comp:true", "three")] assert item_in_db.destination() == np("one/two") def test_singleton_path(self, item_in_db): self.lib.directory = b"one" self.lib.path_formats = [ ("default", "two"), ("singleton:true", "four"), ("comp:true", "three"), ] assert item_in_db.destination() == np("one/four") def test_comp_before_singleton_path(self, item_in_db): item_in_db.comp = True self.lib.directory = b"one" self.lib.path_formats = [ ("default", "two"), ("comp:true", "three"), ("singleton:true", "four"), ] assert item_in_db.destination() == np("one/three") def test_comp_path(self, item_in_db): item_in_db.comp = True self.lib.add_album([item_in_db]) self.lib.directory = b"one" self.lib.path_formats = [("default", "two"), ("comp:true", "three")] assert item_in_db.destination() == np("one/three") def test_multi_value_string_query_path(self, item_in_db): item_in_db.genres = ["Classical"] self.lib.directory = b"one" self.lib.path_formats = [ ("default", "two"), ("genres:=~Classical", "three"), ] assert item_in_db.destination() == np("one/three") def test_multi_value_match_query_path(self, item_in_db): item_in_db.genres = ["Classical"] self.lib.directory = b"one" self.lib.path_formats = [ ("default", "two"), ("genres:=Classical", "three"), ] assert item_in_db.destination() == np("one/three") def test_multi_value_string_query_path_no_substring_match(self, item_in_db): item_in_db.genres = ["Neoclassical"] self.lib.directory = b"one" self.lib.path_formats = [ ("default", "two"), ("genres:=~Classical", "three"), ] assert item_in_db.destination() == np("one/two") def test_albumtype_query_path(self, item_in_db): item_in_db.comp = True self.lib.add_album([item_in_db]) item_in_db.albumtype = "sometype" self.lib.directory = b"one" self.lib.path_formats = [ ("default", "two"), ("albumtype:sometype", "four"), ("comp:true", "three"), ] assert item_in_db.destination() == np("one/four") def test_albumtype_path_fallback_to_comp(self, item_in_db): item_in_db.comp = True self.lib.add_album([item_in_db]) item_in_db.albumtype = "sometype" self.lib.directory = b"one" self.lib.path_formats = [ ("default", "two"), ("albumtype:anothertype", "four"), ("comp:true", "three"), ] assert item_in_db.destination() == np("one/three") def test_get_formatted_does_not_replace_separators(self, item_in_db): with _common.platform_posix(): name = str(Path("a") / "b") item_in_db.title = name newname = item_in_db.formatted().get("title") assert name == newname def test_get_formatted_pads_with_zero(self, item_in_db): with _common.platform_posix(): item_in_db.track = 1 name = item_in_db.formatted().get("track") assert name.startswith("0") def test_get_formatted_uses_kbps_bitrate(self, item_in_db): with _common.platform_posix(): item_in_db.bitrate = 12345 val = item_in_db.formatted().get("bitrate") assert val == "12kbps" def test_get_formatted_uses_khz_samplerate(self, item_in_db): with _common.platform_posix(): item_in_db.samplerate = 12345 val = item_in_db.formatted().get("samplerate") assert val == "12kHz" def test_get_formatted_datetime(self, item_in_db): with _common.platform_posix(): item_in_db.added = 1368302461.210265 val = item_in_db.formatted().get("added") assert val.startswith("2013") def test_get_formatted_none(self, item_in_db): with _common.platform_posix(): item_in_db.some_other_field = None val = item_in_db.formatted().get("some_other_field") assert val == "" def test_artist_falls_back_to_albumartist(self, item_in_db): item_in_db.artist = "" item_in_db.albumartist = "something" self.lib.path_formats = [("default", "$artist")] p = item_in_db.destination() assert p.rsplit(util.PATH_SEP, 1)[1] == b"something" def test_albumartist_falls_back_to_artist(self, item_in_db): item_in_db.artist = "trackartist" item_in_db.albumartist = "" self.lib.path_formats = [("default", "$albumartist")] p = item_in_db.destination() assert p.rsplit(util.PATH_SEP, 1)[1] == b"trackartist" def test_artist_overrides_albumartist(self, item_in_db): item_in_db.artist = "theartist" item_in_db.albumartist = "something" self.lib.path_formats = [("default", "$artist")] p = item_in_db.destination() assert p.rsplit(util.PATH_SEP, 1)[1] == b"theartist" def test_albumartist_overrides_artist(self, item_in_db): item_in_db.artist = "theartist" item_in_db.albumartist = "something" self.lib.path_formats = [("default", "$albumartist")] p = item_in_db.destination() assert p.rsplit(util.PATH_SEP, 1)[1] == b"something" def test_unicode_extension_in_fragment(self, item_in_db): self.lib.path_formats = [("default", "foo")] item_in_db.path = Path("bar.caf\xe9") with patch("sys.platform", "linux"): dest = item_in_db.destination(relative_to_libdir=True) assert as_string(dest) == "foo.caf\xe9" def test_asciify_character_expanding_to_slash(self, item_in_db): config["asciify_paths"] = True self.lib.directory = b"lib" self.lib.path_formats = [("default", "$title")] item_in_db.title = "ab\xa2\xbdd" assert item_in_db.destination() == np("lib/abC_ 1_2d") def test_destination_with_replacements(self, item_in_db): self.lib.directory = b"base" self.lib.replacements = [(re.compile(r"a"), "e")] self.lib.path_formats = [("default", "$album/$title")] item_in_db.title = "foo" item_in_db.album = "bar" assert item_in_db.destination() == np("base/ber/foo") def test_destination_stays_in_basedir_with_empty_leading_field( self, item_in_db ): # Regression test for #4889: an empty leading template field # combined with custom replacements that lack the default # separator rule must not produce an absolute path that escapes # the base directory. self.lib.directory = b"base" self.lib.replacements = [(re.compile(r"a"), "e")] self.lib.path_formats = [("default", "$album/$title")] item_in_db.album = "" item_in_db.title = "three" assert item_in_db.destination() == np("base/three") @unittest.skip("unimplemented: #359") def test_destination_with_empty_component(self, item_in_db): self.lib.directory = b"base" self.lib.replacements = [(re.compile(r"^$"), "_")] self.lib.path_formats = [("default", "$album/$artist/$title")] item_in_db.title = "three" item_in_db.artist = "" item_in_db.albumartist = "" item_in_db.album = "one" assert item_in_db.destination() == np("base/one/_/three") @unittest.skip("unimplemented: #359") def test_destination_with_empty_final_component(self, item_in_db): self.lib.directory = b"base" self.lib.replacements = [(re.compile(r"^$"), "_")] self.lib.path_formats = [("default", "$album/$title")] item_in_db.title = "" item_in_db.album = "one" item_in_db.path = "foo.mp3" assert item_in_db.destination() == np("base/one/_.mp3") def test_album_field_query(self, item_in_db): self.lib.directory = b"one" self.lib.path_formats = [("default", "two"), ("flex:foo", "three")] album = self.lib.add_album([item_in_db]) assert item_in_db.destination() == np("one/two") album["flex"] = "foo" album.store() assert item_in_db.destination() == np("one/three") def test_album_field_in_template(self, item_in_db): self.lib.directory = b"one" self.lib.path_formats = [("default", "$flex/two")] album = self.lib.add_album([item_in_db]) album["flex"] = "foo" album.store() assert item_in_db.destination() == np("one/foo/two") class TestItemFormattedMapping(PytestItemHelper): def test_formatted_item_value(self, item_in_db): formatted = item_in_db.formatted() assert formatted["artist"] == "the artist" def test_get_unset_field(self, item_in_db): formatted = item_in_db.formatted() with pytest.raises(KeyError): formatted["other_field"] def test_get_method_with_default(self, item_in_db): formatted = item_in_db.formatted() assert formatted.get("other_field") == "" def test_get_method_with_specified_default(self, item_in_db): formatted = item_in_db.formatted() assert formatted.get("other_field", "default") == "default" def test_item_precedence(self, item_in_db): album = self.lib.add_album([item_in_db]) album["artist"] = "foo" album.store() assert "foo" != item_in_db.formatted().get("artist") def test_album_flex_field(self, item_in_db): album = self.lib.add_album([item_in_db]) album["flex"] = "foo" album.store() assert "foo" == item_in_db.formatted().get("flex") def test_album_field_overrides_item_field_for_path(self, item_in_db): # Make the album inconsistent with the item. album = self.lib.add_album([item_in_db]) album.album = "foo" album.store() item_in_db.album = "bar" item_in_db.store() # Ensure the album takes precedence. formatted = item_in_db.formatted(for_path=True) assert formatted["album"] == "foo" def test_artist_falls_back_to_albumartist(self, item_in_db): item_in_db.artist = "" formatted = item_in_db.formatted() assert formatted["artist"] == "the album artist" def test_albumartist_falls_back_to_artist(self, item_in_db): item_in_db.albumartist = "" formatted = item_in_db.formatted() assert formatted["albumartist"] == "the artist" def test_both_artist_and_albumartist_empty(self, item_in_db): item_in_db.artist = "" item_in_db.albumartist = "" formatted = item_in_db.formatted() assert formatted["albumartist"] == "" class PathFormattingMixin: """Utilities for testing path formatting.""" lib: beets.library.Library def _setf(self, fmt): self.lib.path_formats.insert(0, ("default", fmt)) def _assert_dest(self, dest, item): # Handle paths on Windows. if os.path.sep != "/": dest = dest.replace(b"/", os.path.sep.encode()) # Paths are normalized based on the CWD. dest = normpath(dest) actual = item.destination() assert actual == dest class TestDestinationFunction(TestHelper, PathFormattingMixin): @pytest.fixture(autouse=True) def item(self, setup): self.lib.directory = b"/base" self.lib.path_formats = [("default", "path")] return item(self.lib) def test_upper_case_literal(self, item): self._setf("%upper{foo}") self._assert_dest(b"/base/FOO", item) def test_upper_case_variable(self, item): self._setf("%upper{$title}") self._assert_dest(b"/base/THE TITLE", item) def test_capitalize_variable(self, item): self._setf("%capitalize{$title}") self._assert_dest(b"/base/The title", item) def test_title_case_variable(self, item): self._setf("%title{$title}") self._assert_dest(b"/base/The Title", item) def test_title_case_variable_aphostrophe(self, item): self._setf("%title{I can't}") self._assert_dest(b"/base/I Can't", item) def test_asciify_variable(self, item): self._setf("%asciify{ab\xa2\xbdd}") self._assert_dest(b"/base/abC_ 1_2d", item) def test_left_variable(self, item): self._setf("%left{$title, 3}") self._assert_dest(b"/base/the", item) def test_right_variable(self, item): self._setf("%right{$title,3}") self._assert_dest(b"/base/tle", item) def test_if_false(self, item): self._setf("x%if{,foo}") self._assert_dest(b"/base/x", item) def test_if_false_value(self, item): self._setf("x%if{false,foo}") self._assert_dest(b"/base/x", item) def test_if_true(self, item): self._setf("%if{bar,foo}") self._assert_dest(b"/base/foo", item) def test_if_else_false(self, item): self._setf("%if{,foo,baz}") self._assert_dest(b"/base/baz", item) def test_if_else_false_value(self, item): self._setf("%if{false,foo,baz}") self._assert_dest(b"/base/baz", item) def test_if_int_value(self, item): self._setf("%if{0,foo,baz}") self._assert_dest(b"/base/baz", item) def test_nonexistent_function(self, item): self._setf("%foo{bar}") self._assert_dest(b"/base/%foo{bar}", item) def test_if_def_field_return_self(self, item): item.bar = 3 self._setf("%ifdef{bar}") self._assert_dest(b"/base/3", item) def test_if_def_field_not_defined(self, item): self._setf(" %ifdef{bar}/$artist") self._assert_dest(b"/base/the artist", item) def test_if_def_field_not_defined_2(self, item): self._setf("$artist/%ifdef{bar}") self._assert_dest(b"/base/the artist", item) def test_if_def_true(self, item): self._setf("%ifdef{artist,cool}") self._assert_dest(b"/base/cool", item) def test_if_def_true_complete(self, item): item.series = "Now" self._setf("%ifdef{series,$series Series,Albums}/$album") self._assert_dest(b"/base/Now Series/the album", item) def test_if_def_false_complete(self, item): self._setf("%ifdef{plays,$plays,not_played}") self._assert_dest(b"/base/not_played", item) def test_first(self, item): item.albumtypes = ["album", "compilation"] self._setf("%first{$albumtypes}") self._assert_dest(b"/base/album", item) def test_first_skip(self, item): item.albumtype = "album; ep; compilation" self._setf("%first{$albumtype,1,2}") self._assert_dest(b"/base/compilation", item) def test_first_different_sep(self, item): self._setf("%first{Alice / Bob / Eve,2,0, / , & }") self._assert_dest(b"/base/Alice & Bob", item) class TestDisambiguation(TestHelper, PathFormattingMixin): @pytest.fixture(autouse=True) def items(self, setup): self.lib.directory = b"/base" self.lib.path_formats = [("default", "path")] i1 = item() i1.year = 2001 self.lib.add_album([i1]) i2 = item() i2.year = 2002 self.lib.add_album([i2]) self.lib._connection().commit() self._setf("foo%aunique{albumartist album,year}/$title") return i1, i2 def test_unique_expands_to_disambiguating_year(self, items): i1, _i2 = items self._assert_dest(b"/base/foo [2001]/the title", i1) def test_unique_with_default_arguments_uses_albumtype(self, items): i1, _i2 = items album2 = self.lib.get_album(i1) album2.albumtype = "bar" album2.store() self._setf("foo%aunique{}/$title") self._assert_dest(b"/base/foo [bar]/the title", i1) def test_unique_expands_to_nothing_for_distinct_albums(self, items): i1, i2 = items album2 = self.lib.get_album(i2) album2.album = "different album" album2.store() self._assert_dest(b"/base/foo/the title", i1) def test_use_fallback_numbers_when_identical(self, items): i1, i2 = items album2 = self.lib.get_album(i2) album2.year = 2001 album2.store() self._assert_dest(b"/base/foo [1]/the title", i1) self._assert_dest(b"/base/foo [2]/the title", i2) def test_unique_falls_back_to_second_distinguishing_field(self, items): i1, _i2 = items self._setf("foo%aunique{albumartist album,month year}/$title") self._assert_dest(b"/base/foo [2001]/the title", i1) def test_unique_sanitized(self, items): i1, i2 = items album2 = self.lib.get_album(i2) album2.year = 2001 album1 = self.lib.get_album(i1) album1.albumtype = "foo/bar" album2.store() album1.store() self._setf("foo%aunique{albumartist album,albumtype}/$title") self._assert_dest(b"/base/foo [foo_bar]/the title", i1) def test_drop_empty_disambig_string(self, items): i1, i2 = items album1 = self.lib.get_album(i1) album1.albumdisambig = None album2 = self.lib.get_album(i2) album2.albumdisambig = "foo" album1.store() album2.store() self._setf("foo%aunique{albumartist album,albumdisambig}/$title") self._assert_dest(b"/base/foo/the title", i1) def test_change_brackets(self, items): i1, _i2 = items self._setf("foo%aunique{albumartist album,year,()}/$title") self._assert_dest(b"/base/foo (2001)/the title", i1) def test_remove_brackets(self, items): i1, _i2 = items self._setf("foo%aunique{albumartist album,year,}/$title") self._assert_dest(b"/base/foo 2001/the title", i1) def test_key_flexible_attribute(self, items): i1, i2 = items album1 = self.lib.get_album(i1) album1.flex = "flex1" album2 = self.lib.get_album(i2) album2.flex = "flex2" album1.store() album2.store() self._setf("foo%aunique{albumartist album flex,year}/$title") self._assert_dest(b"/base/foo/the title", i1) class TestSingletonDisambiguation(TestHelper, PathFormattingMixin): @pytest.fixture(autouse=True) def items(self, setup): self.lib.directory = b"/base" self.lib.path_formats = [("default", "path")] i1 = item() i1.year = 2001 self.lib.add(i1) i2 = item() i2.year = 2002 self.lib.add(i2) self.lib._connection().commit() self._setf("foo/$title%sunique{artist title,year}") return i1, i2 def test_sunique_expands_to_disambiguating_year(self, items): i1, _i2 = items self._assert_dest(b"/base/foo/the title [2001]", i1) def test_sunique_with_default_arguments_uses_trackdisambig(self, items): i1, i2 = items i1.trackdisambig = "live version" i1.year = i2.year i1.store() self._setf("foo/$title%sunique{}") self._assert_dest(b"/base/foo/the title [live version]", i1) def test_sunique_expands_to_nothing_for_distinct_singletons(self, items): i1, i2 = items i2.title = "different track" i2.store() self._assert_dest(b"/base/foo/the title", i1) def test_sunique_does_not_match_album(self, items): i1, i2 = items self.lib.add_album([i2]) self._assert_dest(b"/base/foo/the title", i1) def test_sunique_use_fallback_numbers_when_identical(self, items): i1, i2 = items i2.year = i1.year i2.store() self._assert_dest(b"/base/foo/the title [1]", i1) self._assert_dest(b"/base/foo/the title [2]", i2) def test_sunique_falls_back_to_second_distinguishing_field(self, items): i1, _i2 = items self._setf("foo/$title%sunique{albumartist album,month year}") self._assert_dest(b"/base/foo/the title [2001]", i1) def test_sunique_sanitized(self, items): i1, i2 = items i2.year = i1.year i1.trackdisambig = "foo/bar" i2.store() i1.store() self._setf("foo/$title%sunique{artist title,trackdisambig}") self._assert_dest(b"/base/foo/the title [foo_bar]", i1) def test_drop_empty_disambig_string(self, items): i1, i2 = items i1.trackdisambig = None i2.trackdisambig = "foo" i1.store() i2.store() self._setf("foo/$title%sunique{albumartist album,trackdisambig}") self._assert_dest(b"/base/foo/the title", i1) def test_change_brackets(self, items): i1, _i2 = items self._setf("foo/$title%sunique{artist title,year,()}") self._assert_dest(b"/base/foo/the title (2001)", i1) def test_remove_brackets(self, items): i1, _i2 = items self._setf("foo/$title%sunique{artist title,year,}") self._assert_dest(b"/base/foo/the title 2001", i1) def test_key_flexible_attribute(self, items): i1, i2 = items i1.flex = "flex1" i2.flex = "flex2" i1.store() i2.store() self._setf("foo/$title%sunique{artist title flex,year}") self._assert_dest(b"/base/foo/the title", i1) class TestPluginDestination(TestHelper): @pytest.fixture(autouse=True) def item(self, setup): # Mock beets.plugins.item_field_getters. self._tv_map = {} def field_getters(): getters = {} for key, value in self._tv_map.items(): getters[key] = lambda _: value return getters self.old_field_getters = plugins.item_field_getters plugins.item_field_getters = field_getters self.lib.directory = b"/base" self.lib.path_formats = [("default", "$artist $foo")] yield _common.item(self.lib) plugins.item_field_getters = self.old_field_getters def _assert_dest(self, dest, item): with _common.platform_posix(): the_dest = item.destination() assert the_dest == b"/base/" + dest def test_undefined_value_not_substituted(self, item): self._assert_dest(b"the artist $foo", item) def test_plugin_value_not_substituted(self, item): self._tv_map = {"foo": "bar"} self._assert_dest(b"the artist bar", item) def test_plugin_value_overrides_attribute(self, item): self._tv_map = {"artist": "bar"} self._assert_dest(b"bar $foo", item) def test_plugin_value_sanitized(self, item): self._tv_map = {"foo": "bar/baz"} self._assert_dest(b"the artist bar_baz", item) class TestAlbumInfo(PytestItemHelper): @pytest.fixture def item_in_album(self, item): self.lib.add_album((item,)) return item def test_albuminfo_reflects_metadata(self, item_in_album): ai = self.lib.get_album(item_in_album) assert ai.mb_albumartistid == item_in_album.mb_albumartistid assert ai.albumartist == item_in_album.albumartist assert ai.album == item_in_album.album assert ai.year == item_in_album.year def test_albuminfo_stores_art(self, item_in_album): ai = self.lib.get_album(item_in_album) ai.artpath = os.fsdecode(np("/my/great/art")) ai.store() new_ai = self.lib.get_album(item_in_album) assert new_ai.artpath == np("/my/great/art") def test_albuminfo_for_two_items_doesnt_duplicate_row(self, item_in_album): i2 = _common.item(self.lib) self.lib.get_album(item_in_album) self.lib.get_album(i2) c = self.lib._connection().cursor() c.execute("select * from albums where album=?", (item_in_album.album,)) # Cursor should only return one row. assert c.fetchone() is not None assert c.fetchone() is None def test_individual_tracks_have_no_albuminfo(self): i2 = _common.item() i2.album = "aTotallyDifferentAlbum" self.lib.add(i2) ai = self.lib.get_album(i2) assert ai is None def test_get_album_by_id(self, item_in_album): ai = self.lib.get_album(item_in_album) ai = self.lib.get_album(item_in_album.id) assert ai is not None def test_album_items_consistent(self, item_in_album): ai = self.lib.get_album(item_in_album) assert item_in_album.id in {i.id for i in ai.items()} def test_albuminfo_changes_affect_items(self, item_in_album): ai = self.lib.get_album(item_in_album) ai.album = "myNewAlbum" ai.store() assert self.get_first_item().album == "myNewAlbum" def test_albuminfo_change_albumartist_changes_items(self, item_in_album): ai = self.lib.get_album(item_in_album) ai.albumartist = "myNewArtist" ai.store() item = self.get_first_item() assert item.albumartist == "myNewArtist" assert item.artist != "myNewArtist" def test_albuminfo_change_artist_does_change_items(self, item_in_album): ai = self.lib.get_album(item_in_album) ai.artist = "myNewArtist" ai.store(inherit=True) assert self.get_first_item().artist == "myNewArtist" def test_albuminfo_change_artist_does_not_change_items(self, item_in_album): ai = self.lib.get_album(item_in_album) ai.artist = "myNewArtist" ai.store(inherit=False) assert self.get_first_item().artist != "myNewArtist" def test_albuminfo_remove_removes_items(self, item_in_album): item_id = item_in_album.id self.lib.get_album(item_in_album).remove() c = self.lib._connection().execute( "SELECT id FROM items WHERE id=?", (item_id,) ) assert c.fetchone() is None def test_removing_last_item_removes_album(self, item_in_album): assert len(self.lib.albums()) == 1 item_in_album.remove() assert len(self.lib.albums()) == 0 def test_noop_albuminfo_changes_affect_items(self, item_in_album): item = self.get_first_item() item.album = "foobar" item.store() ai = self.lib.get_album(item_in_album) ai.album = ai.album ai.store() item = self.get_first_item() assert item.album == ai.album class TestArtDestination(TestHelper): @pytest.fixture(autouse=True) def item_and_album(self, setup): config["art_filename"] = "artimage" config["replace"] = {"X": "Y"} self.lib.replacements = [(re.compile("X"), "Y")] self.lib.path_formats = [("default", "$artist/$album/$track $title")] item = _common.item(self.lib) item.path = item.destination() ai = self.lib.add_album((item,)) return item, ai def test_art_filename_respects_setting(self, item_and_album): _i, ai = item_and_album art = ai.art_destination("something.jpg") new_art = bytestring_path(f"{os.path.sep}artimage.jpg") assert new_art in art def test_art_path_in_item_dir(self, item_and_album): i, ai = item_and_album art = ai.art_destination("something.jpg") track = i.destination() assert os.path.dirname(art) == os.path.dirname(track) def test_art_path_sanitized(self, item_and_album): _i, ai = item_and_album config["art_filename"] = "artXimage" art = ai.art_destination("something.jpg") assert b"artYimage" in art class TestPathString(PytestItemHelper): def test_item_path_is_bytestring(self, item_in_db): assert isinstance(item_in_db.path, bytes) def test_fetched_item_path_is_bytestring(self, item_in_db): assert isinstance(self.get_first_item().path, bytes) def test_unicode_path_becomes_bytestring(self, item_in_db): item_in_db.path = "unicodepath" assert isinstance(item_in_db.path, bytes) def test_unicode_in_database_becomes_bytestring(self, item_in_db): self.lib._connection().execute( """ update items set path=? where id=? """, (item_in_db.id, "somepath"), ) assert isinstance(self.get_first_item().path, bytes) def test_special_chars_preserved_in_database(self, item_in_db): path = Path("b\xe1r") item_in_db.path = path item_in_db.store() assert self.get_first_item().filepath == self.lib_path / path def test_special_char_path_added_to_database(self, item, item_in_db): item_in_db.remove() path = Path("b\xe1r") item = _common.item() item.path = path self.lib.add(item) assert self.get_first_item().filepath == self.lib_path / path def test_destination_returns_bytestring(self, item_in_db): item_in_db.artist = "b\xe1r" dest = item_in_db.destination() assert isinstance(dest, bytes) def test_art_destination_returns_bytestring(self, item_in_db): item_in_db.artist = "b\xe1r" alb = self.lib.add_album([item_in_db]) dest = alb.art_destination("image.jpg") assert isinstance(dest, bytes) def test_artpath_stores_special_chars(self, item_in_db): path = Path("b\xe1r") alb = self.lib.add_album([item_in_db]) alb.artpath = path alb.store() stored_path = ( self.lib._connection() .execute("select artpath from albums where id=?", (alb.id,)) .fetchone()[0] ) alb = self.lib.get_album(item_in_db) assert stored_path == os.fsencode(path) assert alb.art_filepath == self.lib_path / path def test_sanitize_path_with_special_chars(self): path = "b\xe1r?" new_path = util.sanitize_path(path) assert new_path.startswith("b\xe1r") def test_sanitize_path_returns_unicode(self): path = "b\xe1r?" new_path = util.sanitize_path(path) assert isinstance(new_path, str) def test_unicode_artpath_becomes_bytestring(self, item_in_db): alb = self.lib.add_album([item_in_db]) alb.artpath = "somep\xe1th" assert isinstance(alb.artpath, bytes) def test_unicode_artpath_in_database_decoded(self, item_in_db): alb = self.lib.add_album([item_in_db]) self.lib._connection().execute( "update albums set artpath=? where id=?", ("somep\xe1th", alb.id) ) alb = self.lib.get_album(alb.id) assert isinstance(alb.artpath, bytes) def test_relative_path_is_stored(self, item_in_db): relative_path = Path("abc") / "foo.mp3" absolute_path = self.lib_path / relative_path item_in_db.path = absolute_path item_in_db.store() stored_path = ( self.lib._connection() .execute("select path from items where id=?", (item_in_db.id,)) .fetchone()[0] ) album = self.lib.add_album([item_in_db]) assert item_in_db.filepath == absolute_path assert stored_path == util.path_as_posix(os.fsencode(relative_path)) assert album.filepath == absolute_path.parent class TestMtime(TestHelper): @pytest.fixture(autouse=True) def item(self, setup): self.ipath = self.temp_path / "testfile.mp3" shutil.copy(_common.RSRC / "full.mp3", self.ipath) item = beets.library.Item.from_path(self.ipath) self.lib.add(item) yield item if self.ipath.exists(): self.ipath.unlink() def _mtime(self): return int(self.ipath.stat().st_mtime) def test_mtime_initially_up_to_date(self, item): assert item.mtime >= self._mtime() def test_mtime_reset_on_db_modify(self, item): item.title = "something else" assert item.mtime < self._mtime() def test_mtime_up_to_date_after_write(self, item): item.title = "something else" item.write() assert item.mtime >= self._mtime() def test_mtime_up_to_date_after_read(self, item): item.title = "something else" item.read() assert item.mtime >= self._mtime() class TestImportTime(TestHelper): def added(self): self.track = item() self.album = self.lib.add_album((self.track,)) assert self.album.added > 0 assert self.track.added > 0 def test_atime_for_singleton(self): self.singleton = item(self.lib) assert self.singleton.added > 0 class TestTemplate(PytestItemHelper): def test_year_formatted_in_template(self, item_in_db): item_in_db.year = 123 item_in_db.store() assert item_in_db.evaluate_template("$year") == "0123" def test_album_flexattr_appears_in_item_template(self, item_in_db): self.album = self.lib.add_album([item_in_db]) self.album.foo = "baz" self.album.store() assert item_in_db.evaluate_template("$foo") == "baz" def test_album_and_item_format(self, item_in_db): config["format_album"] = "foö $foo" album = beets.library.Album() album.foo = "bar" album.tagada = "togodo" assert f"{album}" == "foö bar" assert f"{album:$tagada}" == "togodo" assert str(album) == "foö bar" assert bytes(album) == b"fo\xc3\xb6 bar" config["format_item"] = "bar $foo" item = beets.library.Item() item.foo = "bar" item.tagada = "togodo" assert f"{item}" == "bar bar" assert f"{item:$tagada}" == "togodo" class TestUnicodePath(PytestItemHelper): def test_unicode_path(self, item_in_db): item_in_db.path = _common.RSRC / "unicode\u2019d.mp3" # If there are any problems with unicode paths, we will raise # here and fail. item_in_db.read() item_in_db.write() class TestWrite(TestHelper): def test_write_nonexistant(self): item = self.create_item() item.path = b"/path/does/not/exist" with pytest.raises(beets.library.ReadError): item.write() def test_no_write_permission(self): item = self.add_item_fixture() item.filepath.chmod(stat.S_IRUSR) try: with pytest.raises(beets.library.WriteError) as exc_info: item.write() assert "super:" not in str(exc_info.value) finally: # Restore write permissions so the file can be cleaned up. item.filepath.chmod(stat.S_IRUSR | stat.S_IWUSR) def test_write_with_custom_path(self): item = self.add_item_fixture() custom_path = self.temp_path / "custom.mp3" shutil.copy(item.filepath, custom_path) item["artist"] = "new artist" assert MediaFile(custom_path).artist != "new artist" assert MediaFile(item.filepath).artist != "new artist" item.write(custom_path) assert MediaFile(custom_path).artist == "new artist" assert MediaFile(item.filepath).artist != "new artist" def test_write_custom_tags(self): item = self.add_item_fixture(artist="old artist") item.write(tags={"artist": "new artist"}) assert item.artist != "new artist" assert MediaFile(item.filepath).artist == "new artist" def test_write_multi_tags(self): item = self.add_item_fixture(artist="old artist") item.write(tags={"artists": ["old artist", "another artist"]}) assert MediaFile(item.filepath).artists == [ "old artist", "another artist", ] def test_write_multi_tags_id3v23(self): item = self.add_item_fixture(artist="old artist") item.write( tags={"artists": ["old artist", "another artist"]}, id3v23=True ) assert MediaFile(item.filepath).artists == ["old artist/another artist"] def test_write_date_field(self): # Since `date` is not a MediaField, this should do nothing. item = self.add_item_fixture() clean_year = item.year item.date = "foo" item.write() assert MediaFile(item.filepath).year == clean_year class TestItemRead(PytestItemHelper): def test_unreadable_raise_read_error(self, item_in_db): unreadable = _common.RSRC / "image-2x3.png" with pytest.raises(beets.library.ReadError) as exc_info: item_in_db.read(unreadable) assert isinstance(exc_info.value.reason, UnreadableFileError) def test_nonexistent_raise_read_error(self, item_in_db): with pytest.raises(beets.library.ReadError): item_in_db.read("/thisfiledoesnotexist") def test_read_error_str_includes_reason(self, item_in_db): unreadable = _common.RSRC / "image-2x3.png" with pytest.raises(beets.library.ReadError) as exc_info: item_in_db.read(unreadable) message = str(exc_info.value) assert "super:" not in message assert str(exc_info.value.reason) in message class TestItemReadGenre(TestHelper): def test_read_semicolon_delimited_genres(self): """Semicolon-delimited genre tags are split into individual genres on read.""" path = self.create_mediafile_fixture() mf = MediaFile(path) mf.genres = ["Jazz; Funk; Soul"] mf.save() item = beets.library.Item.from_path(path) assert item.genres == ["Jazz", "Funk", "Soul"] class TestFilesize(TestHelper): def test_filesize(self): item = self.add_item_fixture() assert item.filesize != 0 def test_nonexistent_file(self): item = beets.library.Item() assert item.filesize == 0 class TestItemPruneDirsClutter(TestHelper): """Regression tests: prune_dirs respects config["clutter"] during move/remove.""" def _drop_clutter(self, directory: Path) -> Path: """Create a clutter file in *directory* (bytes path).""" path = directory / "unwanted.log" path.touch() return path def test_move_prunes_dir_with_config_clutter(self): """After moving an item, old dir is removed even when only clutter remains.""" config["clutter"] = ["*.log"] item = self.add_item_fixture() old_dir = item.filepath.parent self._drop_clutter(old_dir) # Change artist so the destination path differs, forcing a real move. item.artist = "new artist" item.store() item.move() assert not old_dir.exists() def test_remove_prunes_dir_with_config_clutter(self): """After deleting an item, its dir is removed even when only clutter remains.""" config["clutter"] = ["*.log"] item = self.add_item_fixture() old_dir = item.filepath.parent self._drop_clutter(old_dir) item.remove(delete=True) assert not old_dir.exists() class TestParseQuery: def test_parse_invalid_query_string(self): with pytest.raises(beets.dbcore.query.ParsingError): beets.library.parse_query_string('foo"', None) def test_parse_bytes(self): with pytest.raises(AssertionError): beets.library.parse_query_string(b"query", None) beetbox-beets-00724b7/test/dbcore/0000775000175000017500000000000015253035401016270 5ustar pieterpieterbeetbox-beets-00724b7/test/dbcore/test_datequery.py0000664000175000017500000002754415253035401021720 0ustar pieterpieter"""Test for dbcore's date-based queries.""" import time import unittest from datetime import datetime, timedelta import pytest from beets.dbcore.query import ( DateInterval, DateQuery, InvalidQueryArgumentValueError, _parse_periods, ) from beets.test.helper import ItemInDBTestCase class TestDateInterval: now = datetime.now().replace(microsecond=0, second=0).isoformat() @pytest.mark.parametrize( "pattern, datestr, include", [ # year precision ("2000..2001", "2000-01-01T00:00:00", True), ("2000..2001", "2001-06-20T14:15:16", True), ("2000..2001", "2001-12-31T23:59:59", True), ("2000..2001", "1999-12-31T23:59:59", False), ("2000..2001", "2002-01-01T00:00:00", False), ("2000..", "2000-01-01T00:00:00", True), ("2000..", "2099-10-11T00:00:00", True), ("2000..", "1999-12-31T23:59:59", False), ("..2001", "2001-12-31T23:59:59", True), ("..2001", "2002-01-01T00:00:00", False), ("-1d..1d", now, True), ("-2d..-1d", now, False), # month precision ("2000-06-20..2000-06-20", "2000-06-20T00:00:00", True), ("2000-06-20..2000-06-20", "2000-06-20T10:20:30", True), ("2000-06-20..2000-06-20", "2000-06-20T23:59:59", True), ("2000-06-20..2000-06-20", "2000-06-19T23:59:59", False), ("2000-06-20..2000-06-20", "2000-06-21T00:00:00", False), # day precision ("1999-12..2000-02", "1999-12-01T00:00:00", True), ("1999-12..2000-02", "2000-02-15T05:06:07", True), ("1999-12..2000-02", "2000-02-29T23:59:59", True), ("1999-12..2000-02", "1999-11-30T23:59:59", False), ("1999-12..2000-02", "2000-03-01T00:00:00", False), # hour precision with 'T' separator ("2000-01-01T12..2000-01-01T13", "2000-01-01T11:59:59", False), ("2000-01-01T12..2000-01-01T13", "2000-01-01T12:00:00", True), ("2000-01-01T12..2000-01-01T13", "2000-01-01T12:30:00", True), ("2000-01-01T12..2000-01-01T13", "2000-01-01T13:30:00", True), ("2000-01-01T12..2000-01-01T13", "2000-01-01T13:59:59", True), ("2000-01-01T12..2000-01-01T13", "2000-01-01T14:00:00", False), ("2000-01-01T12..2000-01-01T13", "2000-01-01T14:30:00", False), # hour precision non-range query ("2008-12-01T22", "2008-12-01T22:30:00", True), ("2008-12-01T22", "2008-12-01T23:30:00", False), # minute precision ("2000-01-01T12:30..2000-01-01T12:31", "2000-01-01T12:29:59", False), ("2000-01-01T12:30..2000-01-01T12:31", "2000-01-01T12:30:00", True), ("2000-01-01T12:30..2000-01-01T12:31", "2000-01-01T12:30:30", True), ("2000-01-01T12:30..2000-01-01T12:31", "2000-01-01T12:31:59", True), ("2000-01-01T12:30..2000-01-01T12:31", "2000-01-01T12:32:00", False), # second precision ("2000-01-01T12:30:50..2000-01-01T12:30:55", "2000-01-01T12:30:49", False), ("2000-01-01T12:30:50..2000-01-01T12:30:55", "2000-01-01T12:30:50", True), ("2000-01-01T12:30:50..2000-01-01T12:30:55", "2000-01-01T12:30:55", True), ("2000-01-01T12:30:50..2000-01-01T12:30:55", "2000-01-01T12:30:56", False), # unbounded # noqa: E501 ("..", datetime.max.isoformat(), True), ("..", datetime.min.isoformat(), True), ("..", "1000-01-01T00:00:00", True), ], ) # fmt: skip def test_intervals(self, pattern, datestr, include): (start, end) = _parse_periods(pattern) interval = DateInterval.from_periods(start, end) assert interval.contains(datetime.fromisoformat(datestr)) == include @pytest.mark.parametrize( "reversed_pattern, forward_pattern", [ ("2001..2000", "2000..2001"), ("2000-02..1999-12", "1999-12..2000-02"), ("2000-01-01T13..2000-01-01T12", "2000-01-01T12..2000-01-01T13"), # Mixed precision. ("2001..2000-06", "2000-06..2001"), ], ) def test_reversed_interval_is_normalised( self, reversed_pattern, forward_pattern ): """A range given back to front means the same as the forward one.""" reversed_ = DateInterval.from_periods(*_parse_periods(reversed_pattern)) forward = DateInterval.from_periods(*_parse_periods(forward_pattern)) assert (reversed_.start, reversed_.end) == (forward.start, forward.end) def _parsetime(s): return time.mktime(datetime.strptime(s, "%Y-%m-%d %H:%M").timetuple()) class DateQueryTest(ItemInDBTestCase): def setUp(self): super().setUp() self.i.added = _parsetime("2013-03-30 22:21") self.i.store() def test_single_month_match_fast(self): query = DateQuery("added", "2013-03") matched = self.lib.items(query) assert len(matched) == 1 def test_single_month_nonmatch_fast(self): query = DateQuery("added", "2013-04") matched = self.lib.items(query) assert len(matched) == 0 def test_single_month_match_slow(self): query = DateQuery("added", "2013-03") assert query.match(self.i) def test_single_month_nonmatch_slow(self): query = DateQuery("added", "2013-04") assert not query.match(self.i) def test_single_day_match_fast(self): query = DateQuery("added", "2013-03-30") matched = self.lib.items(query) assert len(matched) == 1 def test_single_day_nonmatch_fast(self): query = DateQuery("added", "2013-03-31") matched = self.lib.items(query) assert len(matched) == 0 def test_reversed_range_match_fast(self): query = DateQuery("added", "2014..2013") matched = self.lib.items(query) assert len(matched) == 1 def test_reversed_range_match_slow(self): query = DateQuery("added", "2014..2013") assert query.match(self.i) def test_reversed_range_nonmatch_fast(self): query = DateQuery("added", "2012..2011") matched = self.lib.items(query) assert len(matched) == 0 class DateQueryTestRelative(ItemInDBTestCase): def setUp(self): super().setUp() # We pick a date near a month changeover, which can reveal some time # zone bugs. self._now = datetime(2017, 12, 31, 22, 55, 4, 101332) self.i.added = _parsetime(self._now.strftime("%Y-%m-%d %H:%M")) self.i.store() def test_single_month_match_fast(self): query = DateQuery("added", self._now.strftime("%Y-%m")) matched = self.lib.items(query) assert len(matched) == 1 def test_single_month_nonmatch_fast(self): query = DateQuery( "added", (self._now + timedelta(days=30)).strftime("%Y-%m") ) matched = self.lib.items(query) assert len(matched) == 0 def test_single_month_match_slow(self): query = DateQuery("added", self._now.strftime("%Y-%m")) assert query.match(self.i) def test_single_month_nonmatch_slow(self): query = DateQuery( "added", (self._now + timedelta(days=30)).strftime("%Y-%m") ) assert not query.match(self.i) def test_single_day_match_fast(self): query = DateQuery("added", self._now.strftime("%Y-%m-%d")) matched = self.lib.items(query) assert len(matched) == 1 def test_single_day_nonmatch_fast(self): query = DateQuery( "added", (self._now + timedelta(days=1)).strftime("%Y-%m-%d") ) matched = self.lib.items(query) assert len(matched) == 0 class DateQueryTestRelativeMore(ItemInDBTestCase): def setUp(self): super().setUp() self.i.added = _parsetime(datetime.now().strftime("%Y-%m-%d %H:%M")) self.i.store() def test_relative(self): for timespan in ["d", "w", "m", "y"]: query = DateQuery("added", f"-4{timespan}..+4{timespan}") matched = self.lib.items(query) assert len(matched) == 1 def test_relative_fail(self): for timespan in ["d", "w", "m", "y"]: query = DateQuery("added", f"-2{timespan}..-1{timespan}") matched = self.lib.items(query) assert len(matched) == 0 def test_start_relative(self): for timespan in ["d", "w", "m", "y"]: query = DateQuery("added", f"-4{timespan}..") matched = self.lib.items(query) assert len(matched) == 1 def test_start_relative_fail(self): for timespan in ["d", "w", "m", "y"]: query = DateQuery("added", f"4{timespan}..") matched = self.lib.items(query) assert len(matched) == 0 def test_end_relative(self): for timespan in ["d", "w", "m", "y"]: query = DateQuery("added", f"..+4{timespan}") matched = self.lib.items(query) assert len(matched) == 1 def test_end_relative_fail(self): for timespan in ["d", "w", "m", "y"]: query = DateQuery("added", f"..-4{timespan}") matched = self.lib.items(query) assert len(matched) == 0 def test_relative_reversed(self): # `+4d..-4d` is normalised to `-4d..+4d`. for timespan in ["d", "w", "m", "y"]: query = DateQuery("added", f"+4{timespan}..-4{timespan}") matched = self.lib.items(query) assert len(matched) == 1 class DateQueryConstructTest(unittest.TestCase): def test_long_numbers(self): with pytest.raises(InvalidQueryArgumentValueError): DateQuery("added", "1409830085..1412422089") def test_too_many_components(self): with pytest.raises(InvalidQueryArgumentValueError): DateQuery("added", "12-34-56-78") def test_invalid_date_query(self): q_list = [ "2001-01-0a", "2001-0a", "200a", "2001-01-01..2001-01-0a", "2001-0a..2001-01", "200a..2002", "20aa..", "..2aa", ] for q in q_list: with pytest.raises(InvalidQueryArgumentValueError): DateQuery("added", q) def test_pipe_in_relative_date_query(self): # A stray "|" (e.g. a user expecting OR syntax like "added:2000|2001") # must raise a clean InvalidQueryArgumentValueError rather than an # uncaught KeyError from the relative-date parser. for q in ["2000|2001", "1|", "5|3d"]: with pytest.raises(InvalidQueryArgumentValueError): DateQuery("added", q) def test_reversed_date_range(self): # A range whose start lies after its end (e.g. `added:2024..2020`) # is accepted and read as the equivalent forward range, instead of # blowing up with an uncaught ValueError from the interval check. date_query = DateQuery("added", "2024..2020") assert date_query.interval.start == datetime(2020, 1, 1) assert date_query.interval.end == datetime(2025, 1, 1) def test_datetime_uppercase_t_separator(self): date_query = DateQuery("added", "2000-01-01T12") assert date_query.interval.start == datetime(2000, 1, 1, 12) assert date_query.interval.end == datetime(2000, 1, 1, 13) def test_datetime_lowercase_t_separator(self): date_query = DateQuery("added", "2000-01-01t12") assert date_query.interval.start == datetime(2000, 1, 1, 12) assert date_query.interval.end == datetime(2000, 1, 1, 13) def test_datetime_space_separator(self): date_query = DateQuery("added", "2000-01-01 12") assert date_query.interval.start == datetime(2000, 1, 1, 12) assert date_query.interval.end == datetime(2000, 1, 1, 13) def test_datetime_invalid_separator(self): with pytest.raises(InvalidQueryArgumentValueError): DateQuery("added", "2000-01-01x12") beetbox-beets-00724b7/test/dbcore/test_db.py0000664000175000017500000004570215253035401020276 0ustar pieterpieter"""Tests for the DBCore database abstraction.""" import os import shutil import unittest from pathlib import Path from tempfile import mkstemp from typing import ClassVar import pytest from beets import dbcore from beets.dbcore import Index, query, sort, types from beets.dbcore.db import DBCustomFunctionError from beets.library import Album, Item from beets.test.fixtures import ModelFixture1 # Fixture: concrete database and model classes. For migration tests, we # have multiple models with different numbers of fields. @pytest.fixture def db(model): db = model(":memory:") yield db db._connection().close() class DatabaseFixture1(dbcore.Database): _models = (ModelFixture1,) class ModelFixture2(ModelFixture1): _fields: ClassVar[dict[str, dbcore.types.Type]] = { "id": dbcore.types.PRIMARY_ID, "field_one": dbcore.types.INTEGER, "field_two": dbcore.types.INTEGER, } class DatabaseFixture2(dbcore.Database): _models = (ModelFixture2,) class ModelFixture3(ModelFixture1): _fields: ClassVar[dict[str, dbcore.types.Type]] = { "id": dbcore.types.PRIMARY_ID, "field_one": dbcore.types.INTEGER, "field_two": dbcore.types.INTEGER, "field_three": dbcore.types.INTEGER, } class DatabaseFixture3(dbcore.Database): _models = (ModelFixture3,) class ModelFixture4(ModelFixture1): _fields: ClassVar[dict[str, dbcore.types.Type]] = { "id": dbcore.types.PRIMARY_ID, "field_one": dbcore.types.INTEGER, "field_two": dbcore.types.INTEGER, "field_three": dbcore.types.INTEGER, "field_four": dbcore.types.INTEGER, } class DatabaseFixture4(dbcore.Database): _models = (ModelFixture4,) class AnotherModelFixture(ModelFixture1): _table = "another" _flex_table = "anotherflex" _fields: ClassVar[dict[str, dbcore.types.Type]] = { "id": dbcore.types.PRIMARY_ID, "foo": dbcore.types.INTEGER, } _indices = (Index("another_foo_index", ("foo",)),) class ModelFixture5(ModelFixture1): _fields: ClassVar[dict[str, dbcore.types.Type]] = { "some_string_field": dbcore.types.STRING, "some_float_field": dbcore.types.FLOAT, "some_boolean_field": dbcore.types.BOOLEAN, } class DatabaseFixtureTwoModels(dbcore.Database): _models = (ModelFixture2, AnotherModelFixture) class TestDatabasePath: @pytest.mark.parametrize( "path", [":memory:", b":memory:", Path(":memory:")] ) def test_path_inputs_are_stored_as_path(self, path): db = DatabaseFixture1(path) try: assert db.path == Path(":memory:") assert isinstance(db.path, Path) finally: db._connection().close() def test_bytes_filesystem_path_opens_decoded_path(self, tmp_path): db_path = tmp_path / "library.db" db = DatabaseFixture1(db_path) try: assert db.path == db_path assert db_path.exists() finally: db._connection().close() class ModelFixtureWithGetters(dbcore.Model): @classmethod def _getters(cls): return {"aComputedField": (lambda s: "thing")} class MigrationTest(unittest.TestCase): """Tests the ability to change the database schema between versions. """ @classmethod def setUpClass(cls): handle, orig_libfile = mkstemp("orig_db") cls.orig_libfile = Path(orig_libfile) os.close(handle) # Set up a database with the two-field schema. old_lib = DatabaseFixture2(cls.orig_libfile) # Add an item to the old library. old_lib._connection().execute( "insert into test (field_one, field_two) values (4, 2)" ) old_lib._connection().commit() old_lib._connection().close() del old_lib @classmethod def tearDownClass(cls): cls.orig_libfile.unlink() def setUp(self): handle, libfile = mkstemp("db") self.libfile = Path(libfile) os.close(handle) shutil.copyfile(self.orig_libfile, self.libfile) def tearDown(self): self.libfile.unlink() def test_open_with_same_fields_leaves_untouched(self): new_lib = DatabaseFixture2(self.libfile) c = new_lib._connection().cursor() c.execute("select * from test") row = c.fetchone() c.connection.close() assert len(row.keys()) == len(ModelFixture2._fields) def test_open_with_new_field_adds_column(self): new_lib = DatabaseFixture3(self.libfile) c = new_lib._connection().cursor() c.execute("select * from test") row = c.fetchone() c.connection.close() assert len(row.keys()) == len(ModelFixture3._fields) def test_open_with_fewer_fields_leaves_untouched(self): new_lib = DatabaseFixture1(self.libfile) c = new_lib._connection().cursor() c.execute("select * from test") row = c.fetchone() c.connection.close() assert len(row.keys()) == len(ModelFixture2._fields) def test_open_with_multiple_new_fields(self): new_lib = DatabaseFixture4(self.libfile) c = new_lib._connection().cursor() c.execute("select * from test") row = c.fetchone() c.connection.close() assert len(row.keys()) == len(ModelFixture4._fields) def test_extra_model_adds_table(self): new_lib = DatabaseFixtureTwoModels(self.libfile) c = new_lib._connection() c.execute("select * from another") c.close() def test_index_creation(self): """Test that declared indices are created on database initialization.""" db = DatabaseFixture1(":memory:") with db.transaction() as tx: rows = tx.query("PRAGMA index_info(field_one_index)") assert len(rows) > 0 # Index exists db._connection().close() class TransactionTest(unittest.TestCase): def setUp(self): self.db = DatabaseFixture1(":memory:") def tearDown(self): self.db._connection().close() def test_mutate_increase_revision(self): old_rev = self.db.revision with self.db.transaction() as tx: tx.mutate( f"INSERT INTO {ModelFixture1._table} (field_one) VALUES (?);", (111,), ) assert self.db.revision > old_rev def test_query_no_increase_revision(self): old_rev = self.db.revision with self.db.transaction() as tx: tx.query(f"PRAGMA table_info({ModelFixture1._table})") assert self.db.revision == old_rev class ModelTest(unittest.TestCase): def setUp(self): self.db = DatabaseFixture1(":memory:") def tearDown(self): self.db._connection().close() def test_add_model(self): model = ModelFixture1() model.add(self.db) rows = self.db._connection().execute("select * from test").fetchall() assert len(rows) == 1 def test_store_fixed_field(self): model = ModelFixture1() model.add(self.db) model.field_one = 123 model.store() row = self.db._connection().execute("select * from test").fetchone() assert row["field_one"] == 123 def test_revision(self): old_rev = self.db.revision model = ModelFixture1() model.add(self.db) model.store() assert model._revision == self.db.revision assert self.db.revision > old_rev mid_rev = self.db.revision model2 = ModelFixture1() model2.add(self.db) model2.store() assert model2._revision > mid_rev assert self.db.revision > model._revision # revision changed, so the model should be re-loaded model.load() assert model._revision == self.db.revision # revision did not change, so no reload mod2_old_rev = model2._revision model2.load() assert model2._revision == mod2_old_rev def test_retrieve_by_id(self): model = ModelFixture1() model.add(self.db) other_model = self.db._get(ModelFixture1, model.id) assert model.id == other_model.id def test_store_and_retrieve_flexattr(self): model = ModelFixture1() model.add(self.db) model.foo = "bar" model.store() other_model = self.db._get(ModelFixture1, model.id) assert other_model.foo == "bar" def test_store_flexattr_in_fields(self): model = ModelFixture1() model.add(self.db) model.foo = "bar" model.store(fields=["foo"]) other_model = self.db._get(ModelFixture1, model.id) assert other_model.foo == "bar" def test_delete_flexattr(self): model = ModelFixture1() model["foo"] = "bar" assert "foo" in model del model["foo"] assert "foo" not in model def test_delete_flexattr_via_dot(self): model = ModelFixture1() model["foo"] = "bar" assert "foo" in model del model.foo assert "foo" not in model def test_delete_flexattr_persists(self): model = ModelFixture1() model.add(self.db) model.foo = "bar" model.store() model = self.db._get(ModelFixture1, model.id) del model["foo"] model.store() model = self.db._get(ModelFixture1, model.id) assert "foo" not in model def test_delete_non_existent_attribute(self): model = ModelFixture1() with pytest.raises(KeyError): del model["foo"] def test_delete_fixed_attribute(self): model = ModelFixture5() model.some_string_field = "foo" model.some_float_field = 1.23 model.some_boolean_field = True for field, type_ in model._fields.items(): assert model[field] != type_.null for field, type_ in model._fields.items(): del model[field] assert model[field] == type_.null def test_null_value_normalization_by_type(self): model = ModelFixture1() model.field_one = None assert model.field_one == 0 def test_null_value_stays_none_for_untyped_field(self): model = ModelFixture1() model.foo = None assert model.foo is None def test_normalization_for_typed_flex_fields(self): model = ModelFixture1() model.some_float_field = None assert model.some_float_field == 0.0 def test_load_deleted_flex_field(self): model1 = ModelFixture1() model1["flex_field"] = True model1.add(self.db) model2 = self.db._get(ModelFixture1, model1.id) assert "flex_field" in model2 del model1["flex_field"] model1.store() model2.load() assert "flex_field" not in model2 def test_check_db_fails(self): with pytest.raises(ValueError, match="no database"): dbcore.Model()._check_db() with pytest.raises(ValueError, match="no id"): ModelFixture1(self.db)._check_db() dbcore.Model(self.db)._check_db(need_id=False) def test_missing_field(self): with pytest.raises(AttributeError): ModelFixture1(self.db).nonExistingKey def test_computed_field(self): model = ModelFixtureWithGetters() assert model.aComputedField == "thing" with pytest.raises(KeyError, match=r"computed field .+ deleted"): del model.aComputedField def test_items(self): model = ModelFixture1(self.db) model.id = 5 assert {("id", 5), ("field_one", 0), ("field_two", "")} == set( model.items() ) def test_delete_internal_field(self): model = dbcore.Model() del model._db with pytest.raises(AttributeError): model._db def test_parse_nonstring(self): with pytest.raises(TypeError, match="must be a string"): dbcore.Model._parse(None, 42) def test_pickle_dump(self): """Tries to pickle an item. This tests the __getstate__ method of the Model ABC""" import pickle model = ModelFixture1(self.db) model.add(self.db) model.field_one = 123 model.store() assert model._db is not None pickle.dumps(model) class FormatTest(unittest.TestCase): def test_format_fixed_field_integer(self): model = ModelFixture1() model.field_one = 155 value = model.formatted().get("field_one") assert value == "155" def test_format_fixed_field_integer_normalized(self): """The normalize method of the Integer class rounds floats""" model = ModelFixture1() model.field_one = 142.432 value = model.formatted().get("field_one") assert value == "142" model.field_one = 142.863 value = model.formatted().get("field_one") assert value == "143" def test_format_fixed_field_string(self): model = ModelFixture1() model.field_two = "caf\xe9" value = model.formatted().get("field_two") assert value == "caf\xe9" def test_format_flex_field(self): model = ModelFixture1() model.other_field = "caf\xe9" value = model.formatted().get("other_field") assert value == "caf\xe9" def test_format_flex_field_bytes(self): model = ModelFixture1() model.other_field = "caf\xe9".encode() value = model.formatted().get("other_field") assert isinstance(value, str) assert value == "caf\xe9" def test_format_unset_field(self): model = ModelFixture1() value = model.formatted().get("other_field") assert value == "" def test_format_typed_flex_field(self): model = ModelFixture1() model.some_float_field = 3.14159265358979 value = model.formatted().get("some_float_field") assert value == "3.1" class FormattedMappingTest(unittest.TestCase): def test_keys_equal_model_keys(self): model = ModelFixture1() formatted = model.formatted() assert set(model.keys(True)) == set(formatted.keys()) def test_get_unset_field(self): model = ModelFixture1() formatted = model.formatted() with pytest.raises(KeyError): formatted["other_field"] def test_get_method_with_default(self): model = ModelFixture1() formatted = model.formatted() assert formatted.get("other_field") == "" def test_get_method_with_specified_default(self): model = ModelFixture1() formatted = model.formatted() assert formatted.get("other_field", "default") == "default" class ParseTest(unittest.TestCase): def test_parse_fixed_field(self): value = ModelFixture1._parse("field_one", "2") assert isinstance(value, int) assert value == 2 def test_parse_flex_field(self): value = ModelFixture1._parse("some_float_field", "2") assert isinstance(value, float) assert value == 2.0 def test_parse_untyped_field(self): value = ModelFixture1._parse("field_nine", "2") assert value == "2" class TestModelTypeFallback: def test_album_type_falls_back_to_item_type(self): typ = Album._type("artists") assert isinstance(typ, types.DelimitedString) assert typ is types.MULTI_VALUE_DSV def test_album_type_falls_back_to_item_type_other_list_fields(self): for field in ["genres", "composers", "artists_sort"]: typ = Album._type(field) assert isinstance(typ, types.DelimitedString), field def test_item_type_does_not_change(self): typ = Item._type("artists") assert isinstance(typ, types.DelimitedString) def test_unknown_key_falls_through_to_default(self): typ = Album._type("nonexistent_field_xyz") assert isinstance(typ, types.Default) class ResultsIteratorTest(unittest.TestCase): def setUp(self): self.db = DatabaseFixture1(":memory:") model = ModelFixture1() model["foo"] = "baz" model.add(self.db) model = ModelFixture1() model["foo"] = "bar" model.add(self.db) def tearDown(self): self.db._connection().close() def test_iterate_once(self): objs = self.db._get_results(ModelFixture1) assert len(list(objs)) == 2 def test_iterate_twice(self): objs = self.db._get_results(ModelFixture1) list(objs) assert len(list(objs)) == 2 def test_concurrent_iterators(self): results = self.db._get_results(ModelFixture1) it1 = iter(results) it2 = iter(results) next(it1) list(it2) assert len(list(it1)) == 1 def test_slow_query(self): q = query.SubstringQuery("foo", "ba", False) objs = self.db._get_results(ModelFixture1, q) assert len(list(objs)) == 2 def test_slow_query_negative(self): q = query.SubstringQuery("foo", "qux", False) objs = self.db._get_results(ModelFixture1, q) assert len(list(objs)) == 0 def test_iterate_slow_sort(self): s = sort.SlowFieldSort("foo") res = self.db._get_results(ModelFixture1, sort=s) objs = list(res) assert objs[0].foo == "bar" assert objs[1].foo == "baz" def test_unsorted_subscript(self): objs = self.db._get_results(ModelFixture1) assert objs[0].foo == "baz" assert objs[1].foo == "bar" def test_slow_sort_subscript(self): s = sort.SlowFieldSort("foo") objs = self.db._get_results(ModelFixture1, sort=s) assert objs[0].foo == "bar" assert objs[1].foo == "baz" def test_negative_subscript(self): objs = self.db._get_results(ModelFixture1) assert objs[-1].foo == "bar" assert objs[-2].foo == "baz" def test_slice(self): objs = self.db._get_results(ModelFixture1) assert [obj.foo for obj in objs[:]] == ["baz", "bar"] assert [obj.foo for obj in objs[1:]] == ["bar"] assert [obj.foo for obj in objs[::-1]] == ["bar", "baz"] def test_length(self): objs = self.db._get_results(ModelFixture1) assert len(objs) == 2 def test_out_of_range(self): objs = self.db._get_results(ModelFixture1) with pytest.raises(IndexError): objs[100] def test_no_results(self): assert ( self.db._get_results(ModelFixture1, query.FalseQuery()).get() is None ) class TestException: @pytest.mark.parametrize("model", [DatabaseFixture1]) @pytest.mark.filterwarnings( "ignore: .*plz_raise.*: pytest.PytestUnraisableExceptionWarning" ) @pytest.mark.filterwarnings( "error: .*: pytest.PytestUnraisableExceptionWarning" ) def test_custom_function_error(self, db: DatabaseFixture1): def plz_raise(): raise Exception("i haz raized") db._connection().create_function("plz_raise", 0, plz_raise) with db.transaction() as tx: tx.mutate("insert into test (field_one) values (1)") with pytest.raises(DBCustomFunctionError): with db.transaction() as tx: tx.query("select * from test where plz_raise()") beetbox-beets-00724b7/test/dbcore/test_queryparse.py0000664000175000017500000001264615253035401022112 0ustar pieterpieter"""Tests for dbcore query parsing helpers.""" import unittest from beets import dbcore from beets.dbcore import query, sort from beets.test.fixtures import ModelFixture1, SortFixture class QueryParseTest(unittest.TestCase): def pqp(self, part): return dbcore.queryparse.parse_query_part( part, {"year": query.NumericQuery}, {":": query.RegexpQuery} )[:-1] # remove the negate flag def test_one_basic_term(self): q = "test" r = (None, "test", query.SubstringQuery) assert self.pqp(q) == r def test_one_keyed_term(self): q = "test:val" r = ("test", "val", query.SubstringQuery) assert self.pqp(q) == r def test_colon_at_end(self): q = "test:" r = ("test", "", query.SubstringQuery) assert self.pqp(q) == r def test_one_basic_regexp(self): q = r":regexp" r = (None, "regexp", query.RegexpQuery) assert self.pqp(q) == r def test_keyed_regexp(self): q = r"test::regexp" r = ("test", "regexp", query.RegexpQuery) assert self.pqp(q) == r def test_escaped_colon(self): q = r"test\:val" r = (None, "test:val", query.SubstringQuery) assert self.pqp(q) == r def test_escaped_colon_in_regexp(self): q = r":test\:regexp" r = (None, "test:regexp", query.RegexpQuery) assert self.pqp(q) == r def test_single_year(self): q = "year:1999" r = ("year", "1999", query.NumericQuery) assert self.pqp(q) == r def test_multiple_years(self): q = "year:1999..2010" r = ("year", "1999..2010", query.NumericQuery) assert self.pqp(q) == r def test_empty_query_part(self): q = "" r = (None, "", query.SubstringQuery) assert self.pqp(q) == r class QueryFromStringsTest(unittest.TestCase): def qfs(self, strings): return dbcore.queryparse.query_from_strings( query.AndQuery, ModelFixture1, {":": query.RegexpQuery}, strings ) def test_zero_parts(self): q = self.qfs([]) assert isinstance(q, query.AndQuery) assert len(q.subqueries) == 1 assert isinstance(q.subqueries[0], query.TrueQuery) def test_two_parts(self): q = self.qfs(["foo", "bar:baz"]) assert isinstance(q, query.AndQuery) assert len(q.subqueries) == 2 assert isinstance(q.subqueries[0], query.OrQuery) assert isinstance(q.subqueries[1], query.SubstringQuery) def test_parse_fixed_type_query(self): q = self.qfs(["field_one:2..3"]) assert isinstance(q.subqueries[0], query.NumericQuery) def test_parse_flex_type_query(self): q = self.qfs(["some_float_field:2..3"]) assert isinstance(q.subqueries[0], query.NumericQuery) def test_empty_query_part(self): q = self.qfs([""]) assert isinstance(q.subqueries[0], query.TrueQuery) class SortFromStringsTest(unittest.TestCase): def sfs(self, strings): return dbcore.queryparse.sort_from_strings(ModelFixture1, strings) def test_zero_parts(self): s = self.sfs([]) assert isinstance(s, sort.NullSort) assert s == sort.NullSort() def test_one_parts(self): s = self.sfs(["field+"]) assert isinstance(s, sort.Sort) def test_two_parts(self): s = self.sfs(["field+", "another_field-"]) assert isinstance(s, sort.MultipleSort) assert len(s.sorts) == 2 def test_fixed_field_sort(self): s = self.sfs(["field_one+"]) assert isinstance(s, sort.FixedFieldSort) assert s == sort.FixedFieldSort("field_one") def test_flex_field_sort(self): s = self.sfs(["flex_field+"]) assert isinstance(s, sort.SlowFieldSort) assert s == sort.SlowFieldSort("flex_field") def test_special_sort(self): s = self.sfs(["some_sort+"]) assert isinstance(s, SortFixture) class ParseSortedQueryTest(unittest.TestCase): def psq(self, parts): return dbcore.parse_sorted_query(ModelFixture1, parts.split()) def test_and_query(self): q, s = self.psq("foo bar") assert isinstance(q, query.AndQuery) assert isinstance(s, sort.NullSort) assert len(q.subqueries) == 2 def test_or_query(self): q, s = self.psq("foo , bar") assert isinstance(q, query.OrQuery) assert isinstance(s, sort.NullSort) assert len(q.subqueries) == 2 def test_no_space_before_comma_or_query(self): q, s = self.psq("foo, bar") assert isinstance(q, query.OrQuery) assert isinstance(s, sort.NullSort) assert len(q.subqueries) == 2 def test_no_spaces_or_query(self): q, s = self.psq("foo,bar") assert isinstance(q, query.AndQuery) assert isinstance(s, sort.NullSort) assert len(q.subqueries) == 1 def test_trailing_comma_or_query(self): q, s = self.psq("foo , bar ,") assert isinstance(q, query.OrQuery) assert isinstance(s, sort.NullSort) assert len(q.subqueries) == 3 def test_leading_comma_or_query(self): q, s = self.psq(", foo , bar") assert isinstance(q, query.OrQuery) assert isinstance(s, sort.NullSort) assert len(q.subqueries) == 3 def test_only_direction(self): q, s = self.psq("-") assert isinstance(q, query.AndQuery) assert isinstance(s, sort.NullSort) assert len(q.subqueries) == 1 beetbox-beets-00724b7/test/dbcore/test_types.py0000664000175000017500000000464415253035401021055 0ustar pieterpieterimport time import pytest import beets from beets.dbcore import types from beets.util import normpath def test_datetype(): t = types.DATE # format time_format = beets.config["time_format"].as_str() time_local = time.strftime(time_format, time.localtime(123456789)) assert time_local == t.format(123456789) # parse assert 123456789.0 == t.parse(time_local) assert 123456789.0 == t.parse("123456789.0") assert t.null == t.parse("not123456789.0") assert t.null == t.parse("1973-11-29") def test_pathtype(): t = types.PathType() # format assert "/tmp" == t.format("/tmp") assert "/tmp/\xe4lbum" == t.format("/tmp/\u00e4lbum") # parse assert normpath(b"/tmp") == t.parse("/tmp") assert normpath(b"/tmp/\xc3\xa4lbum") == t.parse("/tmp/\u00e4lbum/") def test_musicalkey(): t = types.MusicalKey() # parse assert "C#m" == t.parse("c#m") assert "Gm" == t.parse("g minor") assert "Not c#m" == t.parse("not C#m") def test_durationtype(): t = types.DurationType() # format assert "1:01" == t.format(61.23) assert "60:01" == t.format(3601.23) assert "0:00" == t.format(None) # parse assert 61.0 == t.parse("1:01") assert 61.23 == t.parse("61.23") assert 3601.0 == t.parse("60:01") assert t.null == t.parse("1:00:01") assert t.null == t.parse("not61.23") # config format_raw_length beets.config["format_raw_length"] = True assert "61.23" == t.format(61.23) assert "3601.23" == t.format(3601.23) @pytest.mark.parametrize( "original, expected", [ # single element with embedded "; " is expanded (["Jazz; Folk; Soul"], ["Jazz", "Folk", "Soul"]), # already-correct list passes through unchanged (["Jazz", "Folk"], ["Jazz", "Folk"]), # mixed: only the delimited element is expanded (["Jazz; Folk", "Soul"], ["Jazz", "Folk", "Soul"]), # None -> null (empty list) (None, []), # no false split: value without "; " is unchanged (["Smith, John"], ["Smith, John"]), # plain string gets wrapped (not split into characters) ("Charli XCX", ["Charli XCX"]), # string with delimiter gets split ("Jazz; Folk; Soul", ["Jazz", "Folk", "Soul"]), # empty string ("", []), ], ) def test_delimitedstring_normalize(original, expected): assert types.MULTI_VALUE_DSV.normalize(original) == expected beetbox-beets-00724b7/test/dbcore/test_sort.py0000664000175000017500000002316715253035401020701 0ustar pieterpieter"""Various tests for querying the library database.""" import pytest import beets.library from beets import util from beets.dbcore import types from beets.dbcore.query import TrueQuery from beets.dbcore.sort import FixedFieldSort, SlowFieldSort from beets.library import Album, Item from beets.test import _common _p = pytest.param def abs_test_path(path: str) -> bytes: return util.normpath(path) @pytest.fixture(scope="class") def helper(class_helper): return class_helper @pytest.fixture(scope="class") def setup_library(request: pytest.FixtureRequest, helper): album_ids = [ helper.lib.add( Album( id=id_, album=album, genres=genres, year=year, flex1=flex1, flex2=flex2, albumartist=albumartist, artpath=abs_test_path(f"{id_}cover.jpg"), ) ) for id_, album, genres, year, flex1, flex2, albumartist in ( [1, "Album A", ["Rock"], 2001, "Flex1-1", "Flex2-A", "Foo"], [2, "Album B", ["Rock"], 2002, "Flex1-2", "Flex2-A", "Bar"], [3, "Album C", ["Jazz"], 2005, "Flex1-1", "Flex2-B", "Baz"], ) ] for item in [ _common.item( id=1, title="first", artist="One", album="Album A", year=2001, flex1="Flex1-0", flex2="Flex2-A", album_id=album_ids[0], path=abs_test_path("/path0.mp3"), track=1, ), _common.item( id=2, title="second", artist="Two", album="Album A", year=2002, flex1="Flex1-1", flex2="Flex2-A", album_id=album_ids[0], path=abs_test_path("/patH1.mp3"), track=2, ), _common.item( id=3, title="third", artist="Three", album="Album B", year=2003, flex1="Flex1-2", flex2="Flex1-B", album_id=album_ids[1], path=abs_test_path("/paTH2.mp3"), track=3, ), _common.item( id=4, title="fourth", artist="Three", album="Album C", year=2004, flex1="Flex1-2", flex2="Flex1-C", album_id=album_ids[2], path=abs_test_path("/PATH3.mp3"), track=4, ), ]: helper.lib.add(item) request.cls.lib = helper.lib @pytest.mark.usefixtures("setup_library") class TestSort: @pytest.mark.parametrize( "model,query,expected_ids", [ _p(Album, "year+", [1, 2, 3], id="fixed"), _p(Album, "flex1-", [2, 1, 3], id="flex"), _p(Album, "path+", [1, 2, 3], id="calculated"), _p(Album, "year-", [3, 2, 1], id="fixed-desc"), _p(Album, "genres+ album+", [3, 1, 2], id="multi-fixed-field"), _p(Album, "flex2+ flex1+", [1, 2, 3], id="multi-flex-field"), _p(Album, "path+ year+", [1, 2, 3], id="computed"), _p(Album, "year+ path+", [1, 2, 3], id="computed-reverse"), _p(Item, "flex2- flex1+", [1, 2, 4, 3], id="item-multi-flex-field"), _p(Item, "artpath+", [1, 2, 3, 4], id="item-album-field"), _p(Item, "artpath-", [4, 3, 1, 2], id="item-album-field-reverse"), ], ) def test_sort(self, model, query, expected_ids): results = self.lib._fetch(model, query, None) assert [r.id for r in results] == expected_ids def test_sort_path_field(self): results = self.lib.items("", FixedFieldSort("path", True)) expected_paths = [ b"/path0.mp3", b"/patH1.mp3", b"/paTH2.mp3", b"/PATH3.mp3", ] expected_paths_with_prefix = list(map(util.normpath, expected_paths)) assert [i.path for i in results] == expected_paths_with_prefix def test_config_defaults(self): artists = [r.artist for r in self.lib.items()] albumartists = [r.albumartist for r in self.lib.albums()] assert artists == ["One", "Three", "Three", "Two"] assert albumartists == ["Bar", "Baz", "Foo"] def test_config_overrides(self, config): config.set({"sort_item": "artist-", "sort_album": "albumartist-"}) artists = [r.artist for r in self.lib.items()] albumartists = [r.albumartist for r in self.lib.albums()] assert artists == ["Two", "Three", "Three", "One"] assert albumartists == ["Foo", "Baz", "Bar"] class TestCaseSensitivity: """If case_insensitive is false, lower-case values should be placed after all upper-case values. E.g., `Foo Qux bar` """ @pytest.fixture(autouse=True, scope="class") def setup(self, helper): helper.lib.add(Album(album="album", albumartist="bar")) helper.lib.add(Album(album="Album", albumartist="Bar")) helper.add_item(artist="artist", flex1="flex1", track=10) helper.add_item(artist="Artist", flex1="Flex1", track=2) @pytest.mark.parametrize( "getter,query,attr,expected_insensitive,expected_sensitive", [ _p( "items", "artist+", "artist", ["artist", "Artist"], ["Artist", "artist"], id="smart-artist-case", ), _p( "albums", "album+", "album", ["album", "Album"], ["Album", "album"], id="fixed-field-case", ), _p( "items", "flex1+", "flex1", ["flex1", "Flex1"], ["Flex1", "flex1"], id="flex-field-case", ), ], ) def test_text_field_case_sorting( self, config, getter, query, attr, expected_insensitive, expected_sensitive, helper, ): config["sort_case_insensitive"] = True results = getattr(helper.lib, getter)(query) assert [r[attr] for r in results] == expected_insensitive config["sort_case_insensitive"] = False results = getattr(helper.lib, getter)(query) assert [r[attr] for r in results] == expected_sensitive def test_case_sensitive_only_affects_text(self, config, helper): config["sort_case_insensitive"] = True results = helper.lib.items("track+") # If the numerical values were sorted as strings, # then ['10', '2'] would be valid. assert [r.track for r in results] == [2, 10] @pytest.mark.usefixtures("setup_library") class TestNonExistingField: """Test sorting by non-existing fields""" @pytest.mark.parametrize( "q", ["foo+", "foo-", "--", "-+", "+-", "++", "-foo-", "-foo+", "---"] ) def test_non_existing_fields_not_fail(self, q): expected_ids = [i.id for i in self.lib.items("foo+")] actual_ids = [i.id for i in self.lib.items(q)] assert actual_ids == expected_ids def test_combined_non_existing_field(self): expected_ids = [i.id for i in self.lib.items("id+")] actual_ids = [i.id for i in self.lib.items("foo+ id+")] assert actual_ids == expected_ids def test_field_present_in_some_items(self, monkeypatch): """Test ordering by an int-type field not present on all items.""" monkeypatch.setitem(Item._types, "myint", types.Integer()) lower_item, higher_item, *items_without_val = self.lib.items("id+") for item, value in zip((lower_item, higher_item), (2, 10)): item.myint = value item.store() null_values_ids = [i.id for i in items_without_val] ids_asc = [i.id for i in self.lib.items("myint+ id+")] ids_desc = [i.id for i in self.lib.items("myint- id+")] assert ids_asc == [*null_values_ids, lower_item.id, higher_item.id] assert ids_desc == [higher_item.id, lower_item.id, *null_values_ids] @pytest.mark.parametrize( "field_type,lower,higher", [ _p(types.NullInteger(), 2, 10, id="null-integer"), _p(types.NullFloat(), 2.5, 10.5, id="null-float"), ], ) def test_nullable_field_present_in_some_items( self, monkeypatch, field_type, lower, higher ): """Ordering by a nullable-typed field (whose null value is ``None``) that is present on only some items should not raise. See #3461. """ monkeypatch.setitem(Item._types, "mynull", field_type) lower_item, higher_item, *items_without_val = self.lib.items("id+") for item, value in zip((lower_item, higher_item), (lower, higher)): item.mynull = value item.store() null_values_ids = [i.id for i in items_without_val] ids_asc = [i.id for i in self.lib.items("mynull+ id+")] ids_desc = [i.id for i in self.lib.items("mynull- id+")] assert ids_asc == [*null_values_ids, lower_item.id, higher_item.id] assert ids_desc == [higher_item.id, lower_item.id, *null_values_ids] def test_negation_interaction(self): """Test the handling of negation and sorting together. If a string ends with a sorting suffix, it takes precedence over the NotQuery parsing. """ query, sort = beets.library.parse_query_string( "-bar+", beets.library.Item ) assert len(query.subqueries) == 1 assert isinstance(query.subqueries[0], TrueQuery) assert isinstance(sort, SlowFieldSort) assert sort.field == "-bar" beetbox-beets-00724b7/test/dbcore/__init__.py0000664000175000017500000000000015253035401020367 0ustar pieterpieterbeetbox-beets-00724b7/test/dbcore/test_query.py0000664000175000017500000005341615253035401021057 0ustar pieterpieter"""Various tests for querying the library database.""" import logging import os import sys from functools import partial from pathlib import Path import pytest from beets import util from beets.dbcore import AndQuery, MatchQuery, OrQuery, types from beets.dbcore.query import ( BooleanQuery, DateQuery, FalseQuery, InQuery, NoneQuery, NotQuery, NumericQuery, ParsingError, PathQuery, RegexpQuery, StringFieldQuery, StringQuery, SubstringQuery, TrueQuery, ) from beets.library import Item from beets.test import _common # Because the absolute path begins with something like C:, we # can't disambiguate it from an ordinary query. WIN32_NO_IMPLICIT_PATHS = "Implicit paths are not supported on Windows" _p = pytest.param @pytest.fixture(scope="class") def helper(class_helper): """Use class scope because each query class owns a library shape. Class fixtures add rows, albums, flex types, paths, or media files and then query whole collections, so sibling class data would change expectations. """ return class_helper class TestGet: @pytest.fixture(scope="class") def lib(self, helper): album_items = [ helper.create_item( title="first", artist="one", artists=["one", "eleven"], album="baz", year=2001, comp=True, genres=["rock"], composers=["composer"], ), helper.create_item( title="second", artist="two", artists=["two", "twelve"], album="baz", year=2002, comp=True, genres=["Rock"], ), ] album = helper.lib.add_album(album_items) album.albumflex = "foo" album.store() helper.add_item( title="third", artist="three", artists=["three", "one"], album="foo", year=2003, comp=False, genres=["Hard Rock"], comments="caf\xe9", Flex_Attr="flex", ) return helper.lib @pytest.mark.parametrize( "q, expected_titles", [ ("", ["first", "second", "third"]), (None, ["first", "second", "third"]), (":oNE", []), (":one", ["first"]), (":sec :ond", ["second"]), (":second", ["second"]), ("=rock", ["first"]), ('=~"hard rock"', ["third"]), (":t$", ["first"]), ("oNE", ["first"]), ("baz", ["first", "second"]), ("sec ond", ["second"]), ("three", ["third"]), ("albumflex:foo", ["first", "second"]), ("artist::t.+r", ["third"]), ("artist:thrEE", ["third"]), ("artists::eleven", ["first"]), ("artists::one", ["first", "third"]), ("ArTiST:three", ["third"]), ("comments:caf\xe9", ["third"]), ("comp:true", ["first", "second"]), ("comp:false", ["third"]), ("flex_attr:flex", ["third"]), ("Flex_Attr:flex", ["third"]), ("genres:=rock", ["first"]), ("genres:=Rock", ["second"]), ('genres:="Hard Rock"', ["third"]), ('genres:=~"hard rock"', ["third"]), ("genres:=~rock", ["first", "second"]), ('genres:="hard rock"', []), ("popebear", []), ("pope:bear", []), ("singleton:true", ["third"]), ("singleton:1", ["third"]), ("singleton:false", ["first", "second"]), ("singleton:0", ["first", "second"]), ("title:ond", ["second"]), ("title::sec", ["second"]), ("year:2001", ["first"]), ("year:2000..2002", ["first", "second"]), ("xyzzy:nonsense", []), ], ) def test_get_query(self, lib, q, expected_titles): assert {i.title for i in lib.items(q)} == set(expected_titles) @pytest.mark.parametrize( "q, expected_titles", [ (BooleanQuery("comp", True), ("third",)), (DateQuery("added", "2000-01-01"), ("first", "second", "third")), (FalseQuery(), ("first", "second", "third")), (MatchQuery("year", "2003"), ("first", "second")), (NoneQuery("rg_track_gain"), ()), (NumericQuery("year", "2001..2002"), ("third",)), ( AndQuery( [BooleanQuery("comp", True), NumericQuery("year", "2002")] ), ("first", "third"), ), ( OrQuery( [BooleanQuery("comp", True), NumericQuery("year", "2002")] ), ("third",), ), (RegexpQuery("artist", "^t"), ("first",)), (SubstringQuery("album", "ba"), ("third",)), (TrueQuery(), ()), ], ) def test_query_logic(self, lib, q, expected_titles): def get_results(*args): return {i.title for i in lib.items(*args)} # not(a and b) <-> not(a) or not(b) not_q = NotQuery(q) not_q_results = get_results(not_q) assert not_q_results == set(expected_titles) # assert using OrQuery, AndQuery q_or = OrQuery([q, not_q]) q_and = AndQuery([q, not_q]) assert get_results(q_or) == {"first", "second", "third"} assert get_results(q_and) == set() # assert manually checking the item titles all_titles = get_results() q_results = get_results(q) assert q_results.union(not_q_results) == all_titles assert q_results.intersection(not_q_results) == set() # round trip not_not_q = NotQuery(not_q) assert get_results(q) == get_results(not_not_q) @pytest.mark.parametrize( "q, expected_titles", [ ("-artist::t.+r", ["first", "second"]), ("-:t$", ["second", "third"]), ("sec -bar", ["second"]), ("sec -title:bar", ["second"]), ("-ond", ["first", "third"]), ("^ond", ["first", "third"]), ("^title:sec", ["first", "third"]), ("-title:sec", ["first", "third"]), ], ) def test_negation_prefix(self, lib, q, expected_titles): actual_titles = {i.title for i in lib.items(q)} assert actual_titles == set(expected_titles) @pytest.mark.parametrize( "make_q", [ partial(DateQuery, "added", "2001-01-01"), partial(MatchQuery, "artist", "one"), partial(NoneQuery, "rg_track_gain"), partial(NumericQuery, "year", "2002"), partial(StringQuery, "year", "2001"), partial(RegexpQuery, "album", "^.a"), partial(SubstringQuery, "title", "x"), ], ) def test_fast_vs_slow(self, lib, make_q): """Test that the results are the same regardless of the `fast` flag for negated `FieldQuery`s. """ q_fast = make_q(True) q_slow = make_q(False) assert list(map(dict, lib.items(q_fast))) == list( map(dict, lib.items(q_slow)) ) @pytest.mark.parametrize( "q, legacy_field", [ pytest.param("genres::rock", None, id="non-legacy-genres-field"), pytest.param("genre::rock", "genre", id="legacy-genre-field"), pytest.param( "composers::composer", None, id="non-legacy-composer-field" ), pytest.param( "composer::composer", "composer", id="legacy-composer-field" ), ], ) def test_legacy_field(self, caplog, lib, q, legacy_field): with caplog.at_level(logging.WARNING, logger="beets"): actual_titles = {i.title for i in lib.items(q)} assert actual_titles == {"first"} if legacy_field: assert caplog.records, "No log records were captured" assert len(caplog.records) == 1 message = str(caplog.records[0].msg) assert f"The '{legacy_field}' field is deprecated" in message assert f"Use '{legacy_field}s' instead." in message class TestMatch: @pytest.fixture(scope="class") def item(self): return _common.item( album="the album", disc=6, year=1, bitrate=128000, genres=["Classical", "Baroque"], ) @pytest.mark.parametrize( "q, should_match", [ (RegexpQuery("album", "^the album$"), True), (RegexpQuery("album", "^album$"), False), (RegexpQuery("disc", "^6$"), True), (SubstringQuery("album", "album"), True), (SubstringQuery("album", "ablum"), False), (SubstringQuery("disc", "6"), True), (StringQuery("album", "the album"), True), (StringQuery("album", "THE ALBUM"), True), (StringQuery("album", "album"), False), (MatchQuery("genres", "Classical"), True), (MatchQuery("genres", "Neoclassical"), False), (StringQuery("genres", "classical"), True), (StringQuery("genres", "neoclassical"), False), (NumericQuery("year", "1"), True), (NumericQuery("year", "10"), False), (NumericQuery("bitrate", "100000..200000"), True), (NumericQuery("bitrate", "200000..300000"), False), (NumericQuery("bitrate", "100000.."), True), ], ) def test_match(self, item, q, should_match): assert q.match(item) == should_match assert not NotQuery(q).match(item) == should_match class TestPathQuery: """Tests for path-based querying functionality in the database system. Verifies that path queries correctly match items by their file paths, handling special characters, case sensitivity, parent directories, and path separator detection across different platforms. """ @staticmethod def abs_query_path(path: str, trailing_sep: bool = False) -> str: """Build a platform-correct absolute query path without normalizing it. On Windows, leading-slash paths are drive-rooted but Python 3.13 no longer treats them as absolute. Prefix the current drive so explicit path queries stay absolute while preserving raw segments such as ``..``. """ if os.path.__name__ == "ntpath" and path.startswith("/"): drive, _ = os.path.splitdrive(os.fsdecode(util.normpath(os.sep))) path = drive + path path = path.replace("/", os.sep) if trailing_sep: path = os.path.join(path, "") return path.replace("\\", "\\\\") @pytest.fixture(scope="class") def lib(self, helper): helper.add_item(path=b"/aaa/bb/c.mp3", title="path item") helper.add_item(path=b"/x/y/z.mp3", title="another item") helper.add_item(path=b"/c/_/title.mp3", title="with underscore") helper.add_item(path=b"/c/%/title.mp3", title="with percent") helper.add_item(path=rb"/c/\x/title.mp3", title="with backslash") helper.add_item(path=b"/A/B/C2.mp3", title="caps path") return helper.lib @pytest.mark.parametrize( "path, expected_titles, trailing_sep", [ _p("/aaa/bb/c.mp3", ["path item"], False, id="exact-match"), _p("/aaa", ["path item"], False, id="parent-dir-no-slash"), _p("/aaa", ["path item"], True, id="parent-dir-with-slash"), _p("/aa", [], False, id="no-match-does-not-match-parent-dir"), _p("/xyzzy", [], True, id="no-match"), _p("/b", [], True, id="fragment-no-match"), _p("/x/../aaa/bb", ["path item"], False, id="non-normalized"), _p(r"c\.mp3$", ["path item"], False, id="regex"), _p("/c/_", ["with underscore"], False, id="underscore-escaped"), _p("/c/%", ["with percent"], False, id="percent-escaped"), _p(r"/c/\x", ["with backslash"], False, id="backslash-escaped"), ], ) def test_explicit( self, monkeypatch, lib, path, expected_titles, trailing_sep ): """Test explicit path queries with different path specifications.""" monkeypatch.setattr("beets.util.case_sensitive", lambda *_: True) if path == r"c\.mp3$": q = f"path::{path}" elif path == r"/c/\x" and os.path.__name__ != "ntpath": q = r"path:/c/\\x" else: q = f"path:{self.abs_query_path(path, trailing_sep=trailing_sep)}" assert {i.title for i in lib.items(q)} == set(expected_titles) @pytest.mark.parametrize( "query", ["path:", "path::"], ids=["path", "regex"] ) def test_absolute(self, lib, helper, query): item_path = helper.lib_path / "item.mp3" bytes_path = os.fsencode(item_path) helper.add_item(path=bytes_path, title="absolute item") q = f"{query}{item_path}".replace("\\", "\\\\") assert {i.title for i in lib.items(q)} == {"absolute item"} def test_relative(self, lib, helper): item_path = helper.lib_path / "relative" / "item.mp3" bytes_path = os.fsencode(item_path) helper.add_item(path=bytes_path, title="relative item") q = "path:relative/item.mp3" assert {i.title for i in lib.items(q)} == {"relative item"} @pytest.mark.skipif(sys.platform == "win32", reason=WIN32_NO_IMPLICIT_PATHS) @pytest.mark.parametrize( "q, expected_titles", [ _p("/aaa/bb", ["path item"], id="slashed-query"), _p("/aaa/bb , /aaa", ["path item"], id="path-in-or-query"), _p("c.mp3", [], id="no-slash-no-match"), _p("title:/a/b", [], id="slash-with-explicit-field-no-match"), ], ) def test_implicit(self, monkeypatch, lib, q, expected_titles): """Test implicit path detection when queries contain path separators.""" monkeypatch.setattr( "beets.dbcore.query.PathQuery.is_path_query", lambda path: True ) assert {i.title for i in lib.items(q)} == set(expected_titles) @pytest.mark.parametrize( "case_sensitive, expected_titles", [ _p(True, [], id="non-caps-dont-match-caps"), _p(False, ["caps path"], id="non-caps-match-caps"), ], ) def test_case_sensitivity( self, lib, monkeypatch, case_sensitive, expected_titles ): """Test path matching with different case sensitivity settings.""" q = f"path:{self.abs_query_path('/a/b/c2.mp3')}" monkeypatch.setattr( "beets.util.case_sensitive", lambda *_: case_sensitive ) assert {i.title for i in lib.items(q)} == set(expected_titles) # FIXME: Also create a variant of this test for windows, which tests # both os.sep and os.altsep @pytest.mark.skipif(sys.platform == "win32", reason=WIN32_NO_IMPLICIT_PATHS) @pytest.mark.parametrize( "q, is_path_query", [ ("/foo/bar", True), ("foo/bar", True), ("foo/", True), ("foo", False), ("foo/:bar", True), ("foo:bar/", False), ("foo:/bar", False), ], ) def test_path_sep_detection(self, monkeypatch, tmp_path, q, is_path_query): """Test detection of path queries based on the presence of path separators.""" monkeypatch.chdir(tmp_path) (tmp_path / "foo").mkdir() (tmp_path / "foo" / "bar").touch() if Path(q).is_absolute(): q = str(tmp_path / q[1:]) assert PathQuery.is_path_query(q) == is_path_query class TestQuery: ALBUM = "album title" SINGLE = "singleton" @pytest.fixture(scope="class") def lib(self, helper): helper.add_album( title=self.ALBUM, comp=True, flexbool=True, bpm=120, flexint=2, rg_track_gain=0, ) helper.add_item( title=self.SINGLE, comp=False, flexbool=False, rg_track_gain=None ) with pytest.MonkeyPatch.context() as monkeypatch: monkeypatch.setattr( Item, "_types", {"flexbool": types.Boolean(), "flexint": types.Integer()}, ) yield helper.lib @pytest.mark.parametrize("query_class", [MatchQuery, StringFieldQuery]) def test_equality(self, query_class): assert query_class("foo", "bar") == query_class("foo", "bar") def test_in_query_hashable(self): # smartplaylist puts queries in a set; an InQuery whose pattern is a # list used to raise `unhashable type: 'list'`. See #5354. query = InQuery("field", [1, 2, 3]) assert query in {query} @pytest.mark.parametrize( "make_q, expected_msg", [ (lambda: NumericQuery("year", "199a"), "not an int"), (lambda: RegexpQuery("year", "199("), r"not a regular expression.*unterminated subpattern"), # noqa: E501 ] ) # fmt: skip def test_invalid_query(self, make_q, expected_msg): with pytest.raises(ParsingError, match=expected_msg): make_q() @pytest.mark.parametrize( "q, expected_titles", [ # Boolean value _p("comp:true", {ALBUM}, id="parse-true"), _p("flexbool:true", {ALBUM}, id="flex-parse-true"), _p("flexbool:false", {SINGLE}, id="flex-parse-false"), _p("flexbool:1", {ALBUM}, id="flex-parse-1"), _p("flexbool:0", {SINGLE}, id="flex-parse-0"), # TODO: shouldn't this match 1 / true instead? _p("flexbool:something", {SINGLE}, id="flex-parse-true"), # Integer value _p("bpm:120", {ALBUM}, id="int-exact-value"), _p("bpm:110..125", {ALBUM}, id="int-range"), _p("flexint:2", {ALBUM}, id="int-flex"), _p("flexint:3", set(), id="int-no-match"), _p("bpm:12", set(), id="int-dont-match-substring"), # None value _p(NoneQuery("album_id"), {SINGLE}, id="none-match-singleton"), _p(NoneQuery("rg_track_gain"), {SINGLE}, id="none-value"), ], ) def test_value_type(self, lib, q, expected_titles): assert {i.title for i in lib.items(q)} == expected_titles class TestDefaultSearchFields: @pytest.fixture(scope="class") def lib(self, helper): helper.add_album( title="title", album="album", albumartist="albumartist", catalognum="catalognum", year=2001, ) return helper.lib @pytest.mark.parametrize( "entity, q, should_match", [ _p("albums", "album", True, id="album-match-album"), _p("albums", "albumartist", True, id="album-match-albumartist"), _p("albums", "catalognum", False, id="album-dont-match-catalognum"), _p("items", "title", True, id="item-match-title"), _p("items", "2001", False, id="item-dont-match-year"), ], ) def test_search(self, lib, entity, q, should_match): assert bool(getattr(lib, entity)(q)) == should_match class TestRelatedQueries: """Test album-level queries with track-level filters and vice-versa.""" @pytest.fixture(scope="class") def lib(self, helper): for album_idx in range(1, 3): album_name = f"Album{album_idx}" items = [ helper.create_item( album=album_name, title=f"{album_name} Item{idx}" ) for idx in range(1, 3) ] album = helper.lib.add_album(items) album.artpath = f"{album_name} Artpath" album.catalognum = "ABC" album.store() return helper.lib @pytest.mark.parametrize( "q, expected_titles, expected_albums", [ _p( "title:Album1", ["Album1 Item1", "Album1 Item2"], ["Album1"], id="match-album-with-item-field-query", ), _p( "title:Item2", ["Album1 Item2", "Album2 Item2"], ["Album1", "Album2"], id="match-albums-with-item-field-query", ), _p( "artpath::Album1", ["Album1 Item1", "Album1 Item2"], ["Album1"], id="match-items-with-album-field-query", ), _p( "catalognum:ABC Album1", ["Album1 Item1", "Album1 Item2"], ["Album1"], id="query-field-common-to-album-and-item", ), ], ) def test_related_query(self, lib, q, expected_titles, expected_albums): assert {i.album for i in lib.albums(q)} == set(expected_albums) assert {i.title for i in lib.items(q)} == set(expected_titles) class TestHasCoverArtQuery: """Test has_cover_art computed field for detecting embedded cover art.""" @pytest.fixture(scope="class") def lib(self, helper): item_with = helper.add_item_fixture() item_with.title = "with_art" path_with = helper.create_mediafile_fixture(images=["jpg"]) item_with["path"] = path_with item_with.store() path_without = helper.create_mediafile_fixture(images=[]) item_without = helper.add_item_fixture() item_without.title = "without_art" item_without["path"] = path_without item_without.store() return helper.lib @pytest.mark.parametrize( "query, expected_titles", [ ("has_cover_art:true", {"with_art"}), ("has_cover_art:false", {"without_art"}), ], ) def test_has_cover_art_query(self, lib, query, expected_titles): assert {i.title for i in lib.items(query)} == expected_titles beetbox-beets-00724b7/test/conftest.py0000664000175000017500000001474615253035401017245 0ustar pieterpieterfrom __future__ import annotations import inspect import os import sys from typing import TYPE_CHECKING import pytest from beets import logging from beets.autotag import Distance from beets.dbcore.query import Query from beets.test._common import DummyIO from beets.test.helper import RUNNING_IN_CI, ConfigMixin, TestHelper from beets.test.helper import is_importable as check_import from beets.util import cached_classproperty if TYPE_CHECKING: from typing import TextIO def skip_marked_items(items: list[pytest.Item], marker_name: str, reason: str): for item in (i for i in items if i.get_closest_marker(marker_name)): test_name = item.nodeid.split("::", 1)[-1] item.add_marker(pytest.mark.skip(f"{reason}: {test_name}")) def pytest_collection_modifyitems( config: pytest.Config, items: list[pytest.Item] ): if not os.environ.get("INTEGRATION_TEST") == "true": skip_marked_items( items, "integration_test", "INTEGRATION_TEST=1 required" ) if not os.environ.get("LYRICS_UPDATED") == "true": skip_marked_items( items, "on_lyrics_update", "No change in lyrics source code" ) for item in items: if marker := item.get_closest_marker("requires_import"): force_ci = marker.kwargs.get("force_ci", True) if ( force_ci and RUNNING_IN_CI # only apply this to our repository, to allow other projects to # run tests without installing all dependencies and os.environ.get("GITHUB_REPOSITORY", "") == "beetbox/beets" ): continue modname = marker.args[0] if not check_import(modname): test_name = item.nodeid.split("::", 1)[-1] item.add_marker( pytest.mark.skip( f"{modname!r} is not installed: {test_name}" ) ) def pytest_configure(config: pytest.Config) -> None: config.addinivalue_line( "markers", "integration_test: mark a test as an integration test" ) config.addinivalue_line( "markers", "on_lyrics_update: run test only when lyrics source code changes", ) config.addinivalue_line( "markers", ( "requires_import(module, force_ci=True): run test only if module" " is importable (use force_ci=False to allow CI to skip the test too)" ), ) def pytest_make_parametrize_id(config, val, argname): """Generate readable test identifiers for pytest parametrized tests. Provides custom string representations for: - Query classes/instances: use class name - Lambda functions: show abbreviated source - Other values: use standard repr() """ if inspect.isclass(val) and issubclass(val, Query): return val.__name__ if inspect.isfunction(val) and val.__name__ == "": return inspect.getsource(val).split("lambda")[-1][:30] return repr(val) def pytest_assertrepr_compare(op, left, right): if isinstance(left, Distance) or isinstance(right, Distance): return [f"Comparing Distance: {float(left)} {op} {float(right)}"] return None class _CurrentStderrHandler(logging.StreamHandler): # type: ignore[type-arg] """Write CLI logs to the active standard error stream. Logging is bootstrapped when the CLI runs instead of when this module is imported. That startup can happen while callers have temporarily replaced ``sys.stderr`` for capture or redirection, such as pytest's per-test capture streams. The handler must not retain the stream that happened to be active during the first command invocation because that stream may later be closed. Resolving the stream for each record keeps logs attached to the current CLI environment. """ @property def stream(self) -> TextIO: return sys.stderr @stream.setter def stream(self, stream: TextIO) -> None: pass @pytest.fixture(autouse=True) def patch_logging_handler(monkeypatch): """Ensure that beets logs are captured by pytest's capture system.""" monkeypatch.setattr( "beets.ui._get_logging_handler", lambda: _CurrentStderrHandler() ) @pytest.fixture(autouse=True) def do_not_log_sources(monkeypatch): monkeypatch.setattr("beets.config.log_sources", lambda _: None) @pytest.fixture(autouse=True) def clear_cached_classproperty(): cached_classproperty.cache.clear() @pytest.fixture def config(): """Provide a fresh beets configuration when requested.""" return ConfigMixin().config @pytest.fixture def io( request: pytest.FixtureRequest, monkeypatch: pytest.MonkeyPatch, capteesys: pytest.CaptureFixture[str], ) -> DummyIO: """Fixture for tests that need controllable stdin and captured stdout. This fixture builds a per-test ``DummyIO`` helper and exposes it to the test. When used on a test class, it attaches the helper as ``self.io`` attribute to make it available to all test methods, including ``unittest.TestCase``-based ones. """ io = DummyIO(monkeypatch, capteesys) if request.instance: request.instance.io = io return io @pytest.fixture def is_importable(): """Fixture that provides a function to check if a module can be imported.""" return check_import # Inheriting from TestHelper gives each test function isolated state. Use the # fixtures below instead when a broader scope is safe and the suite benefits # from reusing the same helper instance. @pytest.fixture(scope="session") def session_helper(): """Share beets test state across the full test session. Use this for suites that tolerate shared library contents and global configuration. Tests should target specific records rather than assume a completely fresh overall state. """ with TestHelper() as helper: yield helper @pytest.fixture(scope="module") def module_helper(): """Share beets test state within one test module. Use this when tests in the same file can reuse setup and side effects, but later modules should still begin from a clean environment. """ with TestHelper() as helper: yield helper @pytest.fixture(scope="class") def class_helper(): """Share beets test state within one test class. Use this when methods in a class can build on the same setup, while nearby classes still need independent libraries, files, or configuration. """ with TestHelper() as helper: yield helper beetbox-beets-00724b7/SECURITY.md0000664000175000017500000000044415253035401015646 0ustar pieterpieter# Security Policy ## Supported Versions We currently support only the latest release of beets. ## Reporting a Vulnerability To report a security vulnerability, please send email to [our Zulip team][z]. [z]: mailto:email.218c36e48d78cf125c0a6219a6c2a417.show-sender@streams.zulipchat.com beetbox-beets-00724b7/codecov.yml0000664000175000017500000000046515253035401016225 0ustar pieterpietercomment: layout: "header, diff, files" require_changes: true # Sets non-blocking status checks # https://docs.codecov.com/docs/commit-status#informational coverage: status: project: default: informational: true patch: default: informational: true changes: false beetbox-beets-00724b7/docs/0000775000175000017500000000000015253035401015003 5ustar pieterpieterbeetbox-beets-00724b7/docs/contributing.rst0000664000175000017500000000006315253035401020243 0ustar pieterpieter.. contributing: .. include:: ../CONTRIBUTING.rst beetbox-beets-00724b7/docs/index.rst0000664000175000017500000000224115253035401016643 0ustar pieterpieterbeets: the music geek's media organizer ======================================= Welcome to the documentation for beets_, the media library management system for obsessive music geeks. If you're new to beets, begin with the :doc:`guides/main` guide. That guide walks you through installing beets, setting it up how you like it, and starting to build your music library. Then you can get a more detailed look at beets' features in the :doc:`/reference/cli/` and :doc:`/reference/config` references. You might also be interested in exploring the :doc:`plugins `. If you still need help, you can drop by the ``#beets`` IRC channel on Libera.Chat, drop by `the discussion board`_ or `file a bug`_ in the issue tracker. Please let us know where you think this documentation can be improved. .. _beets: https://beets.io/ .. _file a bug: https://github.com/beetbox/beets/issues .. _the discussion board: https://github.com/beetbox/beets/discussions/ Contents -------- .. toctree:: :maxdepth: 2 guides/index reference/index plugins/index faq team contributing code_of_conduct dev/index .. toctree:: :maxdepth: 1 changelog beetbox-beets-00724b7/docs/extensions/0000775000175000017500000000000015253035401017202 5ustar pieterpieterbeetbox-beets-00724b7/docs/extensions/conf.py0000664000175000017500000001107415253035401020504 0ustar pieterpieter"""Sphinx extension for simple configuration value documentation.""" from __future__ import annotations from typing import TYPE_CHECKING, Any, ClassVar from docutils import nodes from docutils.parsers.rst import directives from sphinx import addnodes from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType from sphinx.roles import XRefRole from sphinx.util.nodes import make_refnode if TYPE_CHECKING: from collections.abc import Iterable, Sequence from docutils.nodes import Element from docutils.parsers.rst.states import Inliner from sphinx.addnodes import desc_signature, pending_xref from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.environment import BuildEnvironment from sphinx.util.typing import ExtensionMetadata, OptionSpec class Conf(ObjectDescription[str]): """Directive for documenting a single configuration value.""" option_spec: ClassVar[OptionSpec] = { # type: ignore[misc] "default": directives.unchanged } def handle_signature(self, sig: str, signode: desc_signature) -> str: """Process the directive signature (the config name).""" signode += addnodes.desc_name(sig, sig) # Add default value if provided if "default" in self.options: signode += nodes.Text(" ") default_container = nodes.inline("", "") default_container += nodes.Text("(default: ") default_container += nodes.literal("", self.options["default"]) default_container += nodes.Text(")") signode += default_container return sig def add_target_and_index( self, name: str, sig: str, signode: desc_signature ) -> None: """Add cross-reference target and index entry.""" target = f"conf-{name}" if target not in self.state.document.ids: signode["ids"].append(target) self.state.document.note_explicit_target(signode) # A unique full name which includes the document name index_name = f"{self.env.docname.replace('/', '.')}:{name}" # Register with the conf domain domain = self.env.get_domain("conf") domain.data["objects"][index_name] = (self.env.docname, target) # Add to index self.indexnode["entries"].append( ("single", f"{name} (configuration value)", target, "", None) ) class ConfDomain(Domain): """Domain for simple configuration values.""" name = "conf" label = "Simple Configuration" object_types = {"conf": ObjType("conf", "conf")} # noqa: RUF012 directives = {"conf": Conf} # noqa: RUF012 roles = {"conf": XRefRole()} # noqa: RUF012 initial_data: dict[str, Any] = {"objects": {}} # noqa: RUF012 def get_objects(self) -> Iterable[tuple[str, str, str, str, str, int]]: """Return an iterable of object tuples for the inventory.""" for name, (docname, targetname) in self.data["objects"].items(): # Remove the document name prefix for display display_name = name.split(":")[-1] yield (name, display_name, "conf", docname, targetname, 1) def resolve_xref( self, env: BuildEnvironment, fromdocname: str, builder: Builder, typ: str, target: str, node: pending_xref, contnode: Element, ) -> Element | None: if entry := self.data["objects"].get(target): docname, targetid = entry return make_refnode( builder, fromdocname, docname, targetid, contnode ) return None # sphinx.util.typing.RoleFunction def conf_role( name: str, rawtext: str, text: str, lineno: int, inliner: Inliner, /, options: dict[str, Any] | None = None, content: Sequence[str] = (), ) -> tuple[list[nodes.Node], list[nodes.system_message]]: """Role for referencing configuration values.""" node = addnodes.pending_xref( "", refdomain="conf", reftype="conf", reftarget=text, refwarn=True, **(options or {}), ) node += nodes.literal(text, text.split(":")[-1]) return [node], [] def setup(app: Sphinx) -> ExtensionMetadata: app.add_domain(ConfDomain) # register a top-level directive so users can use ".. conf:: ..." app.add_directive("conf", Conf) # Register role with short name app.add_role("conf", conf_role) return { "version": "0.1", "parallel_read_safe": True, "parallel_write_safe": True, } beetbox-beets-00724b7/docs/faq.rst0000664000175000017500000003444515253035401016316 0ustar pieterpieterFAQ === Here are some answers to frequently-asked questions from IRC and elsewhere. Got a question that isn't answered here? Try the `discussion board`_, or :ref:`filing an issue ` in the bug tracker. .. _discussion board: https://github.com/beetbox/beets/discussions/ .. _mailing list: https://groups.google.com/group/beets-users .. contents:: :local: :depth: 2 How do I… --------- .. _move: …rename my files according to a new path format configuration? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Just run the :ref:`move-cmd` command. Use a :doc:`query ` to rename a subset of your music or leave the query off to rename everything. .. _asispostfacto: …find all the albums I imported "as-is"? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Enable the :ref:`import log ` to automatically record whenever you skip an album or accept one "as-is". Alternatively, you can find all the albums in your library that are missing MBIDs using a command like this: :: beet ls -a mb_albumid::^$ Assuming your files didn't have MBIDs already, then this will roughly correspond to those albums that didn't get autotagged. .. _discdir: …create "Disc N" directories for multi-disc albums? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use the :doc:`/plugins/inline` along with the ``%if{}`` function to accomplish this: :: plugins: inline paths: default: $albumartist/$album%aunique{}/%if{$multidisc,Disc $disc/}$track $title item_fields: multidisc: 1 if disctotal > 1 else 0 This ``paths`` configuration only contains the ``default`` key: it leaves the ``comp`` and ``singleton`` keys as their default values, as documented in :ref:`path-format-config`. To create "Disc N" directories for compilations and singletons, you will need to specify similar templates for those keys as well. .. _multidisc: …import a multi-disc album? ~~~~~~~~~~~~~~~~~~~~~~~~~~~ As of 1.0b11, beets tags multi-disc albums as a *single unit*. To get a good match, it needs to treat all of the album's parts together as a single release. To help with this, the importer uses a simple heuristic to guess when a directory represents a multi-disc album that's been divided into multiple subdirectories. When it finds a situation like this, it collapses all of the items in the subdirectories into a single release for tagging. The heuristic works by looking at the names of directories. If multiple subdirectories of a common parent directory follow the pattern "(title) disc (number) (...)" and the *prefix* (everything up to the number) is the same, the directories are collapsed together. One of the following key words must be present to make this work: "disc", "disk", "CD", "cassette", "digital media", or "vinyl". If you have trouble tagging a multi-disc album, consider the ``--flat`` flag (which treats a whole tree as a single album) or just putting all the tracks into a single directory to force them to be tagged together. .. _mbid: …enter a MusicBrainz ID? ~~~~~~~~~~~~~~~~~~~~~~~~ An MBID looks like one of these: - ``https://musicbrainz.org/release/ded77dcf-7279-457e-955d-625bd3801b87`` - ``d569deba-8c6b-4d08-8c43-d0e5a1b8c7f3`` Beets can recognize either the hex-with-dashes UUID-style string or the full URL that contains it (as of 1.0b11). You can get these IDs by `searching on the MusicBrainz web site `__ and going to a *release* page (when tagging full albums) or a *recording* page (when tagging singletons). Then, copy the URL of the page and paste it into beets. Note that MusicBrainz has both "releases" and "release groups," which link together different versions of the same album. Use *release* IDs here. .. _upgrade: …upgrade to the latest version of beets? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Run a command like this: :: pip install -U beets The ``-U`` flag tells pip_ to upgrade beets to the latest version. If you want a specific version, you can specify with using ``==`` like so: :: pip install beets==1.0rc2 .. _src: …run the latest source version of beets? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Beets sees regular releases (about every six weeks or so), but sometimes it's helpful to run on the "bleeding edge". To run the latest source: 1. Uninstall beets. If you installed using ``pip``, you can just run ``pip uninstall beets``. 2. Install from source. Choose one of these methods: - Directly from GitHub using ``python -m pip install git+https://github.com/beetbox/beets.git`` command. Depending on your system, you may need to use ``pip3`` and ``python3`` instead of ``pip`` and ``python`` respectively. - Use ``pip`` to install the latest snapshot tarball. Type: ``pip install https://github.com/beetbox/beets/tarball/master`` - Use ``pip`` to install an "editable" version of beets based on an automatic source checkout. For example, run ``pip install -e git+https://github.com/beetbox/beets#egg=beets`` to clone beets and install it, allowing you to modify the source in-place to try out changes. - Clone source code and install it in editable mode .. code-block:: shell git clone https://github.com/beetbox/beets.git cd beets pip install -e . This approach lets you decide where the source is stored, with any changes immediately reflected in your environment. More details about the beets source are available on the :doc:`developer documentation ` pages. .. _bugs: …report a bug in beets? ----------------------- We use the `issue tracker`_ on GitHub where you can `open a new ticket`_. Please follow these guidelines when reporting an issue: - Most importantly: if beets is crashing, please `include the traceback `__. Tracebacks can be more readable if you put them in a pastebin (e.g., `Gist `__ or `Hastebin `__), especially when communicating over IRC. - Turn on beets' debug output (using the -v option: for example, ``beet -v import ...``) and include that with your bug report. Look through this verbose output for any red flags that might point to the problem. - If you can, try installing the latest beets source code to see if the bug is fixed in an unreleased version. You can also look at the :doc:`latest changelog entries ` for descriptions of the problem you're seeing. - Try to narrow your problem down to something specific. Is a particular plugin causing the problem? (You can disable plugins to see whether the problem goes away.) Is a some music file or a single album leading to the crash? (Try importing individual albums to determine which one is causing the problem.) Is some entry in your configuration file causing it? Et cetera. - If you do narrow the problem down to a particular audio file or album, include it with your bug report so the developers can run tests. If you've never reported a bug before, Mozilla has some well-written `general guidelines for good bug reports`_. .. _find-config: .. _general guidelines for good bug reports: https://bugzilla.mozilla.org/page.cgi?id=bug-writing.html .. _issue tracker: https://github.com/beetbox/beets/issues …find the configuration file (config.yaml)? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You create this file yourself; beets just reads it. See :doc:`/reference/config`. .. _special-chars: …avoid using special characters in my filenames? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use the ``%asciify{}`` function in your path formats. See :ref:`template-functions`. .. _move-dir: …point beets at a new music directory? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you want to move your music from one directory to another, the best way is to let beets do it for you. First, edit your configuration and set the ``directory`` setting to the new place. Then, type ``beet move`` to have beets move all your files. If you've already moved your music *outside* of beets, you have a few options: - Move the music back (with an ordinary ``mv``) and then use the above steps. - Delete your database and re-create it from the new paths using ``beet import -AWC``. - Resort to manually modifying the SQLite database (not recommended). Why does beets… --------------- .. _nomatch: …complain that it can't find a match? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are a number of possibilities: - First, make sure you have at least one autotagger extension/plugin enabled. See :ref:`autotagger_extensions` for a list of valid plugins. - Check that the album is in `the MusicBrainz database `__. You can search on their site to make sure it's cataloged there. (If not, anyone can edit MusicBrainz---so consider adding the data yourself.) - If the album in question is a multi-disc release, see the relevant FAQ answer above. - The music files' metadata might be insufficient. Try using the "enter search" or "enter ID" options to help the matching process find the right MusicBrainz entry. - If you have a lot of files that are missing metadata, consider using :doc:`acoustic fingerprinting ` or :doc:`filename-based guesses ` for that music. If none of these situations apply and you're still having trouble tagging something, please :ref:`file a bug report `. .. _plugins: …appear to be missing some plugins? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Please make sure you're using the latest version of beets---you might be using a version earlier than the one that introduced the plugin. In many cases, the plugin may be introduced in beets "trunk" (the latest source version) and might not be released yet. Take a look at :doc:`the changelog ` to see which version added the plugin. (You can type ``beet version`` to check which version of beets you have installed.) If you want to live on the bleeding edge and use the latest source version of beets, you can check out the source (see :ref:`the relevant question `). To see the beets documentation for your version (and avoid confusion with new features in trunk), select your version from the menu in the sidebar. .. _kill: …ignore control-C during an import? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Typing a ^C (control-C) control sequence will not halt beets' multithreaded importer while it is waiting at a prompt for user input. Instead, hit "return" (dismissing the prompt) after typing ^C. Alternatively, just type a "b" for "aBort" at most prompts. Typing ^C *will* work if the importer interface is between prompts. Also note that beets may take some time to quit after ^C is typed; it tries to clean up after itself briefly even when canceled. (For developers: this is because the UI thread is blocking on ``input`` and cannot be interrupted by the main thread, which is trying to close all pipeline stages in the exception handler by setting a flag. There is no simple way to remedy this.) .. _id3v24: …not change my ID3 tags? ~~~~~~~~~~~~~~~~~~~~~~~~ Beets writes ID3v2.4_ tags by default. Some software, including Windows (i.e., Windows Explorer and Windows Media Player) and `id3lib/id3v2 `__, don't support v2.4 tags. When using 2.4-unaware software, it might look like the tags are unmodified or missing completely. To enable ID3v2.3 tags, enable the :ref:`id3v23` config option. .. _id3v2.4: https://id3.org/id3v2.4.0-structure .. _invalid: …complain that a file is "unreadable"? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Beets will log a message like "unreadable file: /path/to/music.mp3" when it encounters files that *look* like music files (according to their extension) but seem to be broken. Most of the time, this is because the file is corrupted. To check whether the file is intact, try opening it in another media player (e.g., `VLC `__) to see whether it can read the file. You can also use specialized programs for checking file integrity---for example, type ``metaflac --list music.flac`` to check FLAC files. If beets still complains about a file that seems to be valid, `open a new ticket`_ and we'll look into it. There's always a possibility that there's a bug "upstream" in the `Mutagen `__ library used by beets, in which case we'll forward the bug to that project's tracker. .. _importhang: …seem to "hang" after an import finishes? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Probably not. Beets uses a *multithreaded importer* that overlaps many different activities: it can prompt you for decisions while, in the background, it talks to MusicBrainz and copies files. This means that, even after you make your last decision, there may be a backlog of files to be copied into place and tags to be written. (Plugin tasks, like looking up lyrics and genres, also run at this time.) If beets pauses after you see all the albums go by, have patience. .. _replaceq: …put a bunch of underscores in my filenames? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When naming files, beets replaces certain characters to avoid causing problems on the filesystem. For example, leading dots can confusingly hide files on Unix and several non-alphanumeric characters are forbidden on Windows. The :ref:`replace` config option controls which replacements are made. By default, beets makes filenames safe for all known platforms by replacing several patterns with underscores. This means that, even on Unix, filenames are made Windows-safe so that network filesystems (such as SMB) can be used safely. Most notably, Windows forbids trailing dots, so a folder called "M.I.A." will be rewritten to "M.I.A\_" by default. Change the ``replace`` config if you don't want this behavior and don't need Windows-safe names. .. _pathq: …say "command not found"? ~~~~~~~~~~~~~~~~~~~~~~~~~ You need to put the ``beet`` program on your system's search path. If you installed using pip, the command ``pip show -f beets`` can show you where ``beet`` was placed on your system. If you need help extending your ``$PATH``, try `this Super User answer`_. .. _open a new ticket: https://github.com/beetbox/beets/issues/new?template=bug-report.md .. _pip: https://pip.pypa.io/en/stable/ .. _this super user answer: https://superuser.com/questions/284342/what-are-path-and-other-environment-variables-and-how-can-i-set-or-use-them/284361#284361 beetbox-beets-00724b7/docs/.gitignore0000664000175000017500000000002115253035401016764 0ustar pieterpieter_build generated/beetbox-beets-00724b7/docs/conf.py0000664000175000017500000001233115253035401016302 0ustar pieterpieter# Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information import sys from pathlib import Path # Add custom extensions directory to path sys.path.insert(0, str(Path(__file__).parent / "extensions")) project = "beets" AUTHOR = "Adrian Sampson" copyright = "2016, Adrian Sampson" # noqa: A001 master_doc = "index" language = "en" version = "2.14" release = "2.14.1" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ "sphinx.ext.autodoc", "sphinx.ext.autosummary", "sphinx.ext.extlinks", "sphinx.ext.viewcode", "sphinx_design", "sphinx_copybutton", "conf", "sphinx_toolbox.more_autodoc.autotypeddict", "sphinx_toolbox.more_autodoc.autonamedtuple", ] autosummary_generate = True autosummary_context = { "related_typeddicts": { "MusicBrainzAPI": [ "beetsplug._utils.musicbrainz.LookupKwargs", "beetsplug._utils.musicbrainz.SearchKwargs", "beetsplug._utils.musicbrainz.BrowseKwargs", "beetsplug._utils.musicbrainz.BrowseRecordingsKwargs", "beetsplug._utils.musicbrainz.BrowseReleaseGroupsKwargs", ] } } autodoc_member_order = "bysource" exclude_patterns = ["_build"] templates_path = ["_templates"] source_suffix = {".rst": "restructuredtext", ".md": "markdown"} pygments_style = "sphinx" # External links to the bug tracker and other sites. extlinks = { "bug": ("https://github.com/beetbox/beets/issues/%s", "#%s"), "user": ("https://github.com/%s", "%s"), "pypi": ("https://pypi.org/project/%s/", "%s"), "stdlib": ("https://docs.python.org/3/library/%s.html", "%s"), } linkcheck_ignore = [ r"https://github.com/beetbox/beets/issues/", r"https://github.com/[^/]+$", # ignore user pages r".*localhost.*", r"https?://127\.0\.0\.1", r"https://www.musixmatch.com/", # blocks requests r"https://genius.com/", # blocks requests r"https://sourceforge\.net/", # blocks requests r"https://[^/]*fanart\.tv/", # blocks requests r"https://[^/]*fandom\.com/", # blocks requests r"https://imgur\.com/", # not accessible from the UK r"https://(www\.)?discogs.com.*", # blocks requests r"https://essentia.upf.edu/", # times out in CI r"https://flask.palletsprojects.com.*", # times out in CI r"https://search.worldcat.org.*", # blocks requests r"https://tidal.com.*", # blocks requests r"https://www.tekstowo.pl/", # blocks requests r"https://www.gnu.org.*", # sometimes unreachable r"https://www.nongnu.org.*", # sometimes unreachable r"https://web.archive.org.*", # sometimes unreachable r"https://www.sonos.com.*", # blocks requests r"https://stackoverflow.com.*", # blocks requests r"https://superuser.com.*", # blocks requests r"https://support.discogs.com.*", # blocks requests r"https://forge\.kanis\.fr.*", # SSL cert issues r"https://id3\.org.*", # intermittent server errors ] # Options for HTML output htmlhelp_basename = "beetsdoc" # Options for LaTeX output latex_documents = [ ("index", "beets.tex", "beets Documentation", AUTHOR, "manual") ] # Options for manual page output man_pages = [ ( "reference/cli", "beet", "music tagger and library organizer", [AUTHOR], 1, ), ( "reference/config", "beetsconfig", "beets configuration file", [AUTHOR], 5, ), ] # Global substitutions that can be used anywhere in the documentation. rst_epilog = r""" .. |Album| replace:: :class:`~beets.library.models.Album` .. |AlbumInfo| replace:: :class:`beets.autotag.hooks.AlbumInfo` .. |BeetsPlugin| replace:: :class:`beets.plugins.BeetsPlugin` .. |ImportSession| replace:: :class:`~beets.importer.session.ImportSession` .. |ImportTask| replace:: :class:`~beets.importer.tasks.ImportTask` .. |Item| replace:: :class:`~beets.library.models.Item` .. |Library| replace:: :class:`~beets.library.library.Library` .. |Model| replace:: :class:`~beets.dbcore.db.Model` .. |TrackInfo| replace:: :class:`beets.autotag.hooks.TrackInfo` .. |semicolon_space| replace:: :literal:`; \ ` """ # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "pydata_sphinx_theme" html_theme_options = { "collapse_navigation": False, "logo": {"text": "beets"}, "show_nav_level": 2, # How many levels in left sidebar to show automatically "navigation_depth": 4, # How many levels of navigation to expand } html_title = "beets" html_logo = "_static/beets_logo_nobg.png" html_static_path = ["_static"] html_css_files = ["beets.css"] def skip_member(app, what, name: str, obj, skip, options): if name.startswith("_"): return True return skip def setup(app) -> None: app.connect("autodoc-skip-member", skip_member) beetbox-beets-00724b7/docs/_templates/0000775000175000017500000000000015253035401017140 5ustar pieterpieterbeetbox-beets-00724b7/docs/_templates/autosummary/0000775000175000017500000000000015253035401021526 5ustar pieterpieterbeetbox-beets-00724b7/docs/_templates/autosummary/module.rst0000664000175000017500000000025415253035401023546 0ustar pieterpieter{{ fullname | escape | underline}} {% block modules %} {% if modules %} .. rubric:: Modules {% for item in modules %} {{ item }} {%- endfor %} {% endif %} {% endblock %} beetbox-beets-00724b7/docs/_templates/autosummary/class.rst0000664000175000017500000000156715253035401023376 0ustar pieterpieter{{ name | escape | underline}} .. currentmodule:: {{ module }} .. autoclass:: {{ objname }} :members: <-- add at least this line :private-members: :show-inheritance: <-- plus I want to show inheritance... :inherited-members: <-- ...and inherited members too {% block methods %} .. automethod:: __init__ {% if methods %} .. rubric:: {{ _('Public methods summary') }} .. autosummary:: {% for item in methods %} ~{{ name }}.{{ item }} {%- endfor %} {% for item in _methods %} ~{{ name }}.{{ item }} {%- endfor %} {% endif %} {% endblock %} .. rubric:: {{ _('Methods definition') }} {% if objname in related_typeddicts %} Related TypedDicts ------------------ {% for typeddict in related_typeddicts[objname] %} .. autotypeddict:: {{ typeddict }} :show-inheritance: {% endfor %} {% endif %} beetbox-beets-00724b7/docs/_templates/autosummary/namedtuple.rst0000664000175000017500000000014415253035401024415 0ustar pieterpieter{{ name | escape | underline }} .. currentmodule:: {{ module }} .. autonamedtuple:: {{ objname }} beetbox-beets-00724b7/docs/_templates/autosummary/base.rst0000664000175000017500000000015015253035401023166 0ustar pieterpieter{{ fullname | escape | underline}} .. currentmodule:: {{ module }} .. auto{{ objtype }}:: {{ objname }} beetbox-beets-00724b7/docs/Makefile0000664000175000017500000001130615253035401016444 0ustar pieterpieter# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build SOURCEDIR = . # When both are available, use Sphinx 2.x for autodoc compatibility. ifeq ($(shell which sphinx-build2 >/dev/null 2>&1 ; echo $$?),0) SPHINXBUILD = sphinx-build2 endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest auto help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* $(SOURCEDIR)/api/generated/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/beets.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/beets.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/beets" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/beets" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." beetbox-beets-00724b7/docs/team.rst0000664000175000017500000000463515253035401016473 0ustar pieterpieterTeam ==== This is an introduction of beets' core-team members, collaborators and frequent contributors. Refer to this list to find out who to ask about your collaboration idea, discuss a usage-question, request a review of your open PR. Beets is a huge project and not everyone involved, knows everything. We hope this helps to point you in the right direction in the first place and should give you an idea of what you can expect from these *knowledge owners*. @arsaboo -------- - The master of the Spotify plugin - Testing out new contributions - beets as a music discovery tool @bal-e ------ - Documentation - The Fish plugin - Type annotations @govynnus --------- - The AURA plugin - The AURA specification - The web plugin - The plugin ecosystem - The library database API and its documentation @jackwilsdon ------------ - Broad knowledge around beets' configuration and plugins - Assists in discussion forums frequently - Knows internals of beets and puts new contributors into the right direction @joj0 ----- - The Discogs plugin - Good documentation throughout the project - The smartplaylist plugin - The lastgenre plugin - Support for M3U and other playlist formats - beets as a DJ companion tool (BPM, audio features, key) @RollingStar ------------ - Data visualization - ListenBrainz / Last.fm - Smart playlists - Library reports - MusicBrainz fields and searching - Project organization and roadmap @sampsyo -------- - The founder - Knows almost everything ;-) @serene-arc ----------- - Good documentation throughout the project - Experienced Python developer - Experienced in test-driven-development - Code quality - Typing @snejus ------- - Grug-minded approach: simple, obvious solutions over clever complexity - MusicBrainz/autotagger internals and source-plugin behavior - Query/path handling and SQL-backed lookup behavior - Typing and tooling modernization (mypy, Ruff, annotations) - Test architecture, CI reliability, and coverage improvements - Release and packaging workflows (Poetry/pyproject, dependencies, changelog) - Cross-plugin refactors (especially metadata and lyrics-related internals) @wisp3rwind ----------- - Mr. Tidy - Keeping the code in shape - Focus on improving core things rather than implementing new features @ybnd ----- - The replaygain plugin - Improving the general parallelism of plugins - Experienced with web scrapers - Experienced with Flask and JavaScript integration - The web plugin beetbox-beets-00724b7/docs/plugins/0000775000175000017500000000000015253035401016464 5ustar pieterpieterbeetbox-beets-00724b7/docs/plugins/tidal.rst0000664000175000017500000001046215253035401020316 0ustar pieterpieterTidal Plugin ============ The ``tidal`` plugin provides metadata matches for the autotagger using the Tidal_ Web APIs. .. _tidal: https://tidal.com Why Use the Tidal Plugin? ------------------------- The Tidal plugin allows you to: - Fetch metadata for albums and tracks from Tidal's catalog - Look up tracks by ISRC code (useful if your music files already contain ISRC tags) - Look up albums by barcode ID (useful if your CDs have UPC barcodes) - Get matches during import without needing to manually search This is especially useful if your music already has ISRC or barcode metadata embedded, as it allows for quick and accurate matching to Tidal's catalog. Requirements ------------ - A Tidal account (free or premium) - Python environment with network access to Tidal's API Before using the plugin, you need to authorize your beets installation to access your Tidal account. Installation ------------ To use the ``tidal`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``tidal`` extra .. code-block:: bash pip install "beets[tidal]" Authentication -------------- To authenticate with Tidal, run: .. code-block:: bash beet tidal --auth This will open a browser window where you can log in to your Tidal account. After successful authentication, your token will be saved to the configured token file and you won't need to re-authenticate on subsequent runs. Basic Usage ----------- Enable the ``tidal`` plugin (see :ref:`using-plugins`). Once enabled, you will receive Tidal matches when importing new items. During import, you can also manually enter a Tidal URL at the ``enter Id`` prompt: .. code-block:: bash Enter search, enter Id, aBort, eDit, edit Candidates, plaY? i Enter release ID: https://tidal.com/album/226495055 You can enter both album and track URLs. For example: .. code-block:: bash https://tidal.com/track/490839595 https://tidal.com/album/234493117 Configuration ------------- This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`. Default ~~~~~~~ .. code-block:: yaml tidal: client_id: mcjmpl1bPATJXcBT tokenfile: tidal_token.json data_source_mismatch_penalty: 0.5 search_limit: 5 .. conf:: client_id :default: mcjmpl1bPATJXcBT The Tidal API client ID. The default value is the public demo client ID. You can register your own application at Tidal's developer portal for production use. .. conf:: tokenfile :default: tidal_token.json The path to the file where the Tidal authentication token is stored. Cover Art --------- When the :doc:`fetchart` plugin is enabled, beets can retrieve album cover art from Tidal. The Tidal plugin automatically includes the cover art URL when looking up albums. No additional configuration is needed to enable this feature. .. include:: ./shared_metadata_source_config.rst Flexible Attributes ------------------- The plugin stores the following flexible attributes on your items during import. You can use them in queries and path formats. .. list-table:: :header-rows: 1 - - Attribute - Type - Description - - ``tidal_track_id`` - STRING - Tidal track ID - - ``tidal_album_id`` - STRING - Tidal album ID - - ``tidal_artist_id`` - STRING - Tidal artist ID - - ``tidal_track_popularity`` - INTEGER - Track popularity score (0-100) - - ``tidal_album_popularity`` - INTEGER - Album popularity score (0-100) - - ``tidal_updated`` - DATE - Unix timestamp of last popularity sync For example, to list your most popular tracks: :: beet ls tidal_track_popularity:80.. To find tracks that have not been synced yet: :: beet ls tidal_track_popularity:0 Synchronise popularity ---------------------- Use ``beet tidalsync`` to refresh popularity data for your imported items and albums from Tidal. By default it skips items that already have popularity data. Options: - ``-f``, ``--force`` -- re-fetch all items, even those already synced. - ``-a``, ``--album`` -- sync albums instead of individual tracks. - ``-w``, ``--write`` -- write updated metadata to media files. You can also pass a query to narrow the scope: :: beet tidalsync -fw artist:"My Artist" beetbox-beets-00724b7/docs/plugins/zero.rst0000664000175000017500000000476315253035401020207 0ustar pieterpieterZero Plugin =========== The ``zero`` plugin allows you to null fields in files' metadata tags. Fields can be nulled unconditionally or conditioned on a pattern match. For example, the plugin can strip useless comments like "ripped by MyGreatRipper." The plugin can work in one of two modes: - ``fields``: A blacklist, where you choose the tags you want to remove (used by default). - ``keep_fields``: A whitelist, where you instead specify the tags you want to keep. To use the ``zero`` plugin, enable the plugin in your configuration (see :ref:`using-plugins`). Configuration ------------- Make a ``zero:`` section in your configuration file. You can specify the fields to nullify and the conditions for nullifying them: - Set ``auto`` to ``yes`` to null fields automatically on import. Default: ``yes``. - Set ``fields`` to a whitespace-separated list of fields to remove. You can get the list of all available fields by running ``beet fields``. In addition, the ``images`` field allows you to remove any images embedded in the media file. - Set ``keep_fields`` to *invert* the logic of the plugin. Only these fields will be kept; other fields will be removed. Remember to set only ``fields`` or ``keep_fields``---not both! - To conditionally filter a field, use ``field: [regexp, regexp]`` to specify regular expressions. - Set ``omit_single_disc`` to ``True`` to omit writing the ``disc`` number and the ``disctotal`` number for albums with a single disc (``disctotal == 1``). - By default this plugin only affects files' tags; the beets database is left unchanged. To update the tags in the database, set the ``update_database`` option to true. For example: :: zero: fields: month day genre genres comments comments: [EAC, LAME, from.+collection, 'ripped by'] genres: [rnb, 'power metal'] update_database: true If a custom pattern is not defined for a given field, the field will be nulled unconditionally. Note that the plugin currently does not zero fields when importing "as-is". Manually Triggering Zero ------------------------ You can also type ``beet zero [QUERY]`` to manually invoke the plugin on music in your library. Preserving Album Art -------------------- If you use the ``keep_fields`` option, the plugin will remove embedded album art from files' tags unless you tell it not to. To keep the album art, include the special field ``images`` in the list. For example: :: zero: keep_fields: title artist album year track genre genres images beetbox-beets-00724b7/docs/plugins/bareasc.rst0000664000175000017500000000553115253035401020622 0ustar pieterpieterBare-ASCII Search Plugin ======================== The ``bareasc`` plugin provides a prefixed query that searches your library using simple ASCII character matching, with accented characters folded to their base ASCII character. This can be useful if you want to find a track with accented characters in the title or artist, particularly if you are not confident you have the accents correct. It is also not unknown for the accents to not be correct in the database entry or wrong in the CD information. First, enable the plugin named ``bareasc`` (see :ref:`using-plugins`). You'll then be able to use the ``#`` prefix to use bare-ASCII matching: :: $ beet ls '#dvorak' István Kertész - REQUIEM - Dvořàk: Requiem, op.89 - Confutatis maledictis Command ------- In addition to the query prefix, the plugin provides a utility ``bareasc`` command. This command is **exactly** the same as the ``beet list`` command except that the output is passed through the bare-ASCII transformation before being printed. This allows you to easily check what the library data looks like in bare ASCII, which can be useful if you are trying to work out why a query is not matching. Using the same example track as above: :: $ beet bareasc 'Dvořàk' Istvan Kertesz - REQUIEM - Dvorak: Requiem, op.89 - Confutatis maledictis Note: the ``bareasc`` command does *not* automatically use bare-ASCII queries. If you want a bare-ASCII query you still need to specify the ``#`` prefix. Notes ----- If the query string is all in lower case, the comparison ignores case as well as accents. The default ``bareasc`` prefix (``#``) is used as a comment character in some shells so may need to be protected (for example in quotes) when typed into the command line. The bare ASCII transliteration is quite simple. It may not give the expected output for all languages. For example, German u-umlaut ``ü`` is transformed into ASCII ``u``, not into ``ue``. The bare ASCII transformation also changes Unicode punctuation like double quotes, apostrophes and even some hyphens. It is often best to leave out punctuation in the queries. Note that the punctuation changes are often not even visible with normal terminal fonts. You can always use the ``bareasc`` command to print the transformed entries and use a command like ``diff`` to compare with the output from the ``list`` command. Configuration ------------- To configure the plugin, make a ``bareasc:`` section in your configuration file. The only available option is: - **prefix**: The character used to designate bare-ASCII queries. Default: ``#``, which may need to be escaped in some shells. Credits ------- The hard work in this plugin is done in Sean Burke's `Unidecode `__ library. Thanks are due to Sean and to all the people who created the Python version and the beets extensible query architecture. beetbox-beets-00724b7/docs/plugins/mbcollection.rst0000664000175000017500000000263515253035401021676 0ustar pieterpieterMusicBrainz Collection Plugin ============================= The ``mbcollection`` plugin lets you submit your catalog to MusicBrainz to maintain your `music collection`_ list there. .. _music collection: https://musicbrainz.org/doc/Collections To begin, just enable the ``mbcollection`` plugin in your configuration (see :ref:`using-plugins`). Then, add your MusicBrainz username and password to your :doc:`configuration file ` under a ``musicbrainz`` section: :: musicbrainz: user: you pass: seekrit Then, use the ``beet mbupdate`` command to send your albums to MusicBrainz. The command automatically adds all of your albums to the first collection it finds. If you don't have a MusicBrainz collection yet, you may need to add one to your profile first. The command has one command-line option: - To remove albums from the collection which are no longer present in the beets database, use the ``-r`` (``--remove``) flag. Configuration ------------- To configure the plugin, make a ``mbcollection:`` section in your configuration file. There is one option available: - **auto**: Automatically amend your MusicBrainz collection whenever you import a new album. Default: ``no``. - **collection**: The MBID of which MusicBrainz collection to update. Default: ``None``. - **remove**: Remove albums from collections which are no longer present in the beets database. Default: ``no``. beetbox-beets-00724b7/docs/plugins/embedart.rst0000664000175000017500000001333415253035401021005 0ustar pieterpieterEmbedArt Plugin =============== Typically, beets stores album art in a "file on the side": along with each album, there is a file (named "cover.jpg" by default) that stores the album art. You might want to embed the album art directly into each file's metadata. While this will take more space than the external-file approach, it is necessary for displaying album art in some media players (iPods, for example). Embedding Art Automatically --------------------------- To use the ``embedart`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``embedart`` extra .. code-block:: bash pip install "beets[embedart]" You'll also want to enable the :doc:`/plugins/fetchart` to obtain the images to be embedded. Art will be embedded after each album has its cover art set. This behavior can be disabled with the ``auto`` config option (see below). .. _image-similarity-check: Image Similarity ~~~~~~~~~~~~~~~~ When importing a lot of files with the ``auto`` option, one may be reluctant to overwrite existing embedded art for all of them. You can tell beets to avoid embedding images that are too different from the existing ones. This works by computing the perceptual hashes (PHASH_) of the two images and checking that the difference between the two does not exceed a threshold. You can set the threshold with the ``compare_threshold`` option. A threshold of 0 (the default) disables similarity checking and always embeds new images. Set the threshold to another number---we recommend between 10 and 100---to adjust the sensitivity of the comparison. The smaller the threshold number, the more similar the images must be. This feature requires ImageMagick_. Configuration ------------- To configure the plugin, make an ``embedart:`` section in your configuration file. The available options are: - **auto**: Enable automatic album art embedding. Default: ``yes``. - **compare_threshold**: How similar candidate art must be to existing art to be written to the file (see :ref:`image-similarity-check`). Default: 0 (disabled). - **ifempty**: Avoid embedding album art for files that already have art embedded. Default: ``no``. - **maxwidth**: A maximum width to downscale images before embedding them (the original image file is not altered). The resize operation reduces image width to at most ``maxwidth`` pixels. The height is recomputed so that the aspect ratio is preserved. See also :ref:`image-resizing` for further caveats about image resizing. Default: 0 (disabled). - **quality**: The JPEG quality level to use when compressing images (when ``maxwidth`` is set). This should be either a number from 1 to 100 or 0 to use the default quality. 65–75 is usually a good starting point. The default behavior depends on the imaging tool used for scaling: ImageMagick tries to estimate the input image quality and uses 92 if it cannot be determined, and PIL defaults to 75. Default: 0 (disabled) - **remove_art_file**: Automatically remove the album art file for the album after it has been embedded. This option is best used alongside the :doc:`FetchArt ` plugin to download art with the purpose of directly embedding it into the file's metadata without an "intermediate" album art file. Default: ``no``. - **clearart_on_import**: Enable automatic embedded art clearing. Default: ``no``. Note: ``compare_threshold`` option requires ImageMagick_, and ``maxwidth`` requires either ImageMagick_ or Pillow_. .. _imagemagick: https://imagemagick.org/ .. _phash: https://web.archive.org/web/*/http://www.fmwconcepts.com/misc_tests/perceptual_hash_test_results_510/index.html .. _pillow: https://github.com/python-pillow/Pillow Manually Embedding and Extracting Art ------------------------------------- The ``embedart`` plugin provides a couple of commands for manually managing embedded album art: - ``beet embedart [-f IMAGE] QUERY``: embed images in every track of the albums matching the query. If the ``-f`` (``--file``) option is given, then use a specific image file from the filesystem; otherwise, each album embeds its own currently associated album art. The command prompts for confirmation before making the change unless you specify the ``-y`` (``--yes``) option. - ``beet embedart [-u IMAGE_URL] QUERY``: embed image specified in the URL into every track of the albums matching the query. The ``-u`` (``--url``) option can be used to specify the URL of the image to be used. The command prompts for confirmation before making the change unless you specify the ``-y`` (``--yes``) option. - ``beet extractart [-a] [-n FILE] QUERY``: extracts the images for all albums matching the query. The images are placed inside the album folder. You can specify the destination file name using the ``-n`` option, but leave off the extension: it will be chosen automatically. The destination filename is specified using the ``art_filename`` configuration option. It defaults to ``cover`` if it's not specified via ``-o`` nor the config. Using ``-a``, the extracted image files are automatically associated with the corresponding album. - ``beet extractart -o FILE QUERY``: extracts the image from an item matching the query and stores it in a file. You have to specify the destination file using the ``-o`` option, but leave off the extension: it will be chosen automatically. - ``beet clearart QUERY``: removes all embedded images from all items matching the query. The command prompts for confirmation before making the change unless you specify the ``-y`` (``--yes``) option. The files listed for confirmation are the ones matching the query independently of having an embedded art. However, only the files with an embedded art are updated, leaving untouched the files without. beetbox-beets-00724b7/docs/plugins/fuzzy.rst0000664000175000017500000000153515253035401020411 0ustar pieterpieterFuzzy Search Plugin =================== The ``fuzzy`` plugin provides a prefixed query that searches your library using fuzzy pattern matching. This can be useful if you want to find a track with complicated characters in the title. First, enable the plugin named ``fuzzy`` (see :ref:`using-plugins`). You'll then be able to use the ``~`` prefix to use fuzzy matching: :: $ beet ls '~Vareoldur' Sigur Rós - Valtari - Varðeldur Configuration ------------- To configure the plugin, make a ``fuzzy:`` section in your configuration file. The available options are: - **threshold**: The "sensitivity" of the fuzzy match. A value of 1.0 will show only perfect matches and a value of 0.0 will match everything. Default: 0.7. - **prefix**: The character used to designate fuzzy queries. Default: ``~``, which may need to be escaped in some shells. beetbox-beets-00724b7/docs/plugins/sonosupdate.rst0000664000175000017500000000114415253035401021562 0ustar pieterpieterSonosUpdate Plugin ================== The ``sonosupdate`` plugin lets you automatically update Sonos_'s music library whenever you change your beets library. To use ``sonosupdate`` plugin, enable it in your configuration (see :ref:`using-plugins`). To use the ``sonosupdate`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``sonosupdate`` extra pip install "beets[sonosupdate]" With that all in place, you'll see beets send the "update" command to your Sonos controller every time you change your beets library. .. _sonos: https://www.sonos.com/ beetbox-beets-00724b7/docs/plugins/index.rst0000664000175000017500000004411715253035401020334 0ustar pieterpieterPlugins ======= Plugins extend beets' core functionality. They add new commands, fetch additional data during import, provide new metadata sources, and much more. If beets by itself doesn't do what you want it to, you may just need to enable a plugin---or, if you want to do something new, :doc:`writing a plugin ` is easy if you know a little Python. .. _using-plugins: Using Plugins ------------- To use one of the plugins included with beets (see the rest of this page for a list), just use the ``plugins`` option in your :doc:`config.yaml ` file: .. code-block:: sh plugins: musicbrainz inline convert web The value for ``plugins`` can be a space-separated list of plugin names or a YAML list like ``[foo, bar]``. You can see which plugins are currently enabled by typing ``beet version``. Each plugin has its own set of options that can be defined in a section bearing its name: .. code-block:: yaml plugins: musicbrainz inline convert web convert: auto: true Some plugins have special dependencies that you'll need to install. The documentation page for each plugin will list them in the setup instructions. For some, you can use ``pip``'s "extras" feature to install the dependencies: .. code-block:: sh pip install "beets[fetchart,lyrics,lastgenre]" .. _metadata-source-plugin-configuration: Using Metadata Source Plugins ----------------------------- We provide several :ref:`autotagger_extensions` that fetch metadata from online databases. They share the following configuration options: .. include:: ./shared_metadata_source_config.rst .. toctree:: :hidden: absubmit acousticbrainz advancedrewrite albumtypes aura autobpm badfiles bareasc beatport bpd bpm bpsync bucket chroma convert deezer discogs duplicates edit embedart embyupdate export fetchart filefilter fish freedesktop fromfilename ftintitle fuzzy hook ihate importadded importsource importfeeds info inline ipfs keyfinder kodiupdate lastgenre lastimport limit listenbrainz loadext lyrics mbsync metasync missing mpdstats mpdupdate musicbrainz mbcollection mbpseudo mbsubmit parentwork permissions play playlist plexupdate random replace replaygain rewrite scrub smartplaylist sonosupdate spotify subsonicplaylist subsonicupdate substitute the thumbnails tidal titlecase types unimported web zero .. _autotagger_extensions: Autotagger Extensions --------------------- :doc:`chroma ` Use acoustic fingerprinting to identify audio files with missing or incorrect metadata. :doc:`deezer ` Search for releases in the Deezer_ database. :doc:`discogs ` Search for releases in the Discogs_ database. :doc:`fromfilename ` Guess metadata for untagged tracks from their filenames. :doc:`musicbrainz ` Search for releases in the MusicBrainz_ database. :doc:`mbpseudo ` Search for releases and pseudo-releases in the MusicBrainz_ database. :doc:`spotify ` Search for releases in the Spotify_ database. :doc:`tidal ` Search for releases in the Tidal_ catalog. .. _deezer: https://www.deezer.com/en/ .. _discogs: https://www.discogs.com .. _musicbrainz: https://www.musicbrainz.com .. _spotify: https://open.spotify.com/ .. _tidal: https://tidal.com/ Metadata -------- :doc:`absubmit ` Analyse audio with the streaming_extractor_music_ program and submit the metadata to an AcousticBrainz server :doc:`acousticbrainz ` Fetch various AcousticBrainz metadata :doc:`autobpm ` Use Librosa_ to calculate the BPM from the audio. :doc:`bpm ` Measure tempo using keystrokes. :doc:`bpsync ` Fetch updated metadata from Beatport. :doc:`edit ` Edit metadata from a text editor. :doc:`embedart ` Embed album art images into files' metadata. :doc:`fetchart ` Fetch album cover art from various sources. :doc:`ftintitle ` Move "featured" artists from the artist field to the title field. :doc:`keyfinder ` Use the KeyFinder_ program to detect the musical key from the audio. :doc:`importadded ` Use file modification times for guessing the value for the ``added`` field in the database. :doc:`lastgenre ` Fetch genres based on Last.fm tags. :doc:`lastimport ` Collect play counts from Last.fm. :doc:`lyrics ` Automatically fetch song lyrics. :doc:`mbsync ` Fetch updated metadata from MusicBrainz. :doc:`metasync ` Fetch metadata from local or remote sources :doc:`mpdstats ` Connect to MPD_ and update the beets library with play statistics (last_played, play_count, skip_count, rating). :doc:`parentwork ` Fetch work titles and works they are part of. :doc:`replaygain ` Calculate volume normalization for players that support it. :doc:`scrub ` Clean extraneous metadata from music files. :doc:`zero ` Nullify fields by pattern or unconditionally. .. _keyfinder: https://www.ibrahimshaath.co.uk/keyfinder/ .. _librosa: https://github.com/librosa/librosa/ .. _streaming_extractor_music: https://acousticbrainz.org/download Path Formats ------------ :doc:`albumtypes ` Format album type in path formats. :doc:`bucket ` Group your files into bucket directories that cover different field values ranges. :doc:`inline ` Use Python snippets to customize path format strings. :doc:`rewrite ` Substitute values in path formats. :doc:`advancedrewrite ` Substitute field values for items matching a query. :doc:`substitute ` As an alternative to :doc:`rewrite `, use this plugin. The main difference between them is that this plugin never modifies the files metadata. :doc:`the ` Move patterns in path formats (i.e., move "a" and "the" to the end). Interoperability ---------------- :doc:`aura ` A server implementation of the AURA_ specification. :doc:`badfiles ` Check audio file integrity. :doc:`embyupdate ` Automatically notifies Emby_ whenever the beets library changes. :doc:`fish ` Adds `Fish shell`_ tab autocompletion to ``beet`` commands. :doc:`importfeeds ` Keep track of imported files via ``.m3u`` playlist file(s) or symlinks. :doc:`ipfs ` Import libraries from friends and get albums from them via ipfs. :doc:`kodiupdate ` Automatically notifies Kodi_ whenever the beets library changes. :doc:`mpdupdate ` Automatically notifies MPD_ whenever the beets library changes. :doc:`play ` Play beets queries in your music player. :doc:`playlist ` Use M3U playlists to query the beets library. :doc:`plexupdate ` Automatically notifies Plex_ whenever the beets library changes. :doc:`smartplaylist ` Generate smart playlists based on beets queries. :doc:`sonosupdate ` Automatically notifies Sonos_ whenever the beets library changes. :doc:`thumbnails ` Get thumbnails with the cover art on your album folders. :doc:`subsonicupdate ` Automatically notifies Subsonic_ whenever the beets library changes. .. _aura: https://auraspec.readthedocs.io/en/latest/ .. _emby: https://emby.media .. _fish shell: https://fishshell.com/ .. _kodi: https://kodi.tv .. _plex: https://watch.plex.tv/ .. _sonos: https://www.sonos.com/ .. _subsonic: https://www.subsonic.org/pages/index.jsp Miscellaneous ------------- :doc:`bareasc ` Search albums and tracks with bare ASCII string matching. :doc:`bpd ` A music player for your beets library that emulates MPD_ and is compatible with `MPD clients`_. :doc:`convert ` Transcode music and embed album art while exporting to a different directory. :doc:`duplicates ` List duplicate tracks or albums. :doc:`export ` Export data from queries to a format. :doc:`filefilter ` Automatically skip files during the import process based on regular expressions. :doc:`fuzzy ` Search albums and tracks with fuzzy string matching. :doc:`hook ` Run a command when an event is emitted by beets. :doc:`ihate ` Automatically skip albums and tracks during the import process. :doc:`info ` Print music files' tags to the console. :doc:`loadext ` Load SQLite extensions. :doc:`mbcollection ` Maintain your MusicBrainz collection list. :doc:`mbsubmit ` Print an album's tracks in a MusicBrainz-friendly format. :doc:`missing ` List missing tracks. mstream_ A music streaming server + webapp that can be used alongside beets. :doc:`random ` Randomly choose albums and tracks from your library. :doc:`spotify ` Create Spotify playlists from the Beets library. :doc:`types ` Declare types for flexible attributes. :doc:`web ` An experimental Web-based GUI for beets. .. _mpd: https://www.musicpd.org/ .. _mpd clients: https://mpd.fandom.com/wiki/Clients .. _mstream: https://github.com/IrosTheBeggar/mStream .. _other-plugins: Other Plugins ------------- In addition to the plugins that come with beets, there are several plugins that are maintained by the beets community. To use an external plugin, there are two options for installation: - Make sure it's in the Python path (known as ``sys.path`` to developers). This just means the plugin has to be installed on your system (e.g., with a ``setup.py`` script or a command like ``pip`` or ``easy_install``). - Set the ``pluginpath`` config variable to point to the directory containing the plugin. (See :doc:`/reference/config`.) Once the plugin is installed, enable it by placing its name on the ``plugins`` line in your config file. Here are a few of the plugins written by the beets community: beets-aisauce_ Uses artificial intelligence to clean up or create metadata. beets-alternatives_ Manages external files. beet-amazon_ Adds Amazon.com as a tagger data source. beets-artistcountry_ Fetches the artist's country of origin from MusicBrainz. beets-autofix_ Automates repetitive tasks to keep your library in order. beets-autogenre_ Assigns genres to your library items using the :doc:`lastgenre ` and beets-xtractor_ plugins as well as additional rules. beets-audible_ Adds Audible as a tagger data source and provides other features for managing audiobook collections. beets-barcode_ Lets you scan or enter barcodes for physical media to search for their metadata. beetcamp_ Enables **bandcamp.com** autotagger with a fairly extensive amount of metadata. beetstream_ Server implementation of the `Subsonic API`_ specification, serving the beets library and (:doc:`smartplaylist ` plugin generated) M3U playlists, allowing you to stream your music on a multitude of clients. beets-bpmanalyser_ Analyses songs and calculates their tempo (BPM). beets-check_ Automatically checksums your files to detect corruption. `A cmus plugin`_ Integrates with the cmus_ console music player. beets-copyartifacts_ Helps bring non-music files along during import. beets-describe_ Gives you the full picture of a single attribute of your library items. drop2beets_ Automatically imports singles as soon as they are dropped in a folder (using Linux's ``inotify``). You can also set a sub-folders hierarchy to set flexible attributes by the way. dsedivec_ Has two plugins: ``edit`` and ``moveall``. beets-filetote_ Helps bring non-music extra files, attachments, and artifacts during imports and CLI file manipulation actions (``beet move``, etc.). beets-fillmissing_ Interactively prompts you to fill in missing or incomplete metadata fields for music tracks. beets-follow_ Lets you check for new albums from artists you like. beetFs_ Is a FUSE filesystem for browsing the music in your beets library. (Might be out of date.) beets-genrecanon_ Maps existing genres into a separate, user-defined canonical taxonomy while preserving the original genre metadata. beets-getlrc_ Fetches synced and non-synced lyrics and creates .lrc files to be used by compatible music players. beets-goingrunning_ Generates playlists to go with your running sessions. beets-ibroadcast_ Uploads tracks to the iBroadcast_ cloud service. beets-id3extract_ Maps arbitrary ID3 tags to beets custom fields. beets-importreplace_ Lets you perform regex replacements on incoming metadata. beets-jiosaavn_ Adds JioSaavn.com as a tagger data source. beets-more_ Finds versions of indexed releases with more tracks, like deluxe and anniversary editions. beets-mosaic_ Generates a montage of a mosaic from cover art. beets-mpd-utils_ Plugins to interface with MPD_. Comes with ``mpd_tracker`` (track play/skip counts from MPD) and ``mpd_dj`` (auto-add songs to your queue.) BeetNik_ A desktop music player for beets libraries. Browse and play your collection by album, artist, or recent additions. beets-noimport_ Adds and removes directories from the incremental import skip list. beets-originquery_ Augments MusicBrainz queries with locally-sourced data to improve autotagger results. beets-plexsync_ Allows you to sync your Plex library with your beets library, create smart playlists in Plex, and import online playlists (from services like Spotify) into Plex. beets-setlister_ Generate playlists from the setlists of a given artist. beet-summarize_ Can compute lots of counts and statistics about your music library. beets-usertag_ Lets you use keywords to tag and organize your music. beets-webm3u_ Serves the (:doc:`smartplaylist ` plugin generated) M3U playlists via HTTP. beets-webrouter_ Serves multiple beets webapps (e.g. :doc:`web `, beets-webm3u_, beetstream_, :doc:`aura `) using a single command/process/host/port, each under a different path. whatlastgenre_ Fetches genres from various music sites. beets-xtractor_ Extracts low- and high-level musical information from your songs. beets-ydl_ Downloads audio from youtube-dl sources and import into beets. beets-ytimport_ Download and import your liked songs from YouTube into beets. beets-yearfixer_ Attempts to fix all missing ``original_year`` and ``year`` fields. beets-youtube_ Adds YouTube Music as a tagger data source. .. _a cmus plugin: https://github.com/coolkehon/beets/blob/master/beetsplug/cmus.py .. _beet-amazon: https://github.com/jmwatte/beet-amazon .. _beet-musicbrainz-collection: https://github.com/jeffayle/Beet-MusicBrainz-Collection/ .. _beet-summarize: https://github.com/steven-murray/beet-summarize .. _beetcamp: https://github.com/snejus/beetcamp .. _beetfs: https://github.com/jbaiter/beetfs .. _beetnik: https://forge.kanis.fr/ivan/beetnik-desktop .. _beets-aisauce: https://github.com/metasauce/beets-aisauce .. _beets-alternatives: https://github.com/geigerzaehler/beets-alternatives .. _beets-artistcountry: https://github.com/agrausem/beets-artistcountry .. _beets-audible: https://github.com/Neurrone/beets-audible .. _beets-autofix: https://github.com/adamjakab/BeetsPluginAutofix .. _beets-autogenre: https://github.com/mgoltzsche/beets-autogenre .. _beets-barcode: https://github.com/8h2a/beets-barcode .. _beets-bpmanalyser: https://github.com/adamjakab/BeetsPluginBpmAnalyser .. _beets-check: https://github.com/geigerzaehler/beets-check .. _beets-copyartifacts: https://github.com/adammillerio/beets-copyartifacts .. _beets-describe: https://github.com/adamjakab/BeetsPluginDescribe .. _beets-filetote: https://github.com/gtronset/beets-filetote .. _beets-fillmissing: https://github.com/amiv1/beets-fillmissing .. _beets-follow: https://github.com/nolsto/beets-follow .. _beets-genrecanon: https://codeberg.org/gbcox/beets-genrecanon .. _beets-getlrc: https://github.com/jaedonswanson/beets-getlrc .. _beets-goingrunning: https://pypi.org/project/beets-goingrunning .. _beets-ibroadcast: https://github.com/ctrueden/beets-ibroadcast .. _beets-id3extract: https://github.com/bcotton/beets-id3extract .. _beets-importreplace: https://github.com/edgars-supe/beets-importreplace .. _beets-jiosaavn: https://github.com/arsaboo/beets-jiosaavn .. _beets-more: https://forgejo.sny.sh/sun/beetsplug/src/branch/main/more .. _beets-mosaic: https://github.com/SusannaMaria/beets-mosaic .. _beets-mpd-utils: https://github.com/thekakkun/beets-mpd-utils .. _beets-noimport: https://gitlab.com/tiago.dias/beets-noimport .. _beets-originquery: https://github.com/x1ppy/beets-originquery .. _beets-plexsync: https://github.com/arsaboo/beets-plexsync .. _beets-setlister: https://github.com/tomjaspers/beets-setlister .. _beets-usertag: https://github.com/edgars-supe/beets-usertag .. _beets-webm3u: https://github.com/mgoltzsche/beets-webm3u .. _beets-webrouter: https://github.com/mgoltzsche/beets-webrouter .. _beets-xtractor: https://github.com/adamjakab/BeetsPluginXtractor .. _beets-ydl: https://github.com/vmassuchetto/beets-ydl .. _beets-yearfixer: https://github.com/adamjakab/BeetsPluginYearFixer .. _beets-youtube: https://github.com/arsaboo/beets-youtube .. _beets-ytimport: https://github.com/mgoltzsche/beets-ytimport .. _beetstream: https://github.com/BinaryBrain/Beetstream .. _cmus: https://sourceforge.net/projects/cmus/ .. _drop2beets: https://github.com/martinkirch/drop2beets .. _dsedivec: https://github.com/dsedivec/beets-plugins .. _ibroadcast: https://ibroadcast.com/ .. _subsonic api: https://www.subsonic.org/pages/api.jsp .. _whatlastgenre: https://github.com/YetAnotherNerd/whatlastgenre/tree/master/plugin/beets beetbox-beets-00724b7/docs/plugins/absubmit.rst0000664000175000017500000000551615253035401021033 0ustar pieterpieterAcousticBrainz Submit Plugin ============================ The ``absubmit`` plugin lets you submit acoustic analysis results to an AcousticBrainz_ server. This plugin is now deprecated since the AcousicBrainz project has been shut down. As an alternative the beets-xtractor_ plugin can be used. Warning ------- The AcousticBrainz project has shut down. To use this plugin you must set the ``base_url`` configuration option to a server offering the AcousticBrainz API. Installation ------------ The ``absubmit`` plugin requires the streaming_extractor_music_ program to run. Its source can be found on GitHub_, and while it is possible to compile the extractor from source, AcousticBrainz would prefer if you used their binary (see the AcousticBrainz FAQ_). Then, install ``beets`` with ``absubmit`` extra pip install "beets[absubmit]" Lastly, enable the plugin in your configuration (see :ref:`using-plugins`). Submitting Data --------------- To run the analysis program and upload its results, type: :: beet absubmit [-f] [-d] [QUERY] By default, the command will only look for AcousticBrainz data when the tracks don't already have it; the ``-f`` or ``--force`` switch makes it refetch data even when it already exists. You can use the ``-d`` or ``--dry`` switch to check which files will be analyzed, before you start a longer period of processing. The plugin works on music with a MusicBrainz track ID attached. The plugin will also skip music that the analysis tool doesn't support. streaming_extractor_music_ currently supports files with the extensions ``mp3``, ``ogg``, ``oga``, ``flac``, ``mp4``, ``m4a``, ``m4r``, ``m4b``, ``m4p``, ``aac``, ``wma``, ``asf``, ``mpc``, ``wv``, ``spx``, ``tta``, ``3g2``, ``aif``, ``aiff`` and ``ape``. Configuration ------------- To configure the plugin, make a ``absubmit:`` section in your configuration file. The available options are: - **auto**: Analyze every file on import. Otherwise, you need to use the ``beet absubmit`` command explicitly. Default: ``no`` - **extractor**: The absolute path to the streaming_extractor_music_ binary. Default: search for the program in your ``$PATH`` - **force**: Analyze items and submit of AcousticBrainz data even for tracks that already have it. Default: ``no``. - **pretend**: Do not analyze and submit of AcousticBrainz data but print out the items which would be processed. Default: ``no``. - **base_url**: The base URL of the AcousticBrainz server. The plugin has no function if this option is not set. Default: None .. _acousticbrainz: https://acousticbrainz.org .. _beets-xtractor: https://github.com/adamjakab/BeetsPluginXtractor .. _faq: https://acousticbrainz.org/faq .. _github: https://github.com/MTG/essentia .. _pip: https://pip.pypa.io .. _requests: https://requests.readthedocs.io/en/latest/ .. _streaming_extractor_music: https://essentia.upf.edu/ beetbox-beets-00724b7/docs/plugins/discogs.rst0000664000175000017500000002024215253035401020651 0ustar pieterpieterDiscogs Plugin ============== The ``discogs`` plugin extends the autotagger's search capabilities to include matches from the Discogs_ database. Files can be imported as albums or as singletons. Since Discogs_ matches are always based on Discogs_ releases, the album tag is written even to singletons. This enhances the importers results when reimporting as (full or partial) albums later on. .. _discogs: https://discogs.com Genre Mapping ------------- Discogs uses ``styles`` for the more specific classifications and ``genres`` for the broader ones. The plugin therefore uses Discogs ``styles`` as the primary source for the beets ``genres`` field, because beets treats ``genres`` as the main multi-valued genre field. The broader Discogs ``genres`` values are written to the beets ``style`` field. If :conf:`plugins.discogs:append_style_genre` is enabled, those broader Discogs ``genres`` values are also appended to beets ``genres``. For example, a Discogs release with ``styles`` set to ``["Techno"]`` and ``genres`` set to ``["Electronic"]`` becomes beets ``genres`` = ``["Techno"]`` and ``style`` = ``"Electronic"`` by default. With ``append_style_genre`` enabled, beets ``genres`` becomes ``["Techno", "Electronic"]``. Installation ------------ To use the ``discogs`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``discogs`` extra .. code-block:: bash pip install "beets[discogs]" You will also need to register for a Discogs_ account, and provide authentication credentials via a personal access token or an OAuth2 authorization. Matches from Discogs will now show up during import alongside matches from MusicBrainz. The search terms sent to the Discogs API are based on the artist and album tags of your tracks. If those are empty no query will be issued. If you have a Discogs ID for an album you want to tag, you can also enter it at the "enter Id" prompt in the importer. OAuth Authorization ~~~~~~~~~~~~~~~~~~~ The first time you run the :ref:`import-cmd` command after enabling the plugin, it will ask you to authorize with Discogs by visiting the site in a browser. Subsequent runs will not require re-authorization. Authentication via Personal Access Token ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As an alternative to OAuth, you can get a token from Discogs and add it to your configuration. To get a personal access token (called a "user token" in the python3-discogs-client_ documentation): 1. login to Discogs_; 2. visit the `Developer settings page `_; 3. press the *Generate new token* button; 4. copy the generated token; 5. place it in your configuration in the ``discogs`` section as the ``user_token`` option: .. code-block:: yaml discogs: user_token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" Configuration ------------- This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`. Default ~~~~~~~ .. code-block:: yaml discogs: apikey: REDACTED apisecret: REDACTED tokenfile: discogs_token.json user_token: index_tracks: no append_style_genre: no separator: ', ' strip_disambiguation: yes featured_string: Feat. extra_tags: [] anv: artist_credit: yes artist: no album_artist: no data_source_mismatch_penalty: 0.5 search_limit: 5 .. conf:: index_tracks :default: no Index tracks (see the `Discogs guidelines`_) along with headers, mark divisions between distinct works on the same release or within works. When enabled, beets will incorporate the names of the divisions containing each track into the imported track's title. For example, importing `divisions album`_ would result in track names like: .. code-block:: text Messiah, Part I: No.1: Sinfony Messiah, Part II: No.22: Chorus- Behold The Lamb Of God Athalia, Act I, Scene I: Sinfonia whereas with ``index_tracks`` disabled you'd get: .. code-block:: text No.1: Sinfony No.22: Chorus- Behold The Lamb Of God Sinfonia This option is useful when importing classical music. .. conf:: append_style_genre :default: no Appends the broader Discogs ``genres`` values to beets ``genres`` after the specific Discogs ``styles`` values already stored there. See the Genre Mapping section above for the default field mapping and an example. .. conf:: separator :default: ", " How to join multiple Discogs ``genres`` values when writing the beets ``style`` field. .. versionchanged:: 2.7.0 This option now only applies to the ``style`` field as beets now only handles lists of ``genres``. .. conf:: strip_disambiguation :default: yes Discogs uses strings like ``"(4)"`` to mark distinct artists and labels with the same name. If you'd like to use the Discogs disambiguation in your tags, you can disable this option. .. conf:: featured_string :default: Feat. Configure the string used for noting featured artists. Useful if you prefer ``Featuring`` or ``ft.``. .. conf:: extra_tags :default: [] By default, beets will use only the artist and album to query Discogs. Additional tags to be queried can be supplied with the ``extra_tags`` setting. This setting should improve the autotagger results if the metadata with the given tags match the metadata returned by Discogs. Tags supported by this setting: * ``barcode`` * ``catalognum`` * ``country`` * ``label`` * ``media`` * ``year`` Example: .. code-block:: yaml discogs: extra_tags: [barcode, catalognum, country, label, media, year] .. conf:: anv This configuration option is dedicated to handling Artist Name Variations (ANVs). Sometimes a release credits artists differently compared to the majority of their work. For example, "Basement Jaxx" may be credited as "Tha Jaxx" or "The Basement Jaxx". You can select any combination of these config options to control where beets writes and stores the variation credit. The default, shown below, writes variations to the artist_credit field. .. code-block:: yaml discogs: anv: artist_credit: yes artist: no album_artist: no Contributor credits ~~~~~~~~~~~~~~~~~~~ When Discogs provides artist roles on a track, beets uses them to separate main artists from other credited contributors. Main artist fields such as ``artist``, ``artists``, ``artist_credit``, ``artists_credit``, ``artist_id``, and ``artists_ids`` keep the primary artist credits, while featured artists from track roles are appended using :conf:`plugins.discogs:featured_string`. Discogs contributor roles are also imported into beets' multi-value performer fields when available. This includes remixer, lyricist, composer, and arranger credits, which populate ``remixers``, ``lyricists``, ``composers``, and ``arrangers`` respectively. .. include:: ./shared_metadata_source_config.rst .. _discogs guidelines: https://support.discogs.com/hc/en-us/articles/360005055373-Database-Guidelines-12-Tracklisting#Index_Tracks_And_Headings .. _divisions album: https://www.discogs.com/release/2026070-Handel-Sutherland-Kirkby-Kwella-Nelson-Watkinson-Bowman-Rolfe-Johnson-Elliott-Partridge-Thomas-The-A Troubleshooting --------------- Several issues have been encountered with the Discogs API. If you have one, please start by searching for `a similar issue on the repo `_. Here are two things you can try: - Try deleting the token file (``~/.config/beets/discogs_token.json`` by default) to force re-authorization. - Make sure that your system clock is accurate. The Discogs servers can reject your request if your clock is too out of sync. Matching tracks by Discogs ID is not yet supported. The ``--group-albums`` option in album import mode provides an alternative to singleton mode for autotagging tracks that are not in album-related folders. .. _python3-discogs-client: https://github.com/joalla/discogs_client beetbox-beets-00724b7/docs/plugins/autobpm.rst0000664000175000017500000000326115253035401020667 0ustar pieterpieterAutoBPM Plugin ============== The ``autobpm`` plugin uses the Librosa_ library to calculate the BPM of a track from its audio data and store it in the ``bpm`` field of your database. It does so automatically when importing music or through the ``beet autobpm [QUERY]`` command. Install ------- To use the ``autobpm`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``autobpm`` extra .. code-block:: bash pip install "beets[autobpm]" Configuration ------------- To configure the plugin, make a ``autobpm:`` section in your configuration file. Default ~~~~~~~ .. code-block:: yaml autobpm: auto: yes force: no beat_track_kwargs: {} quiet: no .. conf:: auto :default: yes Analyze every file on import. Otherwise, you need to use the ``beet autobpm`` command explicitly. .. conf:: force :default: no Calculate a BPM even for files that already have a ``bpm`` value. Can also be set using the ``-f`` or ``--force`` flag. .. conf:: overwrite :default: no .. deprecated:: 2.9 Use ``force`` instead. .. conf:: beat_track_kwargs :default: {} Any extra keyword arguments that you would like to provide to librosa's beat_track_ function call, for example: .. code-block:: yaml autobpm: beat_track_kwargs: start_bpm: 160 .. conf:: quiet :default: no Suppress the message indicating that a file already has a ``bpm`` value. Can also be set using the ``-q`` or ``--quiet`` flag. .. _beat_track: https://librosa.org/doc/latest/api/generated/librosa.beat.beat_track.html .. _librosa: https://github.com/librosa/librosa/ beetbox-beets-00724b7/docs/plugins/export.rst0000664000175000017500000000557315253035401020551 0ustar pieterpieterExport Plugin ============= The ``export`` plugin lets you get data from the items and export the content as JSON_, CSV_, or XML_. .. _csv: https://fileinfo.com/extension/csv .. _json: https://www.json.org .. _xml: https://fileinfo.com/extension/xml Enable the ``export`` plugin (see :ref:`using-plugins` for help). Then, type ``beet export`` followed by a :doc:`query ` to get the data from your library. For example, run this: :: $ beet export beatles to print a JSON file containing information about your Beatles tracks. Command-Line Options -------------------- The ``export`` command has these command-line options: - ``--include-keys`` or ``-i``: Choose the properties to include in the output data. The argument is a comma-separated list of simple glob patterns where ``*`` matches any string. For example: :: $ beet export -i 'title,mb*' beatles will include the ``title`` property and all properties starting with ``mb``. You can add the ``-i`` option multiple times to the command line. - ``--library`` or ``-l``: Show data from the library database instead of the files' tags. - ``--album`` or ``-a``: Show data from albums instead of tracks (implies ``--library``). - ``--output`` or ``-o``: Path for an output file. If not informed, will print the data in the console. - ``--append``: Appends the data to the file instead of writing. - ``--format`` or ``-f``: Specifies the format the data will be exported as. If not informed, JSON will be used by default. The format options include csv, json, `jsonlines `_ and xml. Configuration ------------- To configure the plugin, make a ``export:`` section in your configuration file. For JSON export, these options are available under the ``json`` and ``jsonlines`` keys: - **ensure_ascii**: Escape non-ASCII characters with ``\uXXXX`` entities. - **indent**: The number of spaces for indentation. - **separators**: A ``[item_separator, dict_separator]`` tuple. - **sort_keys**: Sorts the keys in JSON dictionaries. Those options match the options from the `Python json module`_. Similarly, these options are available for the CSV format under the ``csv`` key: - **delimiter**: Used as the separating character between fields. The default value is a comma (,). - **dialect**: The kind of CSV file to produce. The default is ``excel``. These options match the options from the `Python csv module`_. .. _python csv module: https://docs.python.org/3/library/csv.html#csv-fmt-params .. _python json module: https://docs.python.org/3/library/json.html#basic-usage The default options look like this: :: export: json: formatting: ensure_ascii: false indent: 4 separators: [',' , ': '] sort_keys: true csv: formatting: delimiter: ',' dialect: excel beetbox-beets-00724b7/docs/plugins/acousticbrainz.rst0000664000175000017500000000465715253035401022252 0ustar pieterpieterAcousticBrainz Plugin ===================== The ``acousticbrainz`` plugin gets acoustic-analysis information from the AcousticBrainz_ project. This plugin is now deprecated since the AcousicBrainz project has been shut down. As an alternative the beets-xtractor_ plugin can be used. .. _acousticbrainz: https://acousticbrainz.org/ .. _beets-xtractor: https://github.com/adamjakab/BeetsPluginXtractor Enable the ``acousticbrainz`` plugin in your configuration (see :ref:`using-plugins`) and run it by typing: :: $ beet acousticbrainz [-f] [QUERY] By default, the command will only look for AcousticBrainz data when the tracks doesn't already have it; the ``-f`` or ``--force`` switch makes it re-download data even when it already exists. If you specify a query, only matching tracks will be processed; otherwise, the command processes every track in your library. For all tracks with a MusicBrainz recording ID, the plugin currently sets these fields: - ``average_loudness`` - ``bpm`` - ``chords_changes_rate`` - ``chords_key`` - ``chords_number_rate`` - ``chords_scale`` - ``danceable`` - ``gender`` - ``genre_rosamerica`` - ``initial_key`` (This is a built-in beets field, which can also be provided by :doc:`/plugins/keyfinder`.) - ``key_strength`` - ``mood_acoustic`` - ``mood_aggressive`` - ``mood_electronic`` - ``mood_happy`` - ``mood_party`` - ``mood_relaxed`` - ``mood_sad`` - ``moods_mirex`` - ``rhythm`` - ``timbre`` - ``tonal`` - ``voice_instrumental`` Warning ------- The AcousticBrainz project has shut down. To use this plugin you must set the ``base_url`` configuration option to a server offering the AcousticBrainz API. Automatic Tagging ----------------- To automatically tag files using AcousticBrainz data during import, just enable the ``acousticbrainz`` plugin (see :ref:`using-plugins`). When importing new files, beets will query the AcousticBrainz API using MBID and set the appropriate metadata. Configuration ------------- To configure the plugin, make a ``acousticbrainz:`` section in your configuration file. The available options are: - **auto**: Enable AcousticBrainz during ``beet import``. Default: ``yes``. - **force**: Download AcousticBrainz data even for tracks that already have it. Default: ``no``. - **tags**: Which tags from the list above to set on your files. Default: [] (all). - **base_url**: The base URL of the AcousticBrainz server. The plugin has no function if this option is not set. Default: None beetbox-beets-00724b7/docs/plugins/importsource.rst0000664000175000017500000000540015253035401021750 0ustar pieterpieterImportSource Plugin =================== The ``importsource`` plugin adds a ``source_path`` field to every item imported to the library which stores the original media files' paths. Using this plugin makes most sense when the general importing workflow is using ``beet import --copy``. Additionally the plugin interactively suggests deletion of original source files whenever items are removed from the Beets library. To enable it, add ``importsource`` to the list of plugins in your configuration (see :ref:`using-plugins`). Tracking Source Paths --------------------- The primary use case for the plugin is tracking the original location of imported files using the ``source_path`` field. Consider this scenario: you've imported all directories in your current working directory using: .. code-block:: bash beet import --flat --copy */ Later, for instance if the import didn't complete successfully, you'll need to rerun the import but don't want Beets to re-process the already successfully imported directories. You can view which files were successfully imported using: .. code-block:: bash beet ls source_path:$PWD --format='$source_path' To extract just the directory names, pipe the output to standard UNIX utilities: .. code-block:: bash beet ls source_path:$PWD --format='$source_path' | awk -F / '{print $(NF-1)}' | sort -u This might help to find out what's left to be imported. Removal Suggestion ------------------ Another feature of the plugin is suggesting removal of original source files when items are deleted from your library. Consider this scenario: you imported an album using: .. code-block:: bash beet import --copy --flat ~/Desktop/interesting-album-to-check/ After listening to that album and deciding it wasn't good, you want to delete it from your library as well as from your ``~/Desktop``, so you run: .. code-block:: bash beet remove --delete source_path:$HOME/Desktop/interesting-album-to-check After approving the deletion, the plugin will prompt: .. code-block:: text The item: /Interesting Album/01 Interesting Song.flac is originated from: /Desktop/interesting-album-to-check/01-interesting-song.flac What would you like to do? Delete the item's source, Recursively delete the source's directory, do Nothing, do nothing and Stop suggesting to delete items from this album? Configuration ------------- To configure the plugin, make an ``importsource:`` section in your configuration file. There is one option available: - **suggest_removal**: By default ``importsource`` suggests to remove the original directories / files from which the items were imported whenever library items (and files) are removed. To disable these prompts set this option to ``no``. Default: ``yes``. beetbox-beets-00724b7/docs/plugins/mbsync.rst0000664000175000017500000000335515253035401020517 0ustar pieterpieterMBSync Plugin ============= This plugin provides the ``mbsync`` command, which lets you synchronize metadata for albums and tracks that have external data source IDs. This is useful for syncing your library with online data or when changing configuration options that affect tag writing. If your music library already contains correct tags, you can speed up the initial import by importing files "as-is" and then using ``mbsync`` to write tags according to your beets configuration. Usage ----- Enable the ``mbsync`` plugin in your configuration (see :ref:`using-plugins`) and then run ``beet mbsync QUERY`` to fetch updated metadata for a part of your collection (or omit the query to run over your whole library). ID lookups use each item's stored ``data_source``. If a row has no ``data_source``, ``mbsync`` falls back to ``MusicBrainz``. This plugin treats albums and singletons (non-album tracks) separately. It first processes all matching singletons and then proceeds on to full albums. The same query is used to search for both kinds of entities. The command has a few command-line options: - To preview the changes that would be made without applying them, use the ``-p`` (``--pretend``) flag. - By default, files will be moved (renamed) according to their metadata if they are inside your beets library directory. To disable this, use the ``-M`` (``--nomove``) command-line option. - If you have the ``import.write`` configuration option enabled, then this plugin will write new metadata to files' tags. To disable this, use the ``-W`` (``--nowrite``) option. - To customize the output of unrecognized items, use the ``-f`` (``--format``) option. The default output is ``format_item`` or ``format_album`` for items and albums, respectively. beetbox-beets-00724b7/docs/plugins/mpdupdate.rst0000664000175000017500000000244315253035401021204 0ustar pieterpieterMPDUpdate Plugin ================ ``mpdupdate`` is a very simple plugin for beets that lets you automatically update MPD_'s index whenever you change your beets library. .. _mpd: https://www.musicpd.org/ To use ``mpdupdate`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then, you'll probably want to configure the specifics of your MPD server. You can do that using an ``mpd:`` section in your ``config.yaml``, which looks like this: :: mpd: host: localhost port: 6600 password: seekrit With that all in place, you'll see beets send the "update" command to your MPD server every time you change your beets library. If you want to communicate with MPD over a Unix domain socket instead over TCP, just give the path to the socket in the filesystem for the ``host`` setting. (Any ``host`` value starting with a slash or a tilde is interpreted as a domain socket.) Configuration ------------- The available options under the ``mpd:`` section are: - **host**: The MPD server name. Default: The ``$MPD_HOST`` environment variable if set, falling back to ``localhost`` otherwise. - **port**: The MPD server port. Default: The ``$MPD_PORT`` environment variable if set, falling back to 6600 otherwise. - **password**: The MPD server password. Default: None. beetbox-beets-00724b7/docs/plugins/embyupdate.rst0000664000175000017500000000274715253035401021367 0ustar pieterpieterEmbyUpdate Plugin ================= ``embyupdate`` is a plugin that lets you automatically update Emby_'s library whenever you change your beets library. To use it, first enable the your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``embyupdate`` extra .. code-block:: bash pip install "beets[embyupdate]" Then, you'll want to configure the specifics of your Emby server. You can do that using an ``emby`` section in your ``config.yaml`` .. code-block:: yaml emby: host: localhost port: 8096 username: user apikey: apikey With that all in place, you'll see beets send the "update" command to your Emby server every time you change your beets library. .. _emby: https://emby.media/ Configuration ------------- The available options under the ``emby:`` section are: - **host**: The Emby server host. You also can include ``http://`` or ``https://``. Default: ``localhost`` - **port**: The Emby server port. Default: 8096 - **username**: A username of an Emby user that is allowed to refresh the library. - **userid**: A user ID of an Emby user that is allowed to refresh the library. (This is only necessary for private users i.e. when the user is hidden from login screens) - **apikey**: An Emby API key for the user. - **password**: The password for the user. (This is only necessary if no API key is provided.) You can choose to authenticate either with ``apikey`` or ``password``, but only one of those two is required. beetbox-beets-00724b7/docs/plugins/beetsweb.png0000664000175000017500000010176615253035401021005 0ustar pieterpieter‰PNG  IHDR&röçáñPLTEJd}’„qJ‹Íh–¹¾Á¯µ»¹¾Ä�Ÿ  (((NKH:::RRRrrrÕÕÕËËÌÆÆÅúúú___ÿÿÿýþþüüýûûüúúúøøù÷÷÷õõõóóôðððòòòîîîìììêêêéèèçççåååãããâââàààßßßÝÝÝÚÚÚØØØ×××ÖÖÖÔÔÔÒÒÒÏÏÏÍÍÍËËËÉÉÉÇÇÇÄÄÄÁÁÁ¾¾¾»»¼¹¸¸¶¶¶³³³±±±°°°¯¯¯®®®¬«ª§§§¡  ˜˜—“““���‰ˆˆ€€uvtjjjeeeccc___[[[YYYVVVRRRNNNKKKIIIFFFCCC???<<<888333111///+++&&&"""/D$IZ2`DpS‚7c†G[l.Us1E]!4N*><& Bw`“;•Ëq¢‘x¯š~¬£�³«šºÞ•ÖíºìàËïæØ÷ïÞ÷ïçûõíþùòÿý÷ÿÿýþþÿöýÿí÷þéñøÜãêÜãëÝäëàæìßçïáéðäëñåíôÜáæÓÚâÔÖÙÅÍÔ¿Å̵ÀË®·À¦«±š¢¬�™£~Š–]envfR‰qT‰g@…]+yO iBc&T S3]G,rX9Šye¢‰e˜{Rº¥ŒÂ¬˜Ë·¡ÖðæÔ½ØÎÃÝÖÌÑǾÊÀ¸Ãº±¼´¬¹°£�µÊ¨½Ñ³ÈÙ¿ÐÞÆÖãÓàëÌÜêØæóßêûÓËøÌßû¶Ò÷äèë§Âí§Ìú˜¼ø‡²ñw›õyºýp¶üi±úe®ùa­ù]ª÷W¦öS¢ôNŸóKœðGšïH›ñ> ö*šô�ï^°ükµþ_uŒm‹¤|–«„›³Œ¢º“¬Ãœ¬»|£¼u“±Y¡Jq’anzóuqó¿eâ¤K±s øÝ�dz\AŒ×lº­­õ¼·ö­™ò�€òOkóîBñ= ínJïöŸœïVP£ ZÝ™tRNSþþÁþÖÖ¿ÅÓÁÄul`E¿ÖÖüv}Y|�€ŸIDATxÚÔÎE‚„@ …aV,a€çÕzÿó�%-è¸< ¼ò‘•Å®Çl°¹`‰ÃÚöðŽ‚ïòø«þðm¾½Û‘î¡,³âX@Ü¿Îí|¥Á‡¡ù&Ä66Þ%Æ·;áÇŽ–|¢Ä;}F¾W‹:lûÆ¢oß¶|[ò-°áó^ßæ|ƒŸ¨Våe–7’ðï9à˜n‚¿¯I|ÕOûâõ8àS_1BŠ áE%˜úÀØÇ3òmÞgÕ׊�¸úlûŒ|ÞékÆ×½ÏÔǵðµå>+¾y¤þ\fy-OÒÐ÷ý ¤Û }7ZK¯k>^ úÂŒ½àëüôU¿µ?ì‡Ã~/l_dy•”’¤„™/«õ6’ ž#¬æ…ÄZff{™Èãõ^…™ÉL ÑݾÅ2Û–òŽ®¶K=õ•3Ñ$Rø|ž†SUýOÛeš·rÕÊù,b »µoîùU+æ±Yà8KXoEjå|áÎax€y¾Ü†�0Œ¾QÀŠø”�Q7R²U€ÏCùnà;ÐmŠÏêñYC|*º=Ÿ7ÉgÍò1€®Éó…B!oûDÙ6™"\,’訂:³œ#„ˆÄ&/—ËÇѳ²^¡­­½­­˜œ…gÞ•Ä�*"Cu?ø‘Á'/áåçŠ;ð`ïÿhùb–Iƒ2’3h“iÂzR²ÄÙêXÿ–þ±êÙ$Bp!$‹-W¶lÛR)K2É­ ÞÓí¬·¡ýÅÙL€À&¹¯.®ÜÃqãÜÞ¯’�/©À.ÛÂÂ*<ƒ[ùpTÿ çËÈп¿G¸”@œÒÂ�‹o×,Ÿ‡ðŽ ÞŸK?UºûÛ(‰øn‰Ôås‰ ¢àù(äË™‰ôÊU«ÒJ0mÛdªt€Žêðh¸Úá€RЉå‘Je¤Ü<¼Ð¶a#hC{Q 0¥»�ù¶ûðw°À=8 Ç2؃h‰ç�Cµtd}¾ áãl6ôÝÅ™Š3)“œ»‰É™Ý®E`âãÆãù%¾oS>Ž`b�p6Ý¥a¾ ù¸E¾@—ø8#ö,™K¯²m¢9¯µ‰²ŠÍ¯Þ@UKÌyóŽ�Ž8�_€^ÛjTÛ"&©»­³m²?ûÂÁ]\ t¼xp§àÞšÿÛ)�yµx`û`þù§ÿà�PÕ|ßGÃW¹ìªT:•Ö‚Û&Óµ”Z³ ãÚd=ÓJ)ÍΗGG]—Œ–/0mKudé¸6IYO�l@×fHq�0hˆKéR)»—†-¸(LpuˆñSGã9�ñU�>tºå§ôwv œþiñ™Ÿ¶ë#_/éøtçÀá¯ì¿^’Þ+T(ß>tòA¸½-ï¯n¾?^�`ÄwâK ¾ ããàßôu ò%¼“09Û$‰TFKéÚ ´‰Ö®Mð§Iy=K³eí«Qí)ÈWã¬pC ¸W˜Œu1Zamè$t1ãîùø!†¾ûõÇé=-»»?º:½÷£]}-—¦|÷Çôî¯~˜¡Ž|¹cj$À–È%P³|…1wº òu?¬Ë—Žgš„°{|~z•‰˜´qm2ªÜO“a�m“ ,ÃÏ—m‡T*;–/p âK M6XA›€"¥•j úÀmrQÈÒ¿{Ö¼óÂË/~´«÷½ç_~áý?"k¿¼ªåùï[&¤ÑTê!¬GI/Ÿ`É|q “BîYÚd¦©KUÛ%ðìðpµ$Á2r~Ùv ȶIISól›Àß°Ð& eÊÔÙ’Ú@-ˆ7È/4Ò¶‰”¥Ö=k¿Ù3wþ<ÝÛºoÎüù ¾öËÚ°�Ì·?íÜ£QlPM߯7á§™æùääs ò¹LÁS~XEm›ÌòÜçÍ ÿ?��Ö05síèHeÓ¦M•ÊèSsì“kß°aãæ�öÇÉD0@À€“�1´p¢8,ÑÁz÷`‚Ÿ……H³ ð±^ãáÄ×!|5tú7Á×~¼«·uïÌYRÂï Y\˵_íà&Á¦®ýt—ÂÀiŽÑßÔ¿?.°^ï+_‡ò]Ôø†ø~"ƉïǼt¶�I¥ÓZcr ÚÄ}¦u²kxÌþó;6Ü5[[.H';¯×Úäz§óì£íO“Mö§IÇð<ðÝä n‹3š(z3¢$�´¡ >D¡ñ‰ë†p>LPä©Òwoò-¿n7[ ¹çö°õ-ÿeŸýƒ]ø÷¿}ƒ‡ÿË�ž¼2ñè[øè‡ð½:|—êøÁchØëº|ïnùήÇ×1Û#¶Kâ}·m‰z5éÄÚÎîžîεIí¡t¼û:¨æEÑ[7qÝ…uk2փ׀Á &Hq[ã|À�(ÏÚ´¥…©—°ƒµ$ä1a|CédjA:·W­Ïg3ûâF–2™Ô.cÎçö™séì¾�&”�W å{·á› OUäQ„ ¶âzØÿ„vl‘Wþò}�vÚÓ%Ûñpj§ýïÙ×Að€ßò­jËFºŽ¾Åó¿ÃÇ&¿?®úÍßèÿ~»¦?L™{w(£�÷ÿ©ž#[$\é²{—L¼]s’�wNGÁåLöLl¢Õd‰î#t–ªq›ƒ_2ÌwBs±îñó?RRªn'e„H¨ uœ™_¹52¥öTü˜øa~>÷üÕ8˜ž?®eÌ|x9ó5ñ‹´àçÀ”1󳉓_ÿþm-‹Ô:&R&‹VuQÖC`㈈L•ÆêX8ujŸÛˆ�yÆQB¾]¸ö�ÌÇKÍü@L|KeÎ|LïñÝmÐàSãÖ<Û‚/d¼žïîÏô#¾BÅóÉæ+ŸäW—ŸÔµM(¦[ÿòéóQ#{ÈôæXhOj>Ê•S]–óùdºZ-=l÷ùÝ|eïÏðóß–7«Ç|u嚯×òsÍÌÁ_Þ(ØR))6>LúK¤ÊrrYŠÚŽÛ­)mOm°¶ç×|뙯¾ä×Z&<ÅïÏó¹fþŒžƒBºËG;)õˆß߯ïK>Â,«ú09uZFls¹¾óƒ�óã±5_“ÿúx=ÿ#CKþö±|Éàå¡Ü$Ye}˜8rü¸ÛXÉQޝé™m¬fGš]ÏX™ªŸëûp�™`G$edx)m Å ºJFÊ?Тp)ÉbœRñcæãLü|ÀωŸ´Þã+ŠO¯´ä“e>‹sÛÅ÷Ãîg'—Vþ=&µmÝ‚›FÇ”ÜV}_÷“ËÆ{Í=¾ÿøYñŸ}³ÈŽÂpvYekMw+#5 ‘¤AMf¸K¼^%x”ðIRÕ5 rpçÏR‘þVù½ª7;�ý8íÌ&xuš'�MÑÔçŽ-ŠèÍx×ZIÇIŒvJË^X·¤1�:2Ë$x$¡hZšŸ'çöOrú·æû“>¿?ÅÉRÿ9E²Ô?YèO´l!í"2«çCY 1±yZ9Á1Ð%+mÒáMÇ1LËRÑXqd`(;1¸&PÑJËJÖ«Uk¿HwX‘Š�¥¬W_#ªNÚ•{ýv󜿠ѹ’?Ÿ|ZÃ6í »Y³ºJ“uH0±ˆ–vM4IVõœln®ªzå¡�CNʬî;+qͰ„+ˆôº‡ÅÐ"8çd.ø „XÈÃü|ù% …9'þb.È•ðýdÛùsÜ(kJÀÄ’~èNê®;Õ-IÛ7]�ÊÒ¥ ŒÆ°Ùó_&8‘_†ùÝXjDÖûÁ¬‚1&Æ¡×M¡�Qµ <ƒ�vwÂBÉ9gÃ'A°ÛყÊhKväMéy>c�H¥­Š¬ÂLMÖÄÈnÓ|™B¹RXQ…ZOcà`'ž DÀÞLPæWA¤áOµÚÂþCŽÿêëë—¯Þ¼æÛ�žs&Ž?‰Âtnü7a»LgVÎB* ìÕ⸸ M€Eñø¬Éa©dJ%X“`þ—N  ™ÒŒ*ó?öAתnÌ.�¿üd‡ÙÝ'7{»œô®‰}{«øŽãn±Oß?ž>=ýøödzM×!¶�•lÓ�ƒçº¼Ô:Ê\L—~Oɸ®!ça¾Ì�¼Á ù‡ë°hcÛ£x[$v*dTšA T¥tlÅnV²3åì2ä àÅÞõ�?¸Ú…"v†e\ƒ€ÀÚ59¸¬º-úD0‘ E©,lPa4ý|4bõžÂs°&)�°Tä<Ð÷îv?Y7¯¸D–6�ávïöW�@uL€’:‚�î “ç;9%Nž³aÎæ0H‹Lö(žœsQ'çà·9Ý�œïœûË}ª[ÆÙ¼'<þº««Þ· ôý÷[…T'rÛý]v�ºîŽmrã7mûdíÒùsgÊ/~õÔaÎåÛƒò¿¸úoMG„a, g¨–ð.�'TõamÒ8�\,‡ŽÂÿ øýÄq­wÐæÜm.�aèø¼À±ËS�‚ùg¡„x2ê&¦…Éhëq\”t?bw½nÅìÆ•6ÛiWéɱ;oŠÆ‡<Öcwìòfr;vïÚ½{g.݇ˆ!êýÀ’ çD‘�I@¢ías¸³õŒ ¾2íô&u»¾Y’»Pöui¦oóÆV½�Q3,¡øŠÃêÖ#»²^L£�Û3Î0�Z",Q¯ðH¬ 7…U{|õÒ¹óçË—~»¶çSç·' xŒE¹qÇ:•⋟“…G�ò®V{ËÀ'ª|q1•šØq356'ðͱTý0Çå—†b±¡ ïaNà:ŸqûÜœ÷žgþ{x—šþoñ}8çbbù4ÙWŸ*g]<;.ººE5‚!xWC«´áE€îb­„‹Ÿ(ÖíW3[Ç.‡ÒŽxO+@Ýýºi˜õYû�*ªVèPíÓ+›�VÇÐR·H6&x’ÏnOß•Éà3Ôp6{Oª®x"'%Ó˜†BÜÛ¡0ΔŠIP– ˆ9Òíuvn{ûºýÆ®œ±u<˜¡ôô£½[˦‡ýÝ}­í×›cfØî6ôÍ^ºCÝÈÝ’»'D7wª9§Óæ(0�äÈH˜pžo÷¬^¼x~êÊ¿­­]ß3Ã:˜ÈÍÿYîùðù¡_æN’Â/ŸÕŸ~ªLÆ_}äÞ;rß–¾ð—xkñÔøÈTq©Ê¸}m¬€Ž¼“aPÒC œcoŽç¨ZQ… Mh¶/ÇÊiÝѧ°rŠ4êmÍZtŽÉë§'–«A½^æøÅùÐJÍWÖZ¬—x¾öˆôÄÿà�íÛ¶;“Þ²Sd×1i=:�½ï+�Ϩ÷õÛOjÙEo/,=¸X®ôôÓçºà\`„úà2˜’l‰JÊK£Ø»;“Íà“gO6›¹SíöÂÍoc’KÆÂ8� Ghô$™ÒÔ{×wÉõúõ�lÛaôÐ�O}ŠŠ-Ã(µd"�ŠùûÖw×õ ›ÉÁÄè±wÐݚ܉ö9Û¢¶›]´ì‰%"…ÉÁ„ÌIçâ¥üû^[ÛS#tñ�”qŒaûå„‚)E¯ ô‰³W|ñ3jòEÚ8�tŠ!Ęí•fÛ¬fëߎ˼õî'¤øÖgÄÅ’‰W?ÃX„|øÈ “³ï»S–‹Gè„‰è¡ÆÇ{™"ûÞÌÝöDù¤¥ÏJv6¹?ó]î×mdqï­{ÿ ùpï-Ÿ-¼õðÞ_—Þù¸d½÷ð©…N[<ÏôÝI‚;¾ðηS.;ñò' �Å›ÕâJM(,×JîËÈ-gŠ+ÕI¸#~ XO:ÝAÚ» KÈzCœ~ƒäì´ êˆ…Úï—Í™nŸ97ÐÓ¹¹a„ýz Ÿ.tÅ»\¦{Á ®Ô.w·ö øÃ?j*H¿!¢IÄŒRS,�´âlH)Ô%¢fwÝ2T³»oÑáw€‰¢(v´ý!ç[!5•M§ÓYâµhlEh0jÒwfH� íå×Ò:&æ@x zÏP_pCþ~ý�¡Á�?ž�180Ñ5·À“ÙëÿºzíêÕKS¥‹«½JxŽã)&ï?1EŠ/�ús±ŒµñIŠ ˆ8TÎíË�%äýǧÞÏ=7Ã’jÇs�pHW‡ÌDÂÔC´iõˆ)ÅÁDKÙã„3Èá�PÈ/fp„‘”ª@ª¤f¶ÝÓó¨,k&¢cm‹c`0–ʤ2F ‚z06¤Í�ò°¡àD  éFGqÐØŸPˆžì"È&b˜¨ôUe]s œÕþÍÚê•K—.•ØÒùÕë3`‚u0yrг^úºðôq"°Å?{¤þK|Òq09Ã�ž(›o í,dyÐp’ìõ©Kˆõ †ÀtøüÙe‹ãH‘jŒCz|x†´0™ƒ^&o8˜4]«Y!¶ÍZ¬1ΤSΛs�ଛf ô Ì”¦k-•E`â|Òa_ót^Gv© OàÆ—æ æB0C�›Õ�½Z™]®à7ý�â˜ötÚCW\w&»Á£‡[ …�¹ÍKI9¸dÌb™q_ÈƆ;QªÓEf(¢Gí°8}$Š€ƒ‰Ýˤ·íVƒÁèm[Ó™d�úˆ¶¼†0! IÃ8Çd…b" ªˆvÐùÇ Ž@p4•5ƒ®Cã!‘–1ï!HDú4@í)ÓŽA}»!X$ûÊ$‚RP¿–#'®¯^½tñâ9Ž9¿öÇÚ˜|ôè&’ú«â«OM²±~ïÉ’…%ìG&ã€ÃzwÏO¬—¿�Dá0µŒòÎD�� FÇÄuŠ�ñï�LXKùئæ–G@‘1Ž’qàÝ„ )ÄZ“H¤°L1™¶çË…¿À8d’®Axô1+“¥‰)ü%ø˜ŸZÇ,ðK犣ÓH#à€ì·¡8C;O,Õ˜f��¤ŠM³>mqì—¾kYÓ“Ü&œƒ ýß„³hÄÂ~à GLÍKTS �šJ 5MÛ8ॅÑÖVÖ3…¢¥0ýŸg6•ÊîR£·Ð2¢q•Òv¼¤øîlZ ë¿É¦Q•mL4´Óh‡%G"–œÁ°i„œÏ(ñˆ…c£àQ¶í8ä0ÅÒd3–Eug2ŽÇî#»ô°'>xg6&¬åþzí 0¹HÊÿÍeûã1³” ¯<ó±sd1÷ûæ÷¾WŸLíÍ'¯| Óg­?ÏÍÓϼoÿÚÈ}<~Q�üó_3/æê¿>Ö~ ŽòoϯìÝSfÈû˜”�L Xrpd_µ0Z&œ…•eþ/k3BóYQ¬–öÓ¹e˜à¯OY,b©ŒšU‹–¨ùì1‚…K(6]`™?f1…ÑC„ÅbEÖÍŠkåh)�Ó ¥Yíø ,t‡XA [L(ÉZiÁ”—±"ã—ý"]ø¤#«é� �±ëíú�I²C¡13¸˜J‰¨h&˜f$1�¦àrÊ4²d÷%¨6&iÙn�eÀÇŽ $“Û#ÃG¥”ì´)¡g IS!9ab­²!$Ld&®KvH»É¬ˆ¦M€F1�gļ3“Hnhì¶´'x�§¿ê�oÖ®]ºtñüo¯WH믡µ‘üÊXý¢Ú0ÈÖ‰ù^,'gmSW¬Œ;2ùì ±ÌdµÄX�d�Y¨0¸ýÓ©J‰ìK¤Ÿ«0“K©t}š°˜l\kO?ìî/�ÏÞC“V—8[*ú$ñ¦àw“öY�ä}Y¬x»Ò3ÍjÉê–f;`´ºEiÖUôƒ�®YX‡&’G:íù~áa‹¾ {‡Õz°L¾¡V\Öäï6$o·—™”wKeš`ûcDzƶÝ~kÖh#l ù†p/+¡�ª ´¨,‰ƒŠâ iJ0 *¾0¢ç E5xGDyCZZS©”hZqb,�“±tz,•Ct%E–T꣘wnMk’yÇÖ42‰ª©QŠIT¥¦DBR•ÿ*Ù0äÿÚ à€‰F1QLºH[~³{C»’ºIfRÕìÑu˜@Âìsß~óõ×ßþzÎÍÚBˆ…¢×ƒÃ)Z&vÒ6ã’60ŽÑqÞ(à­�§¦Í!¦ØP:Ýf}h«5vqùLë…�5Ûýí‚¡½œ0Û4¡âØÑŽQ&ÑÂ8n*“Ôæ¶Ùq^¬ƒWxþÀˆð¾H¸#·²‰²¡Ù0¢PÔ�Ï7 ©aÿ€ôËj•Áˆ“ÏÀ^-9˜hP,­8’"fÚ–Y2|0ÓÔ5Ù9£ÖÂDƒÔnü )7. Sv®4õfÉ E�‰LM’ù¢ÉfRÑèð*&ž¡bÛ”˜êà˜–Xã”8­Ž©ÕÞ:£hYn.n.!Ëã&ë�7½È�‘û@H‹qH£ÂX7¿§7Ù§ÁÃjoƒÛ~k7¿{gÈVçV3^ 9ƒ8ÿ(µî€õÊ&ýßÙ7ìÈm ˆÞÂ9ÝA�H `f¸÷¿�«P¯÷a ʦӋ®!èø÷-¨”ÂWñðdÆÿ/lÂ¥U)Äi§Í;RŒcã±§g»\ìùÑ«ÒÎøôrKñéá)Àƒø˜iÁ!)ƒ6äÌ&¬zúü1Uû‹Þ‰ÈhÙpiÕWTö¶kôþ›û¼(a:™7|šñ¿þ‘~¬[ØBôÓÀ‚KòÕ�5Áž\cÎ<úˆsA@S"„�ι쨉i(â•3½Xø˜°—¯÷ýõ Â' ´Xi¹õ ŒÇö½$ôA0hœ²°ÒëûnQÏ h·ëóƒëQ†·.Ü0s1%!Ï{x)¨’�'yü¯óïFL|e¾¦¼ö�ÿ5²H�C>ìÊǺí¯�þÿ—Ñ"‹K·ªeñÚ¯!çq8Œ/ iˆvš¸ß"ò¨‘ñæc²v—ƒ]OËBÊèÓœ­u�ª‚×kïµÖ^[o­×®¥6¨ÃíÖRr·¨äe ‹EûVg¶Ì ®¬×¡ŒRŽü:óÑ.þ…s„þÀo¿ s‚_�:óUÍÖvÏoƒ/´êºòÝX*ÚõèCÉ:úœCú¬&K¬ré1AwÁ€b9nÏõüŒuÜÃQL—gZ XšÀ¤ ½ŸwDjŒKÔ”Yä[-+ÿ@Aa5ÁQíÑìU*œuÀ—#£õeò½ð qŠÿü¸9M>6²¼ÜÕŽfštÌ:¶„À|¶*©ä¢•ÊK6“RÌtU«ÕZ5³—«n„árC—›\L§Oc”Rì㦵6ª³jpi,vHÄQÎN‘įƒ?F{W5IsT‹uýsE*Ó<©u‹�,œ™-| SxáËýȯÇ|uø$ð›ó‡Ä§w¾-|«¯”f^9©‘¯ ¶ÎG9lÖ�aƒ2LVjWí£´X†Å¢r�ã1ÁV‡‹ ‰yÓíÓ=6PD¿¬Q;HÃëÂÐêó@ÅŸóåSί3¿�ªª¦œŸg>ü•ogùóåür†o3ŸFüüß²ó‡u~�ùL,|+Q5ÊË �IâÏV­5½A·Þ­>ò"Q»Áë°†=ƒÈ4Hl€�E1sÆqŒs(=õ«ÞL­Ý8˜emæk¸Áv^6øDô‹Õ•Ï:y0ðW>lüŽÏ‘ÎogøÕ:<ð‘BË9~Ó çוß>IÌßñ›ó›ø¦sA¨ñ»ø<¨{~?àf«^|–Î|Zyh¿ø÷M Úœ¤ù]åâ�YõS""¡/êÕWR~v²6K�ìI~:à§|eÔæ5òò_âãòú;>ŒøŸ+‹zÀW䘟VþšÀ’Å_ññ?ñ›ù.}A|{ùL¯‹ûúò;{óm1ÂTµ¸µœý�ý§¹Üªse½ŠÌŸžÖú þ/MWýÿÇ·û?ýƒx 3-Àm7ÓÜ3é p?ͤà1Ì´Ïa&äÈGšIà(3-Àì�ª–ªí¶¬';gÕÜ8Ò…a§æê«ïºÃÌÌÌÌ¢…£a’/ƒB¦e3�5 Î0Ó¿X'¿cOÛ È¹W­žN½§O¸Ÿpl…£ºª¼U…ñ{�çæ•·O‹/”:pF ÉFžØŸ#Ç”aåݬ[»¾OTMS åÍÑFEו�ª¯é % œhÂ?QlÜüÅ>%6B€@¾¤�^))ëÂVþ†úV6¬_¿±PÞ@axÝzB•n S �õùPê€&ª¦iÊæC¨åS«¦®JUuU­ª«lë–4%šK ¯ë U«­®¨­ÕU­ïþ¾Ÿö÷ýû¶F‹ÇŠy|¯(Ž*cª–˜½öå›|ˆåwJ®‰®ëêæ‡ ÉÑ©S¿`XÅåÇà&~ŸSHùDèêà ä,]Ãì#“'O½§PM/B#¡$B·l(Ù¨Z4c0ËîGM§¨†qgSJuìê¥ÍÿCÿÓtÃP᳉<·\l?Bœ¬K¼ôuý}$Š}¶ãÄqNRÝð£ÓPJMx©×ü3uÓt#bAiÓÖ¯®É7÷Ñ «#D4# ´Mtc 4‘PŸ‚„®[‘Ð<º·ÈÒK×�§%¡ïðS�4fÖOˆŸ,öcÐÝMb ‰nøF8ü¬åT8“K8ç •=ñܱ룔†·Þ410Áú¦Cü“„ýÅ�u)ÔtÉú9‰Vw¤Æs¹Þ(›Ùú4ÖrÕÊíÜšÁŰÝ]ŸMŒ¢Ñž¤ãb§.n}Ú´"ÕÀ›tÚŽp‘•ÄÑ‚ƒõöÅ5Á„4iùlStÈq¼7jœ=svZh:–,$±ùtA“G¨·Ôòœ“5˜�Í=Ý4ñ�¢¡Ä×BÂÏ@Å %½fUÒÉÌwMLJLÞhB(¥\“æË•Äþ5KÊâ´,Hy ]ÎõMªz¥§éÓLýsOZF­á”ŒnE0é> ˜AóB�|CyÓšPo—RòÁÅ»¼OÌ5ùt3±ÓBÃñ~‚³xÜÑÚ’cýÄBZt1×/žÍàªÝG& ’û ®Y¬IÅžtïxk8-ÇAÿ¬ÜN9.evžL'�ͺ´ã2.–Z0x(¬^ Œ�&¶Ť[QëYúúDJrÎY[æÏ¾×žöÒÝ hrÓÚ³o<ÎñTïÆ“•”ù {~ê#€&P"„ú_JøIó©­‘\âV=±¬­Ðl†ææ&/dëi Èû¬M@¬b?9{°_ߨ5ëQ¬�3gŸÀïÜ,ÖgØœ}"r2¹TŸ!wV?‹ÉÙŇÊŽ[ÎüÐÊ=?ö•o„¡€&þá?õFÃ�bW-zt¶û‡×tíVj˜Ì è×.Ä:„äÉbÖ­ í“ùýÂ;§,H’dHö¢„.ÿÒO$õù¼�²"¢ùoaüDè³'±a¯Q6cn}Ž®l/4n•íóÃÙðVʽ À«ùŸ_å\Ût|Ö¼•‡'NºçVÓÚð‘IcÇݹ¸‰t¥šöY3fž²Úí3vzY3‹`ö‘9³? CYVS<¥‘ݳƌ¹ëV±Š£sOZ»ÿeï.݈a gW ÃI&9ð!z§�ði!EŠ’2D&lCÏ<’¨¤¸©L“M�³L$/¼êlh²ã… Ç™ˆ7¨§ßMDE2ë8ëØ·Èİ!&‡ïí¤•ãJ¢‘AmZ&"‘D ýð?ý;‰Jf³Ìò˜˜Ô¬û“0NVzþCGlˆ?ˆ?Öa¸ãËê÷Ãý„™?‹ßîW~ºÍ÷_WÿÙ;‹4Ù­Œ†W�kfh,f3¯!<Ìì1“›™Gaf¦�„iùeç–ÝÕy (û£ìF}Ç’G¥;®.¯Ü€³¼²Š‰/ôã4&ž¦Ò�R¦(\Œ‘Ö˜“î{¶wçMw\[ ®ÃjŠ—ë°:¿~w¯Û!SBUê‰Ñ•ŒÀ ÈWf¦§&¦I“`þœ`qmKZ¨'¤¹‘µrRÄ C y*'�drÂ�<ªI�5ŽjÒnG–T¡/ÃD!Ýàÿ#òù|Ž€#�MÇwüMpº¸”-ð_'5éw¸%$I1,½H\ú™Å ˆ@ŽLNàÕĵ½MW×763ÅÆÚÂâÿiBµ’УÅ—¦§¡Hèˆï»®c¹IM‚ù…õí�»»í,Ñìô6æ‚X“^§ZI¨?ó' ™Ë“`ÀÏuÇ6œ„&ÁB°uosƵÍ,a9Sµ�íµÅ Ö$,&Õ ,áýiË>-X#<Ïu]8b[–kKVwº“º¦È²4DF�Œ)Hø÷EÕÝÆÎúb�Ô¤^«”ÉÞŸ�‡5åÀ ÚG8À&I C·“Õd§e©²È2„@›()zåÞµ… Ö¤Q§–K¦¦àH”9Çu2ƒbÃ0LS³bM¶:†rD\¸$$ãtI"ˆ"v‚¬Uû‰j‚á‹•È’IHâ3gÙ©VÐÆ1Sª1ÔdamÇ“…Ñ<~rð#ûàÖ+Ãøì£ßaŸK¤™z«Y²p*½ÍÅà�&…\h‰•^ÂȦ E€¦iŠ9Ôdq»ž¬%‚€�>0év쥫ì2£ªr‰�yö&â­—éÒ8[¢5ú˜TÖëN‘'³Þt0 —zN~vzŠ,!G(k@O?‡þI�PUUŽ5Yø¢�È!m—š `";ûÏ7$ B€KãŒXë51Ò®Õî9LÍ.Þb#MZ¤I173=é{—„§-ÕŒþ‹PD’i‚ì¬wõ¤%îñ'žùýj¬ ”¸ôù37�@5ùä¡§¶°ÿ‘±süÀ„q-&~¯cxƒš\î×D”“Ææ¨&TLBKÌ,(ÔC(PȲ"j\“¥�¦$0ºÍÁæñg¿Nh"°žÝýüMhrìÖúÍÏþxöÙ?{ÿÙ%ÜSJÝNUöT“1u&¥­¡&�:^Mfg&©åX�„‰²¦� }òDåPbÃ%ºÅãqXŽ"’œÐd³.,måü+¿Æš\b^û‰Ñ» Ý:�Ã;/_½ðêŸcÜx*½öÝ%¦÷0—Õ€ì³ÛK‡5™F1á–ü'‡È€ˆŒJL¢â„Bä˜q~K¤¯¸1%IHT“Fòö_vγ+Š´éãîñ#<çêAL›ÌYɰIØusNÆ@ÌÀ Às$öÀ„îž‚9+`$ŠD_ð-ÈüÏ¿úšfX¹£÷2%�ª«{æLÿ¬ª«»ªEEûÞ¯h,„ 9p.ŽRðQvæ«o±h¦ž³Ä1':¼‰Ø<Õ›lBÌ1� (aHø×eIŸ}œ8 –ØVnuÚð#be›×†ŸsÙ¦-xÂÊ“zv•oóвml¡b³á�E,µRX-�+B¢RݺüÑé˜`ÖUy#·§˜”ßj:V¥ ¹‰ˆ³r“4NM8�]ɾDR¢¶ÄÞY%ã±ð«�X�—µd ›°ŽYbîzÄv‘uëÚk% ˆ¿þÝ$¢òösQšô&¹UtÊo¿¬RPHÁ¯Ô͉ ÀQ¢d¤#–$ÕèË›Äq»ÆŒ9ð%@„}¯h¥œºïµq~VºS þ�…§¿ã²ø„ghq\|¢GÞ�Tcó‡ŠáÏRl‘"Š)¡5¬‹ÿ›ÄD¯ÛvÍÕ{´ûgÊégLš²9…u‹?LPWÅ­¬ÝÐ"Ÿ(ÉÏõA÷Mćõ“÷M“ ëáL�™0%16ˆ(¿‘Õ'“'ºÒ&*?T>¨i ýW)¡1¹R¶=>V,LDÅê÷D$‹†‰H]…µ£ìIFÍúÏ{ÊR�¢¥®ŠÁj[ÆùUIº(I¿àoÎp#§E%wa…’X«»¦{“e¸oÀœà’�ß@j=§œ¥n`ðE~vÒ„‰‰j³a{ŽÅ¡>$È o“Ò{·P¢�~n‡ãÄ’I¡NßÅžF‰Žg:ŠXŸì�LÇä½pL®¶ŠÄ‡JLèRí¤7QLLp¦:æZñ„Æ‚˜ô”ß„­-ÞR¿ *%¸‹Å†?~Ê '6…ÿw9Ô{¯ª¢á ±ª`¾¶Þ¯ÍÄäƒ)˜ /Cd¹½߯§�“`c&¥†@^7Ä䣫Y=ØE˜ø“·Ç²öŸÛÒ%„Ì õ¨#ø§0)CsÓêgL˜�˜p¼nÏØ3�u‰ âO•êˆ"L ç’7.WÄ<“ص‰u~Iɬ˜<¢N9йOú1Áâ6}wqç„åMNdb¡D&zà\r¶šù$[ã“ëj¸¸~ &Û­ñò&%yÇÍHe7²ÞŒ‰C™Ngâ¹Ä„G†ÙýB‰*L¸²>P;¿$à×dZ2;&ŠC-¤a§¢|ÐHÙ³aRhïEVÐ�Ý#R„#š0‘¤óJ˜‘›(k$úê+ÊùœúÏò=F`À,„0yÁA§™²2 ìÔ]Â;`WÙÄ6ц‰gÞ6ýÍŽ 8©lݵg÷yoEг<ÍeinD—Tw¬xà«6gî>¿¢yW_yZ¯(… ÏEQÐY�Ù11o (SÓÖJp]�ñ[³yƒÉ&ŠÊ ð¡ÚÁ“œ±„V1WXx[Á„™-Ê0Y�Ù0óS0™™�yfÇDú^*r’:–Y(Â>¶ž}¸ƒLæ0$Ú{VSÊJÌÖÏŠ O,3‘Yú ¼�áÙôÓLjxß&sVü.]*IPU%fÉšÙ0Áxf«f"±ÞïàI°|°…ßù0€Ýo ¤¹ ³Ò¡`KU°µ-†R£°•²€ÉÜÅ„ëÓ–(fŸè’ص³`¢òM�ÅU*h¹ý’'‡*u¦\ª>tV,ï¡J?QBOEia�¯¢¼¸€^÷˜œT^…‰¥íN¡ÌeL0‰Yò*³cÂD‹ª±äÛj<)øW~óä¹;ÚhÄŠ;ª-ŠA+®Ñ¥4¶`Î>Ë7k0*Ñ Þmi*n u®c–Åáï¯ä¯oÃÉÕ)úÈÃ$v馸„„ï+³bÂDœ¸rÄ0qéáÉĤWRr;÷¨X§ ±tÕr¡Š Ìe±Ác.m+¿žýì, U ̵˜ØØ„ÔL,æ—^¡Ìõ²$¯!Å«é^Ï4a4¯6E4gzô°]nÞ°ŠL6$â•�ñq+m³aâàb‚û¸–6Q”mðdbòÀ@mÊÖEù;g,°ç>ƒ;è±¢ˆô‡¬ª¼–ëT[ÏfbòÀÔÜ;òL”æ?êœÆÄ¥Õ$â Su<õn«ï�þ¤Ã§i5u�0­¶.Ñ4®u.mK]ï$%ÚVëhÝg¸"“Ø@’°v6Llð/ÅnUª¸v¬ªòÚ1Y$|Ø8EÉ~¦Þ£úågoæV³‡asEE í«*d¾Ëž-qe?ƒqQV¿€wÉ!ðDqRÃgsß²¤»˜z4W(�’-éç|ôÔË›Apšó¥õ©.Í[LÝÇ*ž¼gxƒÚœÞm`²<ö½‰ÉÆÙ0q¨A>ñ+»ýB”bRñÏt&G«+ÎÔ QqýxUÙmT#5Ùû¹ï0(fTºBcê½\'»@#ʰGTJÍتÌ�2§1Ñ·žÿ(µ‘†S?>ß[lïñzeà1¼^Ãã÷µÑhuuiè5iß’7XŸV_¿‹Žöy.öi.·SX¬ü¾VñE&6²(9©˜†eýOŠP€Ì«*5ø„˜K×vÿI#@åXÕY22%¼°‰²b¢úªÊ&¶0L &<›Û˜p\1œè$wŒâ¬¾¸�ëz5—®íH«¯Õ5 ÷ïúäóu½ºËÄdb¶¾�«ÔeøP l¯¯õÀ¤g‡yt; Üу 2PúƒÌªEN5ÌI1ñ1ïÍ™µ%tùb¡Y=�ë¼wÄ)k¨Ç€DK> ëÁ£`natÐæ:&2Ð]>àwy‹í{ø×èÓ×™ Ù�ÑAûéåêÙz›'S$&œzx›¨Ë2tö½Îk»±¶¨·�Ыþ¨ÁÄ.ž.Y[zã¨SmBœib ¸T@šéUUéíãN¾Ø½p ÙŸ½M 7å—ÞÊ NX1ôE¢˜˜Ø é†O¹~´Zˆ9tXÀ§¼È©ßÞH�¸âC=XéZWL—z6]ì½g¯ |†k/ƒÎ�Çï÷wä�ìã8TÏ}\@ŒIÎø¶whÌ_L‹k£Æ›Ø¨$²ŸU"+­¸Î±ÞU�ËÞ]õ„ru8–1¡¶æ�¬V-â —Ñ/°PƒGïÂäeµúv ‡+9 ä7„Œ Gå=°âˆ Lžú8ñ¥\ê÷ùž€—V󹼫oäv{�)ãn3…- )]Ç™Õ7sû¼Îv“Nç%ÎflDMn‚k?`ã<–úJ‘†”`R„ È”A] \–vߥ Nr› ¡â€Üjõž4Bd)¢S{è¤ÓÄ„†8 ¾O§÷ÐQ§@[öKlG&=šÞLÃÆ@\zæwD�ÌŒ—ƒ‡ÞZŸæ6G:'.\¼˜ñ5 »“ ùCº‘h˜tkìkž#j0åíçØ™8DËG>.Lãâ5Ƥ¢-™% `Kp嚯yW·à„Ö¬ZâÛpÍ©l”’ì•m™{Îûä¡í=BUM͘âv[ab—˜ð ùÄ¥]ð&Ý›”ù;Ñ�;,…Ý|çHç&-yÃ30ÁAQƒ‰U¬fÞ¶t–&LpÅ'5 áÆK1ÅÊ2VñgiÔ{ÈX‡Éˆv3·Çƒ@˜ŒáНý´Ûë�kÈêÑ€ŒÉ…Ë­5HLÖ ea¯­˜LÖ )aÅk,6–)•k¢üLcÈ1(Ü"*p Žc›ðz7©a³nA˜d1&#þ[Çz½[è){Ã¥oÈÃö@#öºML8¤hWsLL>¼JOõ�WLLz€I~Ä�ÿ¸z IÇÍœ:ËÏ`©žéä­ÙÅ!Ž"LE&EÔ L°`Lè…¯�Ó­}Ä。¡~ÎMN}ñ é°5šiHbgSLÝÞ¸ú™lzù¬9�÷Ï?L JÌ4¯M­æn-þâ /z5}Cz�±.}Ïëñ@ú¥ž�´]�xÆçÿdÏ·—Ç{5$'ú†�u:c’x±Îw¡ÏcÔìüb<1oÄ¡OÓ×c¯–ºkÜ=?0™¹Où×!�Ý—¢üO0'1r!ÜiþêÜòÄ�‚!^ž`Âý¼0°ä /õWWcðlèØ�{ù èÁä¿úËÿk™ªM™SeI.—[.äœÿ0ɹÔ§�ïáã ið|ðhRo=˜ð«/Yx©3 ŠŠ·­)b¦¨8`¶ Ìç˜m·ù�˜ýSU²ø¶9_½æÒ×f vëÓÎ%˜àqîÕï¾úúÈ×_õkWEãÞËîÉï;ûöͨc…¾¼ñ»Ÿ» Ÿ Îɇí½üÆ:$èÛû ɬ¯ž�~N]”sŸ5Ç1'xè×j¢“[’§å·-劓kDÝV¬>à!꜡‡âÁá}£•D="´GU¦YѤ,'Ó xmÍeA.ª£æ:&ˆ0š¦!"E-& §ùe?>üë¯?SnÑg÷ …ÝÂo¿õ`E™Ò‡¡€;c¢LÕ›Um4Â5�”Õ3½‰Æ!Löüù§Ÿ"úæê4UžÓ!máMNÿÑ%w,”Lÿ�Oˆ—¯\¹äÑIcéÊ• E–[¬Ý4À÷Ôe+WÆ`)Ê6oݰB`-›+7oÝÈú˜ØûÄšM ŸÙź-ë—‡Y=àš¤(gš8ÉÏ+-•›9ÔUëqN±b½<ß*F]Á©T¼Û¶€Éß6ÒyHt¼šW€Iª¸p!½ÂQÑôË/p •þ€â�K>¡„aý“ß¡ÿ“õ25þJtê뮊”�Æ¥¯uÞÓÜ€Õß. ¼„0Yì�…&Ž> 3�¿�HÀ§ÛÇ—ï;loò[Ê�¾9Ý-* Oâ™P0ù[nÖÛ{\G…19@�CÀFæ&pû$G&j˜^au)³�UÞ°Î�s‚@)‹«„#„‰0á„7qZð0¨�#œä[ë;Èܤô>¦ê1™Áîïð& ˜@‚˜8LL&èRÂUÚG=¢â*0á*‚Óu«Ÿpi…PÂ0‘úK¯Šò¶F\ìd7¼É!œ£‘þä£ó³h0±ç{ + “EþuëַݵÓ0 ìô:±�¢üåe],㤩ò;HLD36Î7‚/EuÌL0Á¥SP”fÇ%.gL¸Â$·Oˆ¶ÏwuOÁ„õ=azUðiFÍÜ„[tøT]2r¡Z˜@Æ|h‚ 3�É"iÀ%QÄ}?÷)/·ßŸn�tàºöMäp±äÀds0Ë~ÄÂä,˜ S“41%7�>ËÔ{ šžÂâ°Ô;“&°��’XlÆÇ$&,öý4.Ô ÁÄÄ©gŒ È{$#е0Lø‹:d®½-Lþó–=‹{ž`’Õ+á˜T4‘”ñª)¹IE!I…~ú€8 ” ÆD½/ %ɧtN¤¥¥~Ö@©;Ì ÛĤ[b¢LÁD±A¹Ÿ¸üòmb¢yµÿ„Ý'4˜—y‡ ƒwþ$²s�cxТå�? ÏãØébnø bB¯3L¹€˜’– ²�©M“«ßˆ‰ £Ú?‘Ý÷V½‰¶!¹çßïÀr[>K¿P0\²áoža²>~›¿bë™»vÎ.Â0Y}l‹Ô‹7a" ÍlC¨h{¿o¯}gƒ¢î(h2Þ€I tÈ.[o —ÑF#†?ì!ŸõØ/´a™òF¸–�îÈ#È駆&þ,#ÓFšC¢“"óžºéÂ1 Ó3>&/S1yHsú ìLæ™U0ç럃AU‘½`QÕ½‰9Ú]p˜×[ÆÄc𺡹uMð ^¯ŽFs�7ÂJL¡± * dß`~N} &y½løã]†´ÆRÓØ†ÏÁ˜<¤¼E“öl;g%÷xþ˜þœ8‘¾ë÷}Ák¤€ƒ,s¤³ÏÔï§ÑÐP÷Ïß¿íª¸nçÜ„/ps—gßý-Mp†1;½slð5 :A†ÝÂ&˜ä:‹è·,„�·Š‰·¦ m@«©õÄÕ×k“ê»u-ð$||N7‰qçÏw�@­g{:üXéã¢Y€ÐDO5t <Úv³eÖÛÌ~@°W“ZߣkíMŽJLnõ“|‰ËÍyå}’2X-1a# £†ë­âXÈXÅ-"x¸-Î6`‡ MÇUuð çˆO” FAÆMË›œÄHço°OêÄ!€.…ˆ;Nß&&¾&ÔºbeÌYœÅí{—øÛuz sö`9" þÏ 2‚Î ;›,êÓ$&ÃnÃðn» þü…YŒ#Ì~À‚QCã¨£ÈŤ$%…Û0¸í‚›)DekJŠaνÐ6gì޻狺X¾@Ò(9¥+-Sô,-;ÓÓûÔÖ”dš¸šSRtÁ™_î¹XcÕî+bCjJ­ƒWð:¸TCàtAëñmj•àwPq�Šf�Ä*œžøß`2êäæ¿¤;t².-ï˜e±u;¹rÚÃ/XŒn@�t†²Æ¡óB«o˧á-œZ€ :0¡ûï©ÙøQú»Úp®xX®ÈÄdúêÅ€˜NÀÆE°SÍÔ¿Ð;fžƒwªl¥Î0Rä|º�C}CM¥ÅÙÛê!žîMD¼Mö.´“é-âNÀ�·�súZîðóµä7¬?¾ðn-q÷�¨÷ø¸á/éR¯�ч GÌ~ÀïÕì§sítjD&&òÕžá•g¼P¬¹0g*ô–„ëE˜^(,ÁÝÖB5I²…Ao­`-Ü€R¾�3B¬ÞÚ f`Ò­ bËuõˆ«0å‹Úµ\Ƥ…;üÜž†Üþ`OÎ Ó?N­&yçP­p;ÆŽôÌo‰:×å¿ì÷ÃhdÕÝìK»v}‘—Û§¹#“…׃’íéÝZ“vÆÄÞcb¢kŒÉÔc¥O³Ztü ¹n³'ÇêØIïÅHF;CÃæHçI°e�]º‰Éê»Y—÷9Ü«E¨7YÀWuÌËt˜˜`+„‰Æ˜`9 ¯¹yLz“Wýhîºs̘‚É5êöºü8fÃßÀ�#ݤ#�kîG? 4Þ<Ú; ¤Ö»#7èüåÏ8�0�#r¯*¤Î˜Œ- 4Ž‘NÏÕ\W!�xà(Ìð² ~A¿°]bb%¶}φw�—0&7ñ¥ÍW¨ó=4|q?àˆ¯�Æt£ƒ^ê‹ÉBÐYß@ß}OxYIÑwt׺ˆ€I!è\Ïî-$:õå"QR­ù”¹¶>³ÃOöÿ¹ôu�d¿¼—ߟc áo(ƒNí¦}”Ó½õýLL67Ðë=tçˆPL–mؾ#nšìغJ™/˜0'›3ö^¾ˆK¨%íʼP»³Ë›p¡×£%]@&‘2®æ&gb·!]϶]ß\FsŸguø¹ø þÔÝß}}©Þ­¹Ñð×éßÉ-ƒ;3»}e? ¡oà�àsD$&byü†åKgÈ{q•yƒ ßHwyøñ®Û0t¯ÕËç1g^ï@á‘þ·¡m ôuco¨ÿÏTá4·ùÒX«ep p1ú;¸=Y7°çˆPL¶®ûëŸ1þ}¡ÌL¬>=¹2ù²ik6Є1oLµ•Š�zrÃ< ˆQD¯e? uHdb"bã–Xågª-¬7K¬Ù8o0™]ÜÅ‹zÿ=7àÒüéÓú#“åqÁ_­µNám[ïo]Àä?-k'V?`¤coc‰hq@(¥ˆ·-`ò_«0ò1áÞïX³kó¢�N`lñöªù�‰{>Ë¿‚É’Ø¥±±KmèÚ°cÒMÕǦjȸ:$ÃGÊÇ“hƒs¬ÛN6“$@¤¿1é£�I˶’Ñ9�˜¨¥êï˜xÄ$4G}ê„CùgäÆZarTÙˆF_0Q¥i€y·¥vLVbâÝò¸Œ •ª�^]®“Ãù1ÍoFš³®O÷~*˜ÄüσÃ�€$| „‰©ÕˆÁ™'£MDF*˜— »9-‡4…1�!+Í¥ŸJŸÒK8ø)MS¢¤9•‰Ó<•áq¦f¢�Osò ~|ÿvLÖb2†¢1x\KÁÍã* Õløpïé¢ô�Âè¾tAµ� ª¯[þ˳<åFTØ`ù´c²“ÿAaÜ”°c²ÿ4m¯ñi$Ñþ^µ¬“u˜„§�¬“•˜øñ¿Ò>ïQ‹vLVb2p=Àä“xøØú¾c²“ßì}YT×öwX¬õ=}ÓTÕ€s'0 Π÷ÞFÀÌwž§Ó 2¨¡}\KP¨nz¬îfTpDqG 0á?äñ{A¯Š¯I 1¯ßoŸ:ÝÕ‚-J{‡6µW8u†}êÞ›þÝsNUýöþý—¹#?lsÿ+§è“MÂäXÊóþ{‰1ÝÓÈH0[K�LŽÊ,æØ¦ Åk¨õg$üL]™•É-Ë 'µ+çêxˆ–OGï[ 6E1¥¢Ž>(_Ó5~˜8¹½¸²ß‹Ìs0™­AjÅÊ„�K\ 9’�^THtÚ9¢OäüÚ^XXø~p¥Ôt�rVíaÅ$†/Lœ�G‚½pŠ5Ÿ÷æyÑ=k3`ÒõëŸÿþ¯ýõÏ*n>µõȺ é~(ûEÙ¤JöáÇýŠT÷kX¿”z…=À™no> A[%ÞLŽ^Ïú¼¶Ã­AÕýB¶,»ÉëäóFÖå¶>ôÌyžÆ�Ïí4`2KSæÌU.°âAe®é`VãÜžf»Ò»q㟤`CÙ¸‘Dk9L¬\à8!@œ+Çê‘"K¤"ê -ôQôî'Ùdˆ”JrœyaÓ“™åž×íœIÙÏÉ¥)»t¾6o|Ú<ÊP¾»Å«¢Ë€Él 0�\m.…¬¤ž+é[H¿ÜŠ ×ˆ+ ÕBv¤?"ötòoRjŠ„¦ÀôäþÄú€#f@J“.¢Œ&î¥gÙΖ†Æ<ˆÉ©n®á9WÑ>]ÙÛŒ_(¸'ABó  J󸇓”ës¶)ƒ ˜È& &&ÀâÕÉWkÏ9 í¶+Û½õ 3íg;ö’t›Þ¨N9ƒ$=Ø]j*'©îm:2@Ð1s(>˜8}×!Ææóxý×Yi(£É³†kø‘yQ'Ѿˆ²ŸYÈ[Š×ļk%ƒéÂ#&dæ; ³ÜyŒÕDÖaÂn»åžm‡¸ßi¿È,P¡ÜcØÏ ¯g¾©ŸZö3Övý ³a"q8‚‰LcÕg±óÄy6ñœe}¾Î£#gY¿¦áw{�ÿÞË“—ùóUY„²—ñ;2ÁW“‘$šçÄ€ 4ü I0Q³Û‡ü~t:„²ßøb®õw�ÃÄ» R~L®Lî í¿§`ÂÌ´¯Â)3`2@Òö·ëÑó`R2$Uôóà~¬{I©Ö$Pr¥­ž«Ó]f8ˆ(&(O p‡8a²<“}¬�«nõhËD‡ó >e€Iï�[!dÙøp€`"xqí¿Ñ©0Árò¨Å=;3`RÂaRa ÒÛ�7ÜW:ìAÉ«“è;Q4TSÁŠí„r�ÉÖR{e©]’8Lø“ÎÍ”… çÏO‰&Ø<,#¨Š³I&NuŸí#U7€€`r0Yaå0ñcýtuâlÒƒ§Ã„@²»Õë3`2 £ŸÝ<9›\dš *ÝL<£AûBî^Ʊ„í,ÀòR[ñ7´°éX¢„·`œO:jP�eÁe¢t¨J‡‰r²A·ãšXM&¤õ绂aqtáóz¬%¡}ÓWJÜmŸõK6&«vЯ¯Ib_ÉÏo^œ½)ñêmï5IèÏvÐ`³yu{½ ðpƒtP(V×]m’lJï¦l²œ0ñ®ìdc Nçº3‹¶½Ðá#½³,äËì½´×øŽCëoi’oF»ƒykºøÙ–<¬w¢aÂX{�¿É7`2³i…"êa“µ?E�èÝaú×åxŸt ÙÉÌŸB•oÜí«ä§.é� ùví Vi½£~hý=:ÃÄ[Xu-Íûï⫠ ãkÍ#z ë2^¯ÅA9±á¢D$«M2ªTFaŠš€?r�µ6®:qÅ·:—º*·ð£#mý^§gþ¼y¨BådY‰öåµ×ðÞ\üì«ó?hoÞÒ‚aš×HóÚñÄ­ý'î™}ÏÅßÕ0y]ôtœ^.ßG+×ð#�sê‹öyx¯Ç¯â×÷BÍÃú<§êó„öŸ0L~Y�0‘MòKøÚf`­½*öZ4�D/D ¢}Q½Nï™a^x²“—7å%Ðd› QDòkÈ^3`’ºrµóEI�µï4Γä)3¥¦rlð"5g�½özÀÄ€ žhO³û&a²šBÿtÚê2žtsƒRu�RÐÒQ¢\=ÃþÄ_ÅÊ ˜Ü8à  Wg¯½&01`rŠ� ’‘MtéƒúSw’ýMªÞâ]P¹Äve'  )•ìö–N¸èìµ×&LÄ�Œ¿åxqæÀÞ’Ù8¯7g£ŸºÒs²�o­ Ƚ]쎿ÚjnêݴѧÁJ{9_ê�êŽ K©ólÕìRµµ\Žb¯½f01`"�áûlPªf–÷Q+””‹tý”Ýžo•§tùi˧Ô¦‡º_š#/HO“®±þKh¤(ÝæáË:{íµ‚‰ÔzKÞr†íªÇÇ=Ö–D´Öý`ïlëhξNv¤µÚŠ�½Là s…Ö$b¯IDl¼À™IÀ*Èìµ× &Lx;øµÍAÀä®T{œÝ–.mm'»-×G`2N£&6 s;·Ð)ö뺱÷˜ˆ|Å^{�`bÀÄ&ÓÏÿûO>ýcý ¾ù1T©‹@Rö&µLÄ€] ÃÁºÁhÝP*u˜èìµ×&L`“_}øÉ‘‚íÁ«y “Gv ¥m@Öù)A)•ŸBRR€l:({íÕEýÍâ§;ºb:ÆoLRL)&üüÉvéÀêÕŽÈj‚Ÿ¼˜~óØ0¹H§V”A´xæœÛQÿŠØkdÎéÑ{ب*Õ_Â13`bþEáöí…GœàÏÎÄÉu¨Æªq×’‰†´;·‹LN°ä†êNó˜TW”;¤š“;ÒÒÍj 5®u¯Š½†�/êDïµ6¨Qˋׯµš]TŽ«uGaÇõÂÑ€Iü‘ÃugùõžT�âùp.Ñž‘‰Ãš¬$}B(·Gø$ÀV�•õS Ø]ü# L}Uì5X`+#û¬O�|ëó®Êkò åͰ– ­äu²*îXí¸2¯Ÿ;¦w–†VPÝ€É,M1-;{#,Û'ÕG-ˆóg6¸kJÏæ&›¤ôfo\ÚÍF%ÐÔr[æoÜ$"Ó¥Þüíí ¨TovƒîV°ý°*½*ö§!ê/+o¢œX�ˆ@ìz?‡IgÙð^‡c%ËáXQ4 rG¯3àƒDеÞoÀ$.‹ÍQ»ôÓ©LCѺ)6Þ#‹É¢ñŠØkNõ ÛÅ£÷ªˆ´¦®ÚÔôº×ÙXÈÅaRº2£ Žk&vÉ‘H°ÂÑãäƒ&e¡kT7`2kSLܦpÔdþÑ�^¯�JÈ,!‰¾ÿá/< , X²¸�,¿2ö­7õçæä3Ï>óShçƒ!"¼îyø.û¯ûª„ãòÜ—çÆw¼ŽÁ‡ĦSþ#ögÔ ˜ü�¨±ûóö›OiSù§°×<Ç@ˆv9§êVܼþ(»¨bíXjh5i º ŽçÌÂÑÇ]-ëŽqÇä& Á:¸�%Ã13Øk±®¡/- teF¶’"ÖýF²7LÇ‹‚nDüýî¿£áøŽA‡#Ãúç‘»ýlÂënÂ9þŽÇŠà˜~úáp гI§züfœMbõ)òsY‘ ýM�%‹kÜ0ñx×çoÛf-Íì,Þ–ŸŸÏJ‡®"XÀdˆ‹ŠeÇ»Ž{J2Ï·çço› cë¸*`"ê³7ƒ½–¹Š,Óñì_U‘ŸÇЬËXåG Œ‚•�õÊòÆŒ+ޡׯœÈf¶L(hÏç3úí““÷ßÿHÁØ3`âéf}Üq¤ 0±!Ç6‚†OÀDÔã0ƒ½¦YSa"þ‚þáÔ2éÜ6Îc8¡ÐrúÈ_ÇšëN0nÉIªNªÀ³l|ì5^ñè=<Oìj(<Þ‘· GÃä Õy(z²—¯T”6pÜܪ¾R˜oaÿðË_þòçæ~É{óQô”&ÄcÓaÒÁJ†©ó’÷)Ç‹›×¬]›ä<ÉÚAd»‰¡8`BÑ{ã!§sC'ÛJBÆ$pã¸*öa‡xŽégxxàúN¶;´—Ýõª×ÙƒaᘞÆâÜtŒo:©saIuöæMMvIÒR¯-Èl\ГÓl¯]—Ó$KOĦJ¦tðØFd&ŒðUm�LNP¼9úJìx]�Û�.·Çõ‡ßÝòÑ/ÙΣE¡U�ìÑûôå ˜0ü�¸‹Äê<Ìï GKè�öh;+ úz*4ÇtkÉêÉpŒÇ .¬f—*ø–Q¯¥^+ía–�Ñn?‹bL®«¤AsÿA+^G×K6±é¼ÑñÀ†=Ç\À“’zôáb¿dÂöÔQf�7êoE^á‡�‡²î…Ô•ï}ð¨�ò–lοIƒË¶´ºÜáÃp+qìç©×Œ>éYÑPo¾–ˆ­žóØ&½ØuªÙÍKl#ü3F)†%¥['ÍÆõ碋ø£Â)Æxý%ã0c5Ù™›—·µ_ÙKŸ„¥K€`2 ñÌZ(е¢‡±&µOÃd´öÔCàh0QŽ[Úòòò¹ ÊòµUàÕJ¶×нfœM(‡V&Ϭ�ÉÖs{A&r&¤Ê"õ\™|‘‰#,õ+o/'�J Áxm`b°×d˜Ä3¬á§-~Lœ•<ÛôÕäF·VÜ•.Š#,} ÄóqQ=±Ú ˜¼60é ¨?‘ãõQÓ¾ "­MX&–Å!;`O»{�ˆ�`’Üh�¼^£w$€‡ÉñRl2‚JÝ'�Y4üÚÀÄ`¯‰x å<#+©×x‰b�ŠÐ¥H"6ðØŠ8D®5©’èl0ÒÁûøvò7»¯ ³Þ`¯m âBU¥gk~þ!¿$R¯Q)²­¡ Dl-<xlڱȵâZK7Ã¥ÅAß¾ÂímD@xÍ`bä7QžJ¢w.?ÿC²¬‡©O!+½N öš®ÝL–yŸ(Q S¦"œˆ -òFŽ2/à�“MÅ€‰‘{-K@˜0´3Y¬./7WŽ�nMѹm³€É,”þfŠœ>3`2;ñ£_0•ú¦¤[Sxe·Í6˜xT²UHB —ïÙØñú<Ó^TIP€Ì€Iê*®Ú8�hhëÖûc¥í›Þ'XjQb¡ õØ:jÁm“馫q�e:cc3¬)¤:_%�øf¬·õØ?Ofkh:N¸"`^[[ë ·çƒLtÛg-ùS®� &s ÛÒšhéSKMO·¦'`ãoìn8&\ûEÎ6YŠÎê6SœÎ5ÆmwŸ×©ËûiUQD ùy3º3¢EÝZ쟟òÖ ·ðp”"àN„€é¢·†×ŠÜµ ˜œ2ÿæg?GÎï¢�T}tç r’݃SHk6уa–ZÑ×Dºµp6™`‚ �ÃDŸ‡Š¸“<L®²äÖÍ›ßc¬OK ìC q‰€+À ]êÞÈI›ê÷ÃYA/IéÔ&~msÑ"Ý‚j 奆̭à:yôy* aŸC¾ž€ Ðý|†v×–¢~̓k×ù÷ƒ æ[ «‡F‘Ö–åälpè©êKíaD,t¨†=ä ØìŠ€‰T·Ø¿Ÿ ØÐ4O²Õ-’¬Ëâ)—®_«J3ÂdÜ¡’šÒ®~Àu‡Aɱ¡©Áínl QáΈòC8 NkjRÝ$¸®ð¡Ø?ä ÖünˆHoä�œi{•¦$j]êÌãâ�$ÈÓÔàÁ ²¸ŠàµŠQ0hÀ„D—'ˆ:2aÎ>…Àº]=B=4BZû#Z˜–”M3/i,µˆXè HÀöš¬m:¡…SͶÓÞ’öW 0?ºTw^дg€É˜7É>èãø¸˜fÆ}�£`Ò/ï(W«ÂB~œ6ýgV¨â^.ß>ðéJBÔû'ä cÛ57Ï� >,”)TÐéÍÌközø¼;!®„ BhÃqƒáÖXh®â¶å!&ç$?¿`}®¶ZšoìaGZz&þ,ÔCi�úv”3L|კK-"ªF°i0éW©è`÷Þ¼ÆJíû'x¥ JNc ªOÀWž&\§Š+ç$× ê�”sÖ|g»‰CHýÝôáÑ�&HþWkÚ¬ZÞÜ�À¬$ôòˆ@ kâLæmò{ÔМÍ:‹ØôJv01ß[“ÄÆ�¸e“±šD1Øp´à‰³”즮EZC‚¿tiÂ< Xøš‚9+’ÂéÖ¤n‹–YKÀä0Bm$\Ç5úI Eå<¾$ÒvtàGÞƒÉ vw1²OŒø{­ÝÇ‹8þ×rï Ö??,õG^¸Þ]Ä%ÿÞ±–«ûð“ó³ âýê…Û˜ïXQÐáXÖI¡Ån÷ÑA�8 /íÚôù)¤C‡ iöLŒ: êdœMÄj’¼nÃú$&ò«Õ�@%Z=TÐL”sìŸüôgOmJ:XjåõŠH·†lÑ0™À²�±ý¸U*î8PÃúPéAÄÛ¶&;¿ÏÌ0ÁÏÜ;1?W «tçÑÊÒm–`÷ŽAŸ�úÓ”ÝÀ“^A^î®GúG¸´-:B¡ëþR-"°¢„Ž)ž£E& ®ŒÎC—çØŽP•“~̱&k’_šg å,Y‡I´z¨€ V”_óôlᄯÊ‌²R¤[sJJ$›€Éî|ÐY8LR4˜ôSå�€_É ¬&Ð&©¿^Ž‚Évïøƒ«ìfǃ!Ÿ&õ'`‚Õ$£‚ª &ê3`""qèuQL¡€×xºuÔëÔaBsn ÂaÒcÀDÒ‘R¥ý§u˜Üœ¢Êa"ñ$ŽWgù1‰ï8H´&¥ðT°”n-:›dãGXl`Aºjd¶Q V7KÊ‚ hͿNjX¾]C½¼ˆÍ±–-;ó)»»lÏ'ï‚àÓ0YN’”‚@�‚Éx&žì\èrGB½€ËÍe ãJ¥.Útü×¢a‚ó¬4Î&;ó p„e}ÈKo&˜$7LQEòµÛ ”žmUÜÅ(–Z½H·¶PŽ$`Ä€[¹}Å.Üè»Ë�Êûy€Ã3ÂäNCccÂ}KIÌÏS…cžP,ýX`Š‘„`Ÿ�ú0_t ^€È˜cÊjBnÖQ¿ˆâèíZ)ÀìávÝ v®ãÞŒ£˜tbÓ™0V“§ó¯�Ùµ·°ç¢¹„zh4iÍÑÍ÷lŠ˜Y#Xjzº5-Ûƒ|5¡-i|?F !ŸA�+!·™ßÂâ—ÃÏ]Á >`åƒnô–Щ¤R¡a©?±yŒ9 ùw›býUa˜ Ü莶š ^tå-"ÐÇ֜aæŸîa»0¸ú4»M¾ÕVö)hG g´P!ÿn2`¢ç_k�Dâ5J´ö&U¤)¤µº+ïlkŠúQß,5¤[ãæ'`“éÆ69qÇœæE—ß(D6à¦õúöö †ªßûðý6¸=7†83÷Pnn.^ª¡1¿�ÖçÁΓÛêB¢¾!ˆ6ª"%Ÿš•ÿñxAâ/èq“!Þ¯5¬÷‡ú[ß§ˆ@ÃôÜBh†�®MÍÜöñ‘6Àdz~[A[Ó–ßÌq/Ç­=94`¢›þj6M=TŒË7Ñ ?Û” nº»B…0?Ë’?w¡¿çÇ{ýdBßOÅEûšë÷ÑPDÐCUº"^|D3&ôþôˆÀH¨ hŠytKÕË5½bN$`Ѐ‰I³ßDO´öiMOÏ6�¥¦§[ ظ)‚§ÍÅ}Ü‘ù d¹ÍC,Lk¸øŸÅ'j¢]úŸk §DšS=ˆbšŠ Š4Læ¦Í_«ÁdÙ޽&KÕ%“Á^›&€BÆ dÝÚ/A\�ýÚž=n›ÎI‹á÷JÍö‚÷ÿ¹3ÃĀɜwÖ­_¿æM9u¶«‰�)™ÞÿìîgßËö %h_=րɜ”Ô…‹ßš#§¼,LiNffV€ž/VgfÍ›öCË ž­sà2�“mE ~¯P‚ÖtËñŠabÀ$-U;ó½,LdzEJñà ½¥,òu±»ìg {¿¬5j¬‚“Ö/)ðT4áGoÏeÞÒ:©C>”óÖ¨vâeô^c“æMþJ4©UÌ&LRSS†YÁä´¥¢Ô/I GŒ‚MÄý,ýܯF胆¤nê%0ÉÏ� ñdk¥œËÆH0“ŧ›”öýw@ü'_Î�üw åûÉÉÉo&ê¼5ù¥,}=ùù?% Ž“¢÷@ì9ÏÞë$˜&çÀø¹ÄŠ[¯œ!rX…%T v²¥ 8-8iÉõZ6µö«ø»~Ÿâª+̃5š>è}éúöü‚Š?Ld8N‘½ŸRE¼µÞŠ?cò>-EEÉPøÓß7“_H@Ã)8›¤~?ùõðדߢósü}W¯<^ ˜üSV“ÖŽ²yçŠr8L,&“y½›[ðÖâä)Ô.í±žÖ9iôë{LW¶ª§ÜY&\ô ’•È eÿeAd¶)B>”1ÌUB…h(ç²™ª­XHºiŠ8†ø&¿”l�'ëÓ“[´¢÷&¿P°°|®<ù2^u.§^‰^ÛUw×Kç&¬é\QÖÉòL«% &”{Ä|ä^½„Õ$½Š8!Êœ¹6¬&휓¦1ƒe¦øˆ1˜˜5©6Y¦ìrH²ò,ùP}‚ËFaÉ :¢Èk´ÁÌTèIç«ÉÇß<þæûÉÏS&¿œ7ùÕ“ÿðc©±Å¯O}º"Ï ºBpàtW˜GåmÕçáƒÞL‚çÙ6v§ºÂÂ7,€‰ÔSXA,pZMçÅ&›èlÒdzù‚lÄ!%¨hÑ0©%˜H½Ä#K‘”§äC�‹h˜˜8¡hW޵8’ÉFÇ�[“Ÿ ˜|ûø1þ–{krøñ—_Oǧ§q£\áY�ݤÿîY-ÖmŠkVv³+%éùÔu†W6Dß~0¹6D_5#˜˜qÒ<˜ôd7ÍïIš`!t&¥ÃÒþO~:xËHªÔ‹tHmm¨—ÎO… Ýu÷� @£Mü´ÕŽi0AÓD¼û_±QÚsL°”<þÎ.ÍL´ëð×õ¨}û-Póý·ñç¬G ê˺Á×1zP‹ású¯cÑ$×¥GYð"F8ߤ,äö®è¤a_¥®×ãû¦VÄ´„‡É)Ð'~Ë«+Š\Õ8. ˜09ÇŠ›�g–!m‘aí«Ïò#¬ùH~Aáz†¡•‡ÿèž+{ -Œ_{ú &£à¥UÜÎÙ²¥‰>õ^ü4]>T®\6À„:þȳ�‡My< „Hsžü=ÜØ¥yßOÖK¾'“ÿ‰&lqÃUNI*wÑÆáS)¾Æ˜xU�&ê'\“d¯®VB”>Ò<ÜÕkt'Ï1"RÓmøn$"E…ÜùPâÃÒ�µ§À"ÛÏx¶^n÷‰ÄJvG¢n圴À’¡Ù8?Âu*ÚP5 füŒºHø= ˜ÔN•-×DC{¨i¢SÌDIÔVb"4 KÚ[X<Ý4_HrÊ÷(ç=ÁêbŠ&% "ù*ýöž5›[›¼nO#ó„ú_&%A¸V‘«[ñˆ¨­>rp{v…ÔŒÎÒA¯g5nƒ1Ö§WœO†ÜžD‡ÉÁk›|Pîl¶#š|²­‡Ò{(ñYunAá¶f»Ä»k¯mËo(æjœ´ L­Á½vÏÏo^œ³É{0'Ç0‡ÄB!š?8fS¦4yº|¨¬sÙdÔOsš«nÊ­Ïyé@yë›Ç_ Sçðv´n¡/L ÁQu-ëØyTé$þØ"˜ø¯U”Œìã¢~bÓ!WŸki×®3 ¶Þà#.~ðŸÕ¥'ߨÊúýˆIZ¶—Á’C¾}ZÄ`0Rñ.Cž„†‰þ˜Wähe$>Až**ÆÅÄ™¹”éò¡SÄ\µò3а´¯¾úêë¯Q ¤âé5mqÂä^ç/EHtW~”úúíµ b³dÀõ¿–uG�#'‡ \‡ˆ6}´tHÈýñP¥Ë¡á6¶–3ìï‚ �D`Ö‡Q¹Ž�ÁÌ$š–È0Ô2!…d‹â˜‘»‚eŠ(7APá.‚ŠFÓ…>( Ý6]>4òŸ£H8¦ tK²é0™Áâ†I_wÑ o¯yàd™÷Zû�º¡7våV@O6ÀÕÿÒ­�å0éÛ[$¦ô‰2§�ûÓ´B— L7Zzú¡·› ø6¶‡ü@Ø]ÖÇîD*þ bÈ—À0ùç`rî³G/)W'Lú¯±¾Å§ÊåC¾uyŸ2À„¶†;>W†¦þ7�œ&LâõvGYàdY†�û£.SÛß]9·£ñ$zÔ5yŸ0e<À£2­2¤®ÎËÇ�“Ù‰ŠÚøâE)i¶§Pb㆑X63¹�Å^MÝé(ó"øtg{‡É£.Öï[ÑYÌCøèÂa²Ìú` 9Y¶B÷�&üpÒvæa7;ŒØ>õÝ&ÿY0Á=hÈ€I¼f›…hœ›Î¢³%æ�ÅXPJ‚nИ¯"Jg¹¦þ÷£í ü$°À¤AÈýÑN:‹(0oÏžßP¦Š®nÇÕgÁDí*¢!&/g©ï„EEkÁv«ËÌŠÅx¾%ÏDnŽÀÂÃð’®2·îõòû,>Fa‚ôâ­x@]v¦tзßLüa˜xº&öÎQ&³í§w,ô'˜qOﲂo¸>ƒºÞyÒðÙGké[•˜,}C“Ÿ ?%œXiÅ sùéRï^¶{;¤øK‚x ë[eeý+4õ?ŸÃõ\Ñ�9§J†V ¹?ŒÚªxN6ß^†÷±j%Û]ˆw„EáP@G¸‚óïg|ñ‚L^&�‹Š²þƒ`ÅÕè�ÂòÓÛ�ò bS×úV,<¦Tžïj ÝËAx·Õ»,z yíÁõ‡Cnφ¶ÿJMÔÏI®Y‡<ruþøžK]!FDð`^ wá�‚�\ºMnA0K„ª<¾ïÒ-ÛÆÐ€ç¥`bÀd4m.L®]³ÎÁa"U‹ÜkúG�[·R&RÚ­¯?ŸB]S†íi·n¡ƒ`b#l0€:?·sø`rl˜ð7Ï™G‚)†ÏÉóDŸpuG\õ1æÓ.*5÷ ‡õáV¢âö‰!÷K™“û¼Jïýƒ&zî5�’[O&'¿›•éÔµ”'_¡í i­&^Nn–4×ï>G�˜&"tOøsGÅ㉊ÖmÝUcú%ú6°¨Š>ôrfÀdçO *ÚÌ“žÔàoÿÓ¹×lôáæ‹áÇ“ßÖÏ{òÝçõS¨kö´'“_£Ó†Õ„\¹‡=…*@ÀÃ'Ç€I‚˜]TTÀ¤ñüÓ¹×lÄoÄöòýwvT¦Q×€P 8^Ðù ‰òý·Ý Ë�“Ɖm01¯éf¿�νfSè`aÂoo×*`(™têg¡˜È'0„ÈÝiøDø ïAiÀäu9›p˜Xš»§æ^£Ã«Ìa‚Š�@M]›Cô&p%�”ïA8øêÉ·¢ç«×&L¸¨XM2+õÜk‚Y0È´­„W†Ï£©kiÑ0áŶôo|ÓáÞ²ôØ€I‚Ãä ç– VÝi&˜4\šš{�k(¾µóŠÿÉwTê=s˜|ÇaÂ=O´cŒ0‰ÉÆ6ÑabeLÄ[غ³Ñ¹×`&<倱6Y¯ M]›$bì<&EáñÿO¸blxrG‘˜â4`ýkؘ“Ý4µ¸Lyö­ß}w£?æ­ëVª±ÆðµªþàJ{ì,Ó=%- �$Æç÷ÐÏÃüž'$bý�6ð{=¼×Ãy%Ö’VšU¯)(Dþ\BË�*Lxè =LçêÛ= …3­i©}©Š+Š)­XØÑe—¬ VÔOX O\¯4Ë¢� p¤$©Ë„¢b /n&Ä_´ÐÛµì5pa��=Çú=7ØXÈŃùT A ¤8½µ­�6p65 ‰>šu Fª“u‘?®å§¢Bb€^/…0Ñ…!(ù ³MÝ$±+E·bd`Ãï-ZÑ·.n™·àJ'×ω¸–Ø„`bÅ4шš©¥y«,“ÎѼؔé1·ª‚^ºòá�ëaã8�ˆ@<ÂÆÖïÕWÅÕÜü$©ª¾¬C´š‘?·¦åçr¶Rå.m:þ«Ö,)LÄÛÔfA<0"ˆÈ 2³mÞY,é`Vゞœf{íúœ&Yo­£Öô lB99±‹è³–Aª]f¨•µ®Ñ.Éo�Ø¥š¤¼!ÕTüMÂí×n¤›t0³1-u�¤Yí©›µ}Ž 1ßyÁÀ$ûÚƒ×ÙÍë‰í,ûüHæÒ|}[ñ6/”Ø=.P#­lgÍrû""a @?*Më;ÌÁJ¼Bj�&g>NI)*?h³ƒ-Â`<Ï–åÔÚ�1 Sëcj�¥–��m;ÏÀ&”CÏ3jñ,mâÖw°@Qä1Àu…'YB,üDÑðeÞpq˜H½�hÜöi•�Gß°sˆ�ÝNìå_´Ûca=·OÐrÑçö_A€`àpdX¨"°o1—öÃêá¯f®Ð’B³6ðY;[!ò7rrWœ.tiF•%׺{@çÐ0¹@ÉMø»1ÑwJÒ€1aÙvÆÌ, {q|m«¸O¿:ÀÀ‚>gÀÑ®ˆÈiº¡XÞH¢~¾«G ýxêm`âkfÀ„‹Ú§Ú”ù÷‚‰IÀÄ$L„ab-Àä\Œ lRïYz´.NÄÙ�&\k»Þ°CÐmwû¬&u'ÊdÑÐ`²·¸ž?ý6U�¯Æa‚ƒuר/Ï~w;ö{(>ŽºÝtEò  òáÉø~à”\D ÂÒ$hŸ{!µfÖdÛp IÏÚÇ•E­w|a @~�t 0ñíEÛ8ÂFeº‡£ÔC ‘*iRP_ž }5 ì}f¶›RovóüÞ½á¸.§ŽÕz°ˆ\ ¥Nƒ –™jˆÕDˆÎ]@…† ¦ºó;æv—Õ§>GÄ-a�G> Ì4ê�Via~ƒ#‘@ùžaêÁ‘'¤ÍZ~y-ßÇñŠE@ingHw‘…34Ñý{D ŠmÇ€‰B¨`»[÷Y™e�¶�G«÷U„³ö]ž( ¡ µ…·ŠµVX!4Êšž�ív4;[^˜`AZM„tèm¯ÉÔ{ÚLàzAÛtl% þÞä»cG"ÀR;U”‹â«¿¯tŒ£ò·À� ?ý"öØ~”S]ù‚ùð$8à[“ÿA{ó–o€”ÏU§˜µ¹ðÓ�h–',òçU3ó5-?uÕ{Û Z]#ëC\r][‹×€I$W#3·`Å?Ï«¥j8I¹™CgH´o…êbd`ËèàýXjl‚”ý§¿`®pÏ :Ùœ‚ϱ]ë­¢q€Ý'œíÜ6Á¸¬qñö‚ ½Ÿí¯æëRì#,—ßCJ=!ÙGÁ|ôè€NÕƒ?FFÎQȰ>Ë‹YBñ/J ¢¹4"B�MG…zekAÁa§¤È”B8?ÿ�_¢*R ½EEŒ l­ö[ ó[tÍzºß{……‡Uz§Ú›_xØ×›ß/Uçª��ºk Øg®¾ßÖÀ½s5ÐÙ„ËŠÖ×äÔÏ�Œ\¨ïM óãWÞrñÊÈõBh�OŸ5]äEtÝxÒÑMK«%ˆg¢)D1¥+›ÂûDCï¶ñ«-Ö°¶¨Iê-Ôž™eºÑ+ÌYO‘’ã|j1ø&ŠI×é W…(šT(Oµbe`ÃÄiz}ú­É“ŒÊHCÕZØ—ŠZ³»¸È,:é?õÕÀ„ó ^”ì5ìKGÛÙ$)¯^Ããþ×E‰Ù‹³¤È¢ W'Êœ4YR~HB)L¦Ëžë-™1Ž??(˜0±Io­J#¬Tg:S*]èõ}šüÏÕñÄ{~h01`rž J&J+<–§ì¥ëÁª=¬øp=”ÎH‹ ׺:—“Ëü;� ˜®A‰¿ßß|’*O²ö-�$ø‡‰YÙk) OÅ6žtk0ÙÏîȤ6tÁ{úr»ô‡‰|·­&1&›Ô“û+­&—Ø€”&]dƒ—ÌCXcN–Í &ΈM‰Ô›ÖˆrŸ)Ê•Š0Û¨îd‘&íVwŠ`r Ó¡HµÇ€‘9Êü%U¤t; ˜@¶O3Ÿgz¤Þ´€>�惭ú¢æýÌ€Iݹ’zé"Ï´…³+ÁD¦Áê³Øy›ÒM”þYœM Ì·¡¹¹¹…þ¸F�g•©Çž§P’±±žM"8ÝU“KÐçý£Ì€I¨®£Ô?g^ÊEðe±šPüÎ9(çŠê¹.mp6 /w ŸÒ~îõ-�—§¡Á¹áGÍ^7ÁdÄ¥ö§"Ξˆù+ôðؾ&@¤± ·B4 oõ‡�“œ4zT—Ú(´ÿAfÀÄ·qª×XËíbÓ!ÞëÍ”… ç/”.àÈ‚¥¥hXéÙˆ�祟tFU1ÀƒGî²*sðͽÅÛyÀßtÿUÒÄð?ˆ»fÀ¤·Õw¥ÅÎße? H<þO²!†4›,Ç/½µ¯p;ˆk’XMf“»~_Mð+#|¯L¥MGWû‹‚Éu6þ6�\a-óâT$`Tù!0;„³É›ÇŠ‚Ç2Dv%Èj²0É0™¿ á¿ËÓL‚¼&šqÀ«Á‘xT>¾Ã ˜,§0@¡é§ÃÊ:P~ó\�Q UŠÕıñÅ�«ÞÂÙd‰¦XQ‚0�ÄXM&’LBL‘*]¨ÔU%9L–„[\0é÷ø“EÝ;ðÛâçvq˜èj&8Í$±þÞ BL “«˜œ+"˜,Z€m€—“ij™aò&ÜF¼Ë:J½€ÉÒhµ?‚‰"9k¬¥¡ ù9ä§m:þëspĽä$m:ý‹;JC#Ðl¼ &o&êjB&Oã$½Ä ^&À!~¾ï@�OWû#˜LŒ646æœÁÉtq8ÈÏQ…äûèl2Š]˜‡³‰_h>ð:& z5‘Ÿn*¯l5©¤Ô6¸&(&l÷‡¬„ Sû3;tµ?l-š�¡¾ÆÊ 10èC2�OÙŸtÞ�DÀÕOO:+Ï-ÀD�É‚IFú &sÒR�’‚‰²dUÆŠ+–Ï{:ÝšïEqbïÍþ˜¸<ëH¾�.ƒ*FºK² (|�÷x£ÔþVåÊÍÍ=4 ¢¡fQ��F6l+hkÊí÷mlÝ Í[ƒz3¶¾/æ%L–/y0™—h0áô#nþ X¡S¬H·¦5`"#›¨à=‚¸óع×`<:Ï¥]¨p�ìÝ1¤ºT ‡z¦¨ýqSÑŠùaŽêõ©èT}ªêŽžG wâÀdMbä¸yÍÚ5×:Y0„èòiéÖP*6½#ªRY&ºÜ]´úH7žX¢ÃöD…êÂP�äÇ Ühš`bÀd)Á$se"äÄNµK<�EݪµYâ0A£whòŒlT©^¿ÖG@#2FVÍ™&ÓÂûªÞ½²U a`’³a]¢Ã¿²‰òœ]”aÍO0Aã¨Ö�z¬Z¶:äÞ§�ðDl»�;^&b ø�ÂdÙ’·Lð¤“h0QRSª�± ¾ ›[Þ¾ÁØ4oÈE6 i|Aõ 6T§�<”kNµ,Kb»_ &°"LÖ¯[�ùÁ$±�°lœSé¬a®™ø›Þ¨IØ8½M:ð®ã2]¥ól˜»Ôž,1`2#L²9LÒ—-NX˜XýäÝå³�ÃøåÛó¶"�âàAÀ$ÜF’°!gÓî6$¤½ F(¨(/t61`Â?&‹ù«àÓ �q¤°p{~_MD㽡”„í]äª�ÜÀ¡¤ÄQ¸yJ-9#L ˜,‰ú¤“°GXÅz‡É ½.ÛXOg“ Z#ÛN{ §Û÷6KÊ|°”.ѳ3FÒÎ3bEž+6`23LÖÑk & &$„/ó¸œËlÔ.Õtq˜ðÆ�KýE- Û ((¡»¯šR\8i®ç.=Ævf˜lÀÑÏÃxWÏa’–p09^$`2jCZ·Ýù”a­Ï5¢ÑÚ½H†¤�ÛòY‰*ÑHF�ˆmgc&3ÃdíêÌéxПtî›NO‹�«'@AR®p¢Zm ÑP¢2²½÷áûm¾¨‘ºë……Í+²Ÿ÷MÇ)lÆ/þºóë“9K𪞟`§½6‘¥D2eªN—¢ˆFTÆ ‘ïD O‘gþBìÑ£þf4=ê﵃ÉbÚsÄÑ$!a¢gKÉÚd™®($шÊÈfC-zD‘ùÄØ0A _3·–™Õ‘¢£þ^;˜¬å‹‰8š< ƒ½æT¯1aã>M«âéx>QA-fÔŸpHp˜Ð›ú𞣟`èlb²ÅXbdyæÌHòL0¹Ên·"PÃb~‘€=�—ÂÿDïÔ¨?!èôè‰ þn Ô5¾ç$ L`¶˜š™Å¦Ä€I} “q‡êƒ© a1?O8Ð/q€­¼cÓ¢þ<«¹`dZBÃäíÌwh1yDX±ç$LÈ8$ùY ÙÀ`›‰ÅV÷ŽúÌáÿûÆÿmtH‰Ã„Ÿ`A\S*‰ùiz`X Põò^5ð^¥¨¿€“¢þÔô$òJºÊ Ñ…xÀ²Àb‚€B6gîâÌ&´šð�4êO1-‰`)Òe’`™Ú«à},1Øèï™ÿCd˜ ’ï˨FíVÿó¿¾ñ_ÿoc½V…%·nnmÝÜâ~ÈñæÉÒaìCÁLP¥í�ñ;ÜÜUB½røë{ØX½×¼Æî„ ”Ò¿ kGȱˆ¼üŽ2ÿ)Úæ-å<“9i×OH«fƒÒt»À†k‰Lñ‹çXíÿ¯V®‚ €Ff“sï“‚h€š(€:Üù¿w²úuœ¬¼kËÙª.6"F­XÕŒ`rÀÈ¢ìÎÝAœ^ãÌ¡€É÷…Δ«œùáÜ•»ÜQkþ4*)jÎàû£¼ŒÓ•uî".²*ÃQhIEND®B`‚beetbox-beets-00724b7/docs/plugins/spotify.rst0000664000175000017500000001330115253035401020711 0ustar pieterpieterSpotify Plugin ============== The ``spotify`` plugin generates Spotify_ playlists from tracks in your library with the ``beet spotify`` command using the `Spotify Search API`_. Also, the plugin can use the Spotify Album_ and Track_ APIs to provide metadata matches for the importer. .. _album: https://developer.spotify.com/documentation/web-api/reference/get-an-album .. _spotify: https://open.spotify.com/ .. _spotify search api: https://developer.spotify.com/documentation/web-api/reference/search .. _track: https://developer.spotify.com/documentation/web-api/reference/get-track Why Use This Plugin? -------------------- - You're a Beets user and Spotify user already. - You have playlists or albums you'd like to make available in Spotify from Beets without having to search for each artist/album/track. - You want to check which tracks in your library are available on Spotify. - You want to autotag music with metadata from the Spotify API. - You want to obtain track popularity and audio features (e.g., danceability) Basic Usage ----------- First, enable the ``spotify`` plugin (see :ref:`using-plugins`). Then, use the ``spotify`` command with a beets query: :: beet spotify [OPTIONS...] QUERY Here's an example: :: $ beet spotify "In The Lonely Hour" Processing 14 tracks... https://open.spotify.com/track/19w0OHr8SiZzRhjpnjctJ4 https://open.spotify.com/track/3PRLM4FzhplXfySa4B7bxS [...] Command-line options include: - ``-m MODE`` or ``--mode=MODE`` where ``MODE`` is either "list" or "open" controls whether to print out the playlist (for copying and pasting) or open it in the Spotify app. (See below.) - ``--show-failures`` or ``-f``: List the tracks that did not match a Spotify ID. You can enter the URL for an album or song on Spotify at the ``enter Id`` prompt during import: :: Enter search, enter Id, aBort, eDit, edit Candidates, plaY? i Enter release ID: https://open.spotify.com/album/2rFYTHFBLQN3AYlrymBPPA Configuration ------------- This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`. Default ~~~~~~~ .. code-block:: yaml spotify: mode: list region_filter: show_failures: no tiebreak: popularity regex: [] search_query_ascii: no client_id: REDACTED client_secret: REDACTED tokenfile: spotify_token.json data_source_mismatch_penalty: 0.5 search_limit: 5 .. conf:: mode :default: list Controls how the playlist is output: - ``list``: Print out the playlist as a list of links. This list can then be pasted in to a new or existing Spotify playlist. - ``open``: This mode actually sends a link to your default browser with instructions to open Spotify with the playlist you created. Until this has been tested on all platforms, it will remain optional. .. conf:: region_filter :default: A two-character country abbreviation, to limit results to that market. .. conf:: show_failures :default: no List each lookup that does not return a Spotify ID (and therefore cannot be added to a playlist). .. conf:: tiebreak :default: popularity How to choose the candidate if there is more than one identical result. For example, there might be multiple releases of the same album. - ``popularity``: pick the more popular candidate - ``first``: pick the first candidate .. conf:: regex :default: [] An array of regex transformations to perform on the track/album/artist fields before sending them to Spotify. Can be useful for changing certain abbreviations, like ft. -> feat. For example: .. code-block:: yaml regex: - field: albumartist search: Something replace: Replaced - field: title search: Something Else replace: AlsoReplaced .. conf:: search_query_ascii :default: no If enabled, the search query will be converted to ASCII before being sent to Spotify. Converting searches to ASCII can enhance search results in some cases, but in general, it is not recommended. For instance, ``artist:deadmau5 album:4×4`` will be converted to ``artist:deadmau5 album:4x4`` (notice ``×!=x``). .. include:: ./shared_metadata_source_config.rst Obtaining Track Popularity and Audio Features from Spotify ---------------------------------------------------------- Spotify provides information on track popularity_ and audio features_ that can be used for music discovery. .. _features: https://developer.spotify.com/documentation/web-api/reference/get-audio-features .. _popularity: https://developer.spotify.com/documentation/web-api/reference/get-track The ``spotify`` plugin provides an additional command ``spotifysync`` to obtain these track attributes from Spotify: - ``beet spotifysync [-f]``: obtain popularity and audio features information for every track in the library. By default, ``spotifysync`` will skip tracks that already have this information populated. Using the ``-f`` or ``-force`` option will download the data even for tracks that already have it. Please note that ``spotifysync`` works on tracks that have the Spotify track identifiers. So run ``spotifysync`` only after importing your music, during which Spotify identifiers will be added for tracks where Spotify is chosen as the tag source. In addition to ``popularity``, the command currently sets these audio features for all tracks with a Spotify track ID: - ``acousticness`` - ``danceability`` - ``energy`` - ``instrumentalness`` - ``key`` - ``liveness`` - ``loudness`` - ``mode`` - ``speechiness`` - ``tempo`` - ``time_signature`` - ``valence`` beetbox-beets-00724b7/docs/plugins/badfiles.rst0000664000175000017500000000476715253035401021005 0ustar pieterpieterBad Files Plugin ================ The ``badfiles`` plugin adds a ``beet bad`` command to check for missing and corrupt files. Configuring ----------- First, enable the ``badfiles`` plugin (see :ref:`using-plugins`). The default configuration defines the following default checkers, which you may need to install yourself: - mp3val_ for MP3 files - FLAC_ command-line tools for FLAC files You can also add custom commands for a specific extension, like this: :: badfiles: check_on_import: yes import_action_on_error: skip import_action_on_warning: continue commands: ogg: myoggchecker --opt1 --opt2 flac: flac --test --warnings-as-errors --silent Custom commands will be run once for each file of the specified type, with the path to the file as the last argument. Commands must return a status code greater than zero for a file to be considered corrupt. You can run the checkers when importing files by using the ``check_on_import`` option. When on, checkers will be run against every imported file and warnings and errors will be presented when selecting a tagging option. ``import_action_on_error`` and ``import_action_on_warning`` can be used to take automatic action on warnings and errors. Both options default to ``ask``. Valid options for both ``import_action_on_(warning|error)`` are ``ask skip abort continue``. .. _flac: https://xiph.org/flac/ .. _mp3val: https://sourceforge.net/projects/mp3val/ Using ----- Type ``beet bad`` with a query according to beets' usual query syntax. For instance, this will run a check on all songs containing the word "wolf": :: beet bad wolf This one will run checks on a specific album: :: beet bad album_id:1234 Here is an example where the FLAC decoder signals a corrupt file: :: beet bad title::^$ /tank/Music/__/00.flac: command exited with status 1 00.flac: *** Got error code 2:FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH 00.flac: ERROR while decoding data state = FLAC__STREAM_DECODER_READ_FRAME Note that the default ``mp3val`` checker is a bit verbose and can output a lot of "stream error" messages, even for files that play perfectly well. Generally, if more than one stream error happens, or if a stream error happens in the middle of a file, this is a bad sign. By default, only errors for the bad files will be shown. In order for the results for all of the checked files to be seen, including the uncorrupted ones, use the ``-v`` or ``--verbose`` option. beetbox-beets-00724b7/docs/plugins/fromfilename.rst0000664000175000017500000000101015253035401021652 0ustar pieterpieterFromFilename Plugin =================== The ``fromfilename`` plugin helps to tag albums that are missing tags altogether but where the filenames contain useful information like the artist and title. When you attempt to import a track that's missing a title, this plugin will look at the track's filename and guess its track number, title, and artist. These will be used to search in MusicBrainz and match track ordering. To use the ``fromfilename`` plugin, enable it in your configuration (see :ref:`using-plugins`). beetbox-beets-00724b7/docs/plugins/hook.rst0000664000175000017500000000415115253035401020157 0ustar pieterpieterHook Plugin =========== Internally, beets uses *events* to tell plugins when something happens. For example, one event fires when the importer finishes processes a song, and another triggers just before the ``beet`` command exits. The ``hook`` plugin lets you run commands in response to these events. .. _hook-configuration: Configuration ------------- To configure the plugin, make a ``hook`` section in your configuration file. The available options are: - **hooks**: A list of events and the commands to run (see :ref:`individual-hook-configuration`). Default: Empty. .. _individual-hook-configuration: Configuring Each Hook ~~~~~~~~~~~~~~~~~~~~~ Each element under ``hooks`` should have these keys: - **event**: The name of the event that will trigger this hook. See the :ref:`plugin events ` documentation for a list of possible values. - **command**: The command to run when this hook executes. .. _command-substitution: Command Substitution ~~~~~~~~~~~~~~~~~~~~ Commands can access the parameters of events using `Python string formatting`_. Use ``{name}`` in your command and the plugin will substitute it with the named value. The name can also refer to a field, as in ``{album.path}``. .. _python string formatting: https://peps.python.org/pep-3101/ You can find a list of all available events and their arguments in the :ref:`plugin events ` documentation. Example Configuration --------------------- .. code-block:: yaml hook: hooks: # Output on exit: # beets just exited! # have a nice day! - event: cli_exit command: echo "beets just exited!" - event: cli_exit command: echo "have a nice day!" # Output on item import: # importing "" # Where is the item being imported - event: item_imported command: echo "importing \"{item.path}\"" # Output on write: # writing to "" # Where is the file being written to - event: write command: echo "writing to {path}" beetbox-beets-00724b7/docs/plugins/metasync.rst0000664000175000017500000000343115253035401021042 0ustar pieterpieterMetaSync Plugin =============== This plugin provides the ``metasync`` command, which lets you fetch certain metadata from other sources: for example, your favorite audio player. Currently, the plugin supports synchronizing with the Amarok_ music player, and with iTunes_. It can fetch the rating, score, first-played date, last-played date, play count, and track uid from Amarok. .. _amarok: https://amarok.kde.org/ .. _itunes: https://www.apple.com/itunes/ Installation ------------ Enable the ``metasync`` plugin in your configuration (see :ref:`using-plugins`). To synchronize with Amarok, you'll need the dbus-python_ library. In such case, install ``beets`` with ``metasync`` extra .. code-block:: bash pip install "beets[metasync]" .. _dbus-python: https://dbus.freedesktop.org/releases/dbus-python/ Configuration ------------- To configure the plugin, make a ``metasync:`` section in your configuration file. The available options are: - **source**: A list of comma-separated sources to fetch metadata from. Set this to "amarok" or "itunes" to enable synchronization with that player. Default: empty The follow subsections describe additional configure required for some players. itunes ~~~~~~ The path to your iTunes library **xml** file has to be configured, e.g.: :: metasync: source: itunes itunes: library: ~/Music/iTunes Library.xml Please note the indentation. Usage ----- Run ``beet metasync QUERY`` to fetch metadata from the configured list of sources. The command has a few command-line options: - To preview the changes that would be made without applying them, use the ``-p`` (``--pretend``) flag. - To specify temporary sources to fetch metadata from, use the ``-s`` (``--source``) flag with a comma-separated list of a sources. beetbox-beets-00724b7/docs/plugins/advancedrewrite.rst0000664000175000017500000000737515253035401022401 0ustar pieterpieterAdvanced Rewrite Plugin ======================= The ``advancedrewrite`` plugin lets you easily substitute values in your templates and path formats, similarly to the :doc:`/plugins/rewrite`. It's recommended to read the documentation of that plugin first. The *advanced* rewrite plugin does not only support the simple rule format of the ``rewrite`` plugin, but also an advanced format: there, the plugin doesn't consider the value of the rewritten field, but instead checks if the given item matches a :doc:`query `. Only then, the field is replaced with the given value. It's also possible to replace multiple fields at once, and even supports multi-valued fields. To use advanced field rewriting, first enable the ``advancedrewrite`` plugin (see :ref:`using-plugins`). Then, make a ``advancedrewrite:`` section in your config file to contain your rewrite rules. In contrast to the normal ``rewrite`` plugin, you need to provide a list of replacement rule objects, which can have a different syntax depending on the rule complexity. The simple syntax is the same as the one of the rewrite plugin and allows to replace a single field: :: advancedrewrite: - artist ODD EYE CIRCLE: ì�´ë‹¬ì�˜ 소녀 오드아ì�´ì�¨í�´ As with :doc:`/plugins/rewrite`, simple rules applied to a multi-valued field rewrite only the matching list entries. The advanced syntax consists of a query to match against, as well as a map of replacements to apply. For example, to credit all songs of ODD EYE CIRCLE before 2023 to their original group name, you can use the following rule: :: advancedrewrite: - match: "mb_artistid:dec0f331-cb08-4c8e-9c9f-aeb1f0f6d88c year:..2022" replacements: artist: ì�´ë‹¬ì�˜ 소녀 오드아ì�´ì�¨í�´ artist_sort: LOONA / ODD EYE CIRCLE Note how the sort name is also rewritten within the same rule. You can specify as many fields as you'd like in the replacements map. If you need to work with multi-valued fields, you can use the following syntax: :: advancedrewrite: - match: "artist:배유빈 feat. 김미현" replacements: artists: - 유빈 - 미미 As a convenience, the plugin applies patterns for the ``artist`` field to the ``albumartist`` field as well. (Otherwise, you would probably want to duplicate every rule for ``artist`` and ``albumartist``.) Make sure to properly quote your query strings if they contain spaces, otherwise they might not do what you expect, or even cause beets to crash. Take the following example: :: advancedrewrite: # BAD, DON'T DO THIS! - match: album:THE ALBUM replacements: artist: New artist On the first sight, this might look sane, and replace the artist of the album *THE ALBUM* with *New artist*. However, due to the space and missing quotes, this query will evaluate to ``album:THE`` and match ``ALBUM`` on any field, including ``artist``. As ``artist`` is the field being replaced, this query will result in infinite recursion and ultimately crash beets. Instead, you should use the following rule: :: advancedrewrite: # Note the quotes around the query string! - match: album:"THE ALBUM" replacements: artist: New artist A word of warning: This plugin theoretically only applies to templates and path formats; it initially does not modify files' metadata tags or the values tracked by beets' library database, but since it *rewrites all field lookups*, it modifies the file's metadata anyway. See comments in issue :bug:`2786`. As an alternative to this plugin the simpler but less powerful :doc:`/plugins/rewrite` can be used. If you don't want to modify the item's metadata and only replace values in file paths, you can check out the :doc:`/plugins/substitute`. beetbox-beets-00724b7/docs/plugins/ihate.rst0000664000175000017500000000206615253035401020314 0ustar pieterpieterIHate Plugin ============ The ``ihate`` plugin allows you to automatically skip things you hate during import or warn you about them. You specify queries (see :doc:`/reference/query`) and the plugin skips (or warns about) albums or items that match any query. To use the ``ihate`` plugin, enable it in your configuration (see :ref:`using-plugins`). Configuration ------------- To configure the plugin, make an ``ihate:`` section in your configuration file. The available options are: - **skip**: Never import items and albums that match a query in this list. Default: ``[]`` (empty list). - **warn**: Print a warning message for matches in this list of queries. Default: ``[]``. Here's an example: :: ihate: warn: - artist:rnb - genres:soul # Only warn about tribute albums in rock genre. - genres:rock album:tribute skip: - genres::russian\srock - genres:polka - artist:manowar - album:christmas The plugin trusts your decision in "as-is" imports. beetbox-beets-00724b7/docs/plugins/mbsubmit.rst0000664000175000017500000000770415253035401021050 0ustar pieterpieterMusicBrainz Submit Plugin ========================= The ``mbsubmit`` plugin provides extra prompt choices when an import session fails to find a good enough match for a release. Additionally, it provides an ``mbsubmit`` command that prints the tracks of the current album in a format that is parseable by MusicBrainz's `track parser`_. The prompt choices are: - Print the tracks to stdout in a format suitable for MusicBrainz's `track parser`_. - Open the program Picard_ with the unmatched folder as an input, allowing you to start submitting the unmatched release to MusicBrainz with many input fields already filled in, thanks to Picard reading the preexisting tags of the files. For the last option, Picard_ is assumed to be installed and available on the machine including a ``picard`` executable. Picard developers list `download options`_. `other GNU/Linux distributions`_ may distribute Picard via their package manager as well. .. _download options: https://picard.musicbrainz.org/downloads/ .. _other gnu/linux distributions: https://repology.org/project/picard-tagger/versions .. _picard: https://picard.musicbrainz.org/ .. _track parser: https://wiki.musicbrainz.org/History:How_To_Parse_Track_Listings Usage ----- Enable the ``mbsubmit`` plugin in your configuration (see :ref:`using-plugins`) and select one of the options mentioned above. Here the option ``Print tracks`` choice is demonstrated: :: No matching release found for 3 tracks. For help, see: https://beets.readthedocs.org/en/latest/faq.html#nomatch [U]se as-is, as Tracks, Group albums, Skip, Enter search, enter Id, aBort, Print tracks, Open files with Picard? p 01. An Obscure Track - An Obscure Artist (3:37) 02. Another Obscure Track - An Obscure Artist (2:05) 03. The Third Track - Another Obscure Artist (3:02) No matching release found for 3 tracks. For help, see: https://beets.readthedocs.org/en/latest/faq.html#nomatch [U]se as-is, as Tracks, Group albums, Skip, Enter search, enter Id, aBort, Print tracks? You can also run ``beet mbsubmit QUERY`` to print the track information for any album: :: $ beet mbsubmit album:"An Obscure Album" 01. An Obscure Track - An Obscure Artist (3:37) 02. Another Obscure Track - An Obscure Artist (2:05) 03. The Third Track - Another Obscure Artist (3:02) As MusicBrainz currently does not support submitting albums programmatically, the recommended workflow is to copy the output of the ``Print tracks`` choice and paste it into the parser that can be found by clicking on the "Track Parser" button on MusicBrainz "Tracklist" tab. Configuration ------------- To configure the plugin, make a ``mbsubmit:`` section in your configuration file. The following options are available: - **format**: The format used for printing the tracks, defined using the same template syntax as beets’ :doc:`path formats `. Default: ``$track. $title - $artist ($length)``. - **threshold**: The minimum strength of the autotagger recommendation that will cause the ``Print tracks`` choice to be displayed on the prompt. Default: ``medium`` (causing the choice to be displayed for all albums that have a recommendation of medium strength or lower). Valid values: ``none``, ``low``, ``medium``, ``strong``. - **picard_path**: The path to the ``picard`` executable. Could be an absolute path, and if not, ``$PATH`` is consulted. The default value is simply ``picard``. Windows users will have to find and specify the absolute path to their ``picard.exe``. That would probably be: ``C:\Program Files\MusicBrainz Picard\picard.exe``. Please note that some values of the ``threshold`` configuration option might require other ``beets`` command line switches to be enabled in order to work as intended. In particular, setting a threshold of ``strong`` will only display the prompt if ``timid`` mode is enabled. You can find more information about how the recommendation system works at :ref:`match-config`. beetbox-beets-00724b7/docs/plugins/loadext.rst0000664000175000017500000000314015253035401020654 0ustar pieterpieterLoad Extension Plugin ===================== Beets uses an SQLite database to store and query library information, which has support for extensions to extend its functionality. The ``loadext`` plugin lets you enable these SQLite extensions within beets. One of the primary uses of this within beets is with the `"ICU" extension`_, which adds support for case insensitive querying of non-ASCII characters. .. _"icu" extension: https://www.sqlite.org/src/dir?ci=7461d2e120f21493&name=ext/icu Configuration ------------- To configure the plugin, make a ``loadext`` section in your configuration file. The section must consist of a list of paths to extensions to load, which looks like this: .. code-block:: yaml loadext: - libicu If a relative path is specified, it is resolved relative to the beets configuration directory. If no file extension is specified, the default dynamic library extension for the current platform will be used. Building the ICU extension -------------------------- This section is for **advanced** users only, and is not an in-depth guide on building the extension. To compile the ICU extension, you will need a few dependencies: - gcc - icu-devtools - libicu - libicu-dev - libsqlite3-dev Here's roughly how to download, build and install the extension (although the specifics may vary from system to system): .. code-block:: shell $ wget https://sqlite.org/2019/sqlite-src-3280000.zip $ unzip sqlite-src-3280000.zip $ cd sqlite-src-3280000/ext/icu $ gcc -shared -fPIC icu.c $(icu-config --ldflags) -o libicu.so $ cp libicu.so ~/.config/beets beetbox-beets-00724b7/docs/plugins/filefilter.rst0000664000175000017500000000203415253035401021342 0ustar pieterpieterFileFilter Plugin ================= The ``filefilter`` plugin allows you to skip files during import using regular expressions. To use the ``filefilter`` plugin, enable it in your configuration (see :ref:`using-plugins`). Configuration ------------- To configure the plugin, make a ``filefilter:`` section in your configuration file. The available options are: - **path**: A regular expression to filter files based on their path and name. Default: ``.*`` (import everything) - **album_path** and **singleton_path**: You may specify different regular expressions used for imports of albums and singletons. This way, you can automatically skip singletons when importing albums if the names (and paths) of the files are distinguishable via a regex. The regexes defined here take precedence over the global ``path`` option. Here's an example: :: filefilter: path: .*\d\d[^/]+$ # will only import files which names start with two digits album_path: .*\d\d[^/]+$ singleton_path: .*/(?!\d\d)[^/]+$ beetbox-beets-00724b7/docs/plugins/replaygain.rst0000664000175000017500000002020415253035401021347 0ustar pieterpieterReplayGain Plugin ================= This plugin adds support for ReplayGain_, a technique for normalizing audio playback levels. .. _replaygain: https://wiki.hydrogenaudio.org/index.php?title=ReplayGain Installation ------------ This plugin can use one of many backends to compute the ReplayGain values: GStreamer, mp3gain (and its cousins, aacgain and mp3rgain), Python Audio Tools, ffmpeg or metaflac. ffmpeg and mp3gain can be easier to install. mp3gain supports fewer audio formats than the other backends, and metaflac only supports FLAC. Once installed, this plugin analyzes all files during the import process. This can be a slow process; to instead analyze after the fact, disable automatic analysis and use the ``beet replaygain`` command (see below). To speed up analysis with some of the available backends, this plugin processes tracks or albums (when using the ``-a`` option) in parallel. By default, a single thread is used per logical core of your CPU. GStreamer ~~~~~~~~~ To use GStreamer_ for ReplayGain analysis, you will of course need to install GStreamer and plugins for compatibility with your audio files. You will need at least GStreamer 1.0 and `PyGObject 3.x`_ (a.k.a. ``python-gi``). .. _gstreamer: https://gstreamer.freedesktop.org/ .. _pygobject 3.x: https://pygobject.gnome.org/ Then, install ``beets`` with ``replaygain`` extra which installs ``GStreamer`` bindings for Python .. code-block:: bash pip install "beets[replaygain]" Lastly, enable the ``replaygain`` plugin in your configuration (see :ref:`using-plugins`) and specify the GStreamer backend by adding this to your configuration file: :: replaygain: backend: gstreamer The GStreamer backend does not support parallel analysis. Supported ``command`` backends ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In order to use this backend, you will need to install a supported command-line tool: - mp3gain_ (MP3 only) - aacgain_ (MP3, AAC/M4A) - mp3rgain_ (MP3, AAC/M4A) mp3gain +++++++ - On Linux, mp3gain_ is probably in your repositories. On Debian or Ubuntu, for example, you can run ``apt-get install mp3gain``. - On Windows, download and install mp3gain_. aacgain +++++++ - On macOS, install via Homebrew_: ``brew install aacgain``. - For other platforms, download from aacgain_ or use a compatible fork if available for your system. mp3rgain ++++++++ mp3rgain_ is a modern Rust rewrite of ``mp3gain`` that also supports AAC/M4A files. It addresses security vulnerability CVE-2019-18359 present in the original mp3gain and works on modern systems including Windows 11 and macOS with Apple Silicon. - On macOS, install via Homebrew_: ``brew install mp3rgain``. - On Linux, install via Nix: ``nix-env -iA nixpkgs.mp3rgain`` or from your distribution packaging (for example, AUR on Arch Linux). - On Windows, download and install mp3rgain_. Configuration +++++++++++++ .. code-block:: yaml replaygain: backend: command command: # mp3rgain, mp3gain, or aacgain If beets doesn't automatically find the command executable, you can configure the path explicitly like so: .. code-block:: yaml replaygain: command: /Applications/MacMP3Gain.app/Contents/Resources/aacgain .. _aacgain: https://github.com/dgilman/aacgain .. _homebrew: https://brew.sh .. _mp3gain: https://sourceforge.net/projects/mp3gain/download.php .. _mp3rgain: https://github.com/M-Igashi/mp3rgain Python Audio Tools ~~~~~~~~~~~~~~~~~~ This backend uses the `Python Audio Tools`_ package to compute ReplayGain for a range of different file formats. The package is not available via PyPI; it must be installed manually (only versions preceding 3.x are compatible). On OS X, most of the dependencies can be installed with Homebrew_: :: brew install mpg123 mp3gain vorbisgain faad2 libvorbis The Python Audio Tools backend does not support parallel analysis. .. _python audio tools: https://sourceforge.net/projects/audiotools/ ffmpeg ~~~~~~ This backend uses ffmpeg to calculate EBU R128 gain values. To use it, install the ffmpeg_ command-line tool and select the ``ffmpeg`` backend in your config file. .. _ffmpeg: https://ffmpeg.org metaflac ~~~~~~~~ This backend uses the metaflac_ command-line tool (part of the FLAC tools) to compute ReplayGain values for FLAC files. It only supports FLAC; files in other formats are skipped. To use it, install the ``flac`` package, which provides ``metaflac``, and select the ``metaflac`` backend in your configuration file: .. code-block:: yaml replaygain: backend: metaflac metaflac scans every file of an album in a single pass, so the files of an album need to share the same sample rate and channel layout. .. _metaflac: https://xiph.org/flac/documentation_tools_metaflac.html Configuration ------------- To configure the plugin, make a ``replaygain:`` section in your configuration file. The available options are: - **auto**: Enable ReplayGain analysis during import. Default: ``yes``. - **threads**: The number of parallel threads to run the analysis in. Overridden by ``--threads`` at the command line. Default: # of logical CPU cores - **parallel_on_import**: Whether to enable parallel analysis during import. As of now this ReplayGain data is not written to files properly, so this option is disabled by default. If you wish to enable it, remember to run ``beet write`` after importing to actually write to the imported files. Default: ``no`` - **backend**: The analysis backend; either ``gstreamer``, ``command``, ``audiotools``, ``ffmpeg`` or ``metaflac``. Default: ``command``. - **overwrite**: On import, re-analyze files that already have ReplayGain tags. Note that, for historical reasons, the name of this option is somewhat unfortunate: It does not decide whether tags are written to the files (which is controlled by the :ref:`import.write ` option). Default: ``no``. - **targetlevel**: A number of decibels for the target loudness level for files using ``REPLAYGAIN_`` tags. Default: ``89``. - **r128_targetlevel**: The target loudness level in decibels (i.e. `` + 107``) for files using ``R128_`` tags. Default: 84 (Use ``83`` for ATSC A/85, ``84`` for EBU R128 or ``89`` for ReplayGain 2.0.) - **r128**: A space separated list of formats that will use ``R128_`` tags with integer values instead of the common ``REPLAYGAIN_`` tags with floating point values. Requires the "ffmpeg" backend. Default: ``Opus``. - **per_disc**: Calculate album ReplayGain on disc level instead of album level. Default: ``no`` These options only work with the "command" backend: - **command**: Name or path to your command backend of choice: either of ``mp3gain``, ``aacgain`` or ``mp3rgain``. - **noclip**: Reduce the amount of ReplayGain adjustment to whatever amount would keep clipping from occurring. Default: ``yes``. This option only works with the "ffmpeg" backend: - **peak**: Either ``true`` (the default) or ``sample``. ``true`` is more accurate but slower. This option only works with the "metaflac" backend: - **metaflac**: Name or path to the ``metaflac`` executable. Default: ``metaflac``. Manual Analysis --------------- By default, the plugin will analyze all items an albums as they are implemented. However, you can also manually analyze files that are already in your library. Use the ``beet replaygain`` command: :: $ beet replaygain [-Waf] [QUERY] The ``-a`` flag analyzes whole albums instead of individual tracks. Provide a query (see :doc:`/reference/query`) to indicate which items or albums to analyze. Files that already have ReplayGain values are skipped unless ``-f`` is supplied. Use ``-w`` (write tags) or ``-W`` (don't write tags) to control whether ReplayGain tags are written into the music files, or stored in the beets database only (the default is to use :ref:`the importer's configuration `). To execute with a different number of threads, call ``beet replaygain --threads N``: :: $ beet replaygain --threads N [-Waf] [QUERY] with N any integer. To disable parallelism, use ``--threads 0``. ReplayGain analysis is not fast, so you may want to disable it during import. Use the ``auto`` config option to control this: :: replaygain: auto: no beetbox-beets-00724b7/docs/plugins/fish.rst0000664000175000017500000000523215253035401020151 0ustar pieterpieterFish Plugin =========== The ``fish`` plugin adds a ``beet fish`` command that creates a `Fish shell`_ tab-completion file named ``beet.fish`` in ``~/.config/fish/completions``. This enables tab-completion of ``beet`` commands for the `Fish shell`_. .. _fish shell: https://fishshell.com/ Configuration ------------- Enable the ``fish`` plugin (see :ref:`using-plugins`) on a system running the `Fish shell`_. Usage ----- Type ``beet fish`` to generate the ``beet.fish`` completions file at: ``~/.config/fish/completions/``. If you later install or disable plugins, run ``beet fish`` again to update the completions based on the enabled plugins. For users not accustomed to tab completion… After you type ``beet`` followed by a space in your shell prompt and then the ``TAB`` key, you should see a list of the beets commands (and their abbreviated versions) that can be invoked in your current environment. Similarly, typing ``beet -`` will show you all the option flags available to you, which also applies to subcommands such as ``beet import -``. If you type ``beet ls`` followed by a space and then the and the ``TAB`` key, you will see a list of all the album/track fields that can be used in beets queries. For example, typing ``beet ls ge`` will complete to ``genres:`` and leave you ready to type the rest of your query. Options ------- In addition to beets commands, plugin commands, and option flags, the generated completions also include by default all the album/track fields. If you only want the former and do not want the album/track fields included in the generated completions, use ``beet fish -f`` to only generate completions for beets/plugin commands and option flags. If you want generated completions to also contain album/track field *values* for the items in your library, you can use the ``-e`` or ``--extravalues`` option. For example: ``beet fish -e genre`` or ``beet fish -e genre -e albumartist`` In the latter case, subsequently typing ``beet list genres: `` will display a list of all the genres in your library and ``beet list albumartist: `` will show a list of the album artists in your library. Keep in mind that all of these values will be put into the generated completions file, so use this option with care when specified fields contain a large number of values. Libraries with, for example, very large numbers of genres/artists may result in higher memory utilization, completion latency, et cetera. This option is not meant to replace database queries altogether. By default, the completion file will be generated at ``~/.config/fish/completions/``. If you want to save it somewhere else, you can use the ``-o`` or ``--output`` option. beetbox-beets-00724b7/docs/plugins/ipfs.rst0000664000175000017500000000566615253035401020174 0ustar pieterpieterIPFS Plugin =========== The ``ipfs`` plugin makes it easy to share your library and music with friends. The plugin uses ipfs_ for storing the library and file content. .. _ipfs: https://about.ipfs.io/ Installation ------------ This plugin requires go-ipfs_ to be running as a daemon and that the associated ``ipfs`` command is on the user's ``$PATH``. .. _go-ipfs: https://github.com/ipfs/kubo Once you have the client installed, enable the ``ipfs`` plugin in your configuration (see :ref:`using-plugins`). Usage ----- This plugin can store and retrieve music individually, or it can share entire library databases. Adding ~~~~~~ To add albums to ipfs, making them shareable, use the ``-a`` or ``--add`` flag. If used without arguments it will add all albums in the local library. When added, all items and albums will get an "ipfs" field in the database containing the hash of that specific file/folder. Newly imported albums will be added automatically to ipfs by default (see below). Retrieving ~~~~~~~~~~ You can give the ipfs hash for some music to a friend. They can get that album from ipfs, and import it into beets, using the ``-g`` or ``--get`` flag. If the argument passed to the ``-g`` flag isn't an ipfs hash, it will be used as a query instead, getting all albums matching the query. Sharing Libraries ~~~~~~~~~~~~~~~~~ Using the ``-p`` or ``--publish`` flag, a copy of the local library will be published to ipfs. Only albums/items with ipfs records in the database will published, and local paths will be stripped from the library. A hash of the library will be returned to the user. A friend can then import this remote library by using the ``-i`` or ``--import`` flag. To tag an imported library with a specific name by passing a name as the second argument to ``-i,`` after the hash. The content of all remote libraries will be combined into an additional library as long as the content doesn't already exist in the joined library. When remote libraries has been imported you can search them by using the ``-l`` or ``--list`` flag. The hash of albums matching the query will be returned, and this can then be used with ``-g`` to fetch and import the album to the local library. Ipfs can be mounted as a FUSE file system. This means that music in a remote library can be streamed directly, without importing them to the local library first. If the ``/ipfs`` folder is mounted then matching queries will be sent to the :doc:`/plugins/play` using the ``-m`` or ``--play`` flag. Configuration ------------- The ipfs plugin will automatically add imported albums to ipfs and add those hashes to the database. This can be turned off by setting the ``auto`` option in the ``ipfs:`` section of the config to ``no``. If the setting ``nocopy`` is true (defaults false) then the plugin will pass the ``--nocopy`` option when adding things to ipfs. If the filestore option of ipfs is enabled this will mean files are neither removed from beets nor copied somewhere else. beetbox-beets-00724b7/docs/plugins/play.rst0000664000175000017500000001147615253035401020174 0ustar pieterpieterPlay Plugin =========== The ``play`` plugin allows you to pass the results of a query to a music player in the form of an m3u playlist or paths on the command line. Command Line Usage ------------------ To use the ``play`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then use it by invoking the ``beet play`` command with a query. The command will create a temporary m3u file and open it using an appropriate application. You can query albums instead of tracks using the ``-a`` option. By default, the playlist is opened using the ``open`` command on OS X, ``xdg-open`` on other Unixes, and ``start`` on Windows. To configure the command, you can use a ``play:`` section in your configuration file: :: play: command: /Applications/VLC.app/Contents/MacOS/VLC You can also specify additional space-separated options to command (like you would on the command-line): :: play: command: /usr/bin/command --option1 --option2 some_other_option While playing you'll be able to interact with the player if it is a command-line oriented, and you'll get its output in real time. Interactive Usage ----------------- The ``play`` plugin can also be invoked during an import. If enabled, the plugin adds a ``plaY`` option to the prompt, so pressing ``y`` will execute the configured command and play the items currently being imported. Once the configured command exits, you will be returned to the import decision prompt. If your player is configured to run in the background (in a client/server setup), the music will play until you choose to stop it, and the import operation continues immediately. Configuration ------------- To configure the plugin, make a ``play:`` section in your configuration file. The available options are: - **command**: The command used to open the playlist. Default: ``open`` on OS X, ``xdg-open`` on other Unixes and ``start`` on Windows. Insert ``$args`` to use the ``--args`` feature. - **relative_to**: If set, emit paths relative to this directory. Default: None. - **use_folders**: When using the ``-a`` option, the m3u will contain the paths to each track on the matched albums. Enable this option to store paths to folders instead. Default: ``no``. - **raw**: Instead of creating a temporary m3u playlist and then opening it, simply call the command with the paths returned by the query as arguments. Default: ``no``. - **warning_threshold**: Set the minimum number of files to play which will trigger a warning to be emitted. If set to ``no``, warning are never issued. Default: 100. - **bom**: Set whether or not a UTF-8 Byte Order Mark should be emitted into the m3u file. If you're using foobar2000 or Winamp, this is needed. Default: ``no``. Optional Arguments ------------------ The ``--args`` (or ``-A``) flag to the ``play`` command lets you specify additional arguments for your player command. Options are inserted after the configured ``command`` string and before the playlist filename. For example, if you have the plugin configured like this: :: play: command: mplayer -quiet and you occasionally want to shuffle the songs you play, you can type: :: $ beet play --args -shuffle to get beets to execute this command: :: mplayer -quiet -shuffle /path/to/playlist.m3u instead of the default. If you need to insert arguments somewhere other than the end of the ``command`` string, use ``$args`` to indicate where to insert them. For example: :: play: command: mpv $args --playlist indicates that you need to insert extra arguments before specifying the playlist. Some players require a different syntax. For example, with ``mpv`` the optional ``$playlist`` variable can be used to match the syntax of the ``--playlist`` option: :: play: command: mpv $args --playlist=$playlist The ``--yes`` (or ``-y``) flag to the ``play`` command will skip the warning message if you choose to play more items than the **warning_threshold** value usually allows. The ``--randomize`` (or ``-R``) flag shuffles the order of playlist entries before passing it to the player: :: $ beet play --randomize my query Note on the Leakage of the Generated Playlists ---------------------------------------------- Because the command that will open the generated ``.m3u`` files can be arbitrarily configured by the user, beets won't try to delete those files. For this reason, using this plugin will leave one or several playlist(s) in the directory selected to create temporary files (Most likely ``/tmp/`` on Unix-like systems. See tempfile.tempdir_ in the Python docs.). Leaking those playlists until they are externally wiped could be an issue for privacy or storage reasons. If this is the case for you, you might want to use the ``raw`` config option described above. .. _tempfile.tempdir: https://docs.python.org/3/library/tempfile.html#tempfile.tempdir beetbox-beets-00724b7/docs/plugins/subsonicupdate.rst0000664000175000017500000000333015253035401022245 0ustar pieterpieterSubsonicUpdate Plugin ===================== ``subsonicupdate`` is a very simple plugin for beets that lets you automatically update Subsonic_'s index whenever you change your beets library. .. _subsonic: https://www.subsonic.org/pages/index.jsp To use ``subsonicupdate`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then, you'll probably want to configure the specifics of your Subsonic server. You can do that using a ``subsonic:`` section in your ``config.yaml``, which looks like this: :: subsonic: url: https://example.com:443/subsonic user: username pass: password auth: token With that all in place, this plugin will send a REST API call to your Subsonic server every time you change your beets library. Due to a current limitation of the API, all libraries visible to that user will be scanned. If the :doc:`/plugins/smartplaylist` is used, creating or changing any playlist will trigger a Subsonic update as well. This plugin requires Subsonic with an active Premium license (or active trial) or any other `Subsonic API compatible`_ server implementing the ``startScan`` endpoint. .. _subsonic api compatible: https://www.subsonic.org/pages/api.jsp Configuration ------------- The available options under the ``subsonic:`` section are: - **url**: The Subsonic server resource. Default: ``http://localhost:4040`` - **user**: The Subsonic user. Default: ``admin`` - **pass**: The Subsonic user password. (This may either be a clear-text password or hex-encoded with the prefix ``enc:``.) Default: ``admin`` - **auth**: The authentication method. Possible choices are ``token`` or ``password``. ``token`` authentication is preferred to avoid sending cleartext password. beetbox-beets-00724b7/docs/plugins/keyfinder.rst0000664000175000017500000000246415253035401021204 0ustar pieterpieterKey Finder Plugin ================= The ``keyfinder`` plugin uses either the KeyFinder_ or keyfinder-cli_ program to detect the musical key of a track from its audio data and store it in the ``initial_key`` field of your database. It does so automatically when importing music or through the ``beet keyfinder [QUERY]`` command. To use the ``keyfinder`` plugin, enable it in your configuration (see :ref:`using-plugins`). Configuration ------------- To configure the plugin, make a ``keyfinder:`` section in your configuration file. The available options are: - **auto**: Analyze every file on import. Otherwise, you need to use the ``beet keyfinder`` command explicitly. Default: ``yes`` - **bin**: The name of the program use for key analysis. You can use either KeyFinder_ or keyfinder-cli_. If you installed the KeyFinder GUI on a Mac, for example, you want something like ``/Applications/KeyFinder.app/Contents/MacOS/KeyFinder``. If using keyfinder-cli_, the binary must be named ``keyfinder-cli``. Default: ``KeyFinder`` (i.e., search for the program in your ``$PATH``).. - **overwrite**: Calculate a key even for files that already have an ``initial_key`` value. Default: ``no``. .. _keyfinder: https://www.ibrahimshaath.co.uk/keyfinder/ .. _keyfinder-cli: https://github.com/EvanPurkhiser/keyfinder-cli/ beetbox-beets-00724b7/docs/plugins/duplicates.rst0000664000175000017500000001560015253035401021355 0ustar pieterpieterDuplicates Plugin ================= This plugin adds a new command, ``duplicates`` or ``dup``, which finds and lists duplicate tracks or albums in your collection. Usage ----- To use the ``duplicates`` plugin, first enable it in your configuration (see :ref:`using-plugins`). By default, the ``beet duplicates`` command lists the names of tracks in your library that are duplicates. It assumes that Musicbrainz track and album ids are unique to each track or album. That is, it lists every track or album with an ID that has been seen before in the library. You can customize the output format, count the number of duplicate tracks or albums, and list all tracks that have duplicates or just the duplicates themselves via command-line switches :: -h, --help show this help message and exit -f FMT, --format=FMT print with custom format -a, --album show duplicate albums instead of tracks -c, --count count duplicate tracks or albums -C PROG, --checksum=PROG report duplicates based on arbitrary command -d, --delete delete items from library and disk -F, --full show all versions of duplicate tracks or albums -s, --strict report duplicates only if all attributes are set -k, --key report duplicates based on keys (can be used multiple times) -M, --merge merge duplicate items -m DEST, --move=DEST move items to dest -o DEST, --copy=DEST copy items to dest -p, --path print paths for matched items or albums -t TAG, --tag=TAG tag matched items with 'k=v' attribute -r, --remove remove items from library Configuration ------------- To configure the plugin, make a ``duplicates:`` section in your configuration file. The available options mirror the command-line options: - **album**: List duplicate albums instead of tracks. Default: ``no``. - **checksum**: Use an arbitrary command to compute a checksum of items. This overrides the ``keys`` option the first time it is run; however, because it caches the resulting checksum as ``flexattrs`` in the database, you can use ``--key=name_of_the_checksumming_program --key=any_other_keys`` (or set the ``keys`` configuration option) the second time around. The command is not run through a shell: it is split into arguments (respecting shell-like quoting) and ``{file}`` is then replaced with the item's path within each argument, so paths containing spaces need no extra quoting. **Note: shell features such as pipes or redirection cannot be used.** The command's entire output is used as the checksum, so it must not contain anything that differs between copies of the same file, such as the file's path. Default: ``ffmpeg -i {file} -f crc -``. - **copy**: A destination base directory into which to copy matched items. Default: none (disabled). - **count**: Print a count of duplicate tracks or albums in the format ``$albumartist - $album - $title: $count`` (for tracks) or ``$albumartist - $album: $count`` (for albums). Default: ``no``. - **delete**: Remove matched items from the library and from the disk. Default: ``no`` - **format**: A specific format with which to print every track or album. This uses the same template syntax as beets' :doc:`path formats `. The usage is inspired by, and therefore similar to, the :ref:`list ` command. Default: :ref:`format_item` - **full**: List every track or album that has duplicates, not just the duplicates themselves. Default: ``no`` - **keys**: Define in which track or album fields duplicates are to be searched. By default, the plugin uses the musicbrainz track and album IDs for this purpose. Using the ``keys`` option (as a YAML list in the configuration file, or as space-delimited strings in the command-line), you can extend this behavior to consider other attributes. Default: ``[mb_trackid, mb_albumid]`` - **merge**: Merge duplicate items by consolidating tracks and-or metadata where possible. - **move**: A destination base directory into which it will move matched items. Default: none (disabled). - **path**: Output the path instead of metadata when listing duplicates. Default: ``no``. - **strict**: Do not report duplicate matches if some of the attributes are not defined (ie. null or empty). Default: ``no`` - **tag**: A ``key=value`` pair. The plugin will add a new ``key`` attribute with ``value`` value as a flexattr to the database for duplicate items. Default: ``no``. - **tiebreak**: Dictionary of lists of attributes keyed by ``items`` or ``albums`` to use when choosing duplicates. By default, the tie-breaking procedure favors the most complete metadata attribute set. If you would like to consider the lower bitrates as duplicates, for example, set ``tiebreak: items: [bitrate]``. Default: ``{}``. - **remove**: Remove matched items from the library, but not from the disk. Default: ``no``. Examples -------- List all duplicate tracks in your collection: :: beet duplicates List all duplicate tracks from 2008: :: beet duplicates year:2008 Print out a unicode histogram of duplicate track years using spark_: :: beet duplicates -f '$year' | spark â–†â–�▆█▄▇▇▄▇▇â–�█▇▆▇▂▄█â–�██▂█â–�â–�██â–�█▂▇▆▂▇█▇▇█▆▆▇█▇█▇▆██▂▇ Print out a listing of all albums with duplicate tracks, and respective counts: :: beet duplicates -ac The same as the above but include the original album, and show the path: :: beet duplicates -acf '$path' Get tracks with the same title, artist, and album: :: beet duplicates -k title -k albumartist -k album Compute Adler CRC32 checksums, storing them as flexattrs, and report back duplicates based on those values: .. code-block:: bash beet dup -C 'ffmpeg -i {file} -f crc -' Note that ``beet dup -C 'md5sum {file}'`` would not work: the command's entire output is used as the checksum, and ``md5sum`` prints the file's path after the hash, so copies of the same file at different paths would never match. Instead, wrap the command in a script that prints only the hash: .. code-block:: bash #!/bin/sh md5sum "$1" | awk '{print $1}' and use that script as the checksum command: .. code-block:: bash beet dup -C 'myscript {file}' Copy highly danceable items to ``party`` directory: :: beet dup --copy /tmp/party Move likely duplicates to ``trash`` directory: :: beet dup --move ${HOME}/.Trash Delete items (careful!), if they're Nickelback: :: beet duplicates --delete -k albumartist -k albumartist:nickelback Tag duplicate items with some flag: :: beet duplicates --tag dup=1 Ignore items with undefined keys: :: beet duplicates --strict Merge and delete duplicate albums with different missing tracks: :: beet duplicates --album --merge --delete .. _spark: https://github.com/holman/spark beetbox-beets-00724b7/docs/plugins/missing.rst0000664000175000017500000000744115253035401020675 0ustar pieterpieterMissing Plugin ============== This plugin adds a new command, ``missing`` or ``miss``, which finds and lists missing tracks for albums in your collection. Each album requires one network call to album data source. Usage ----- The ``beet missing`` command fetches album information from the origin data source and lists names of the **tracks** that are missing from your library. Track-level checks use the album's stored ``data_source`` and fall back to ``MusicBrainz`` when no source is stored. It can also list the names of missing **albums** for each artist, although this is limited to albums from the MusicBrainz data source only. You can customize the output format, show missing counts instead of track titles, or display the total number of missing entities across your entire library: :: -f FORMAT, --format=FORMAT print with custom FORMAT -c, --count count missing tracks per album -t, --total count totals across the entire library -a, --album show missing albums for artist instead of tracks for album --release-type show only missing albums of specified release type. You can provide this argument multiple times to specify multiple release types to filter to. If not provided, defaults to just the "album" release type. provided, it uses the configured ``missing.release_type`` (default: "album"). …or by editing the corresponding configuration options. .. warning:: Option ``-c`` is ignored when used with ``-a``, and ``--release-type`` is ignored when not used with ``-a``. Valid release types can be shown by running ``beet missing -h``. Configuration ------------- To configure the plugin, make a ``missing:`` section in your configuration file. The available options are: - **count**: Print a count of missing tracks per album, with the global ``format_album`` used for formatting. Default: ``no``. - **total**: Print a single count of missing tracks in all albums. Default: ``no``. Formatting ~~~~~~~~~~ - This plugin uses global formatting options from the main configuration; see :ref:`format_item` and :ref:`format_album`: - :ref:`format_item`: Used when listing missing tracks (default item format). - :ref:`format_album`: Used when showing counts (``-c``) or missing albums (``-a``). Here's an example :: format_album: $albumartist - $album format_item: $artist - $album - $title missing: count: no total: no Template Fields --------------- With this plugin enabled, the ``$missing`` template field expands to the number of tracks missing from each album. Examples -------- List all missing tracks in your collection: :: beet missing List all missing albums in your collection: :: beet missing -a List all missing tracks from 2008: :: beet missing year:2008 Print out a unicode histogram of the missing track years using spark_: :: beet missing -f '$year' | spark â–†â–�▆█▄▇▇▄▇▇â–�█▇▆▇▂▄█â–�██▂█â–�â–�██â–�█▂▇▆▂▇█▇▇█▆▆▇█▇█▇▆██▂▇ Print out a listing of all albums with missing tracks, and respective counts: :: beet missing -c Print out a count of the total number of missing tracks: :: beet missing -t List all missing albums of release type "compilation" in your collection: :: beet missing -a --release-type compilation List all missing albums of release type "compilation" and album in your collection: :: beet missing -a --release-type compilation --release-type album Call this plugin from other beet commands: :: beet ls -a -f '$albumartist - $album: $missing' .. _spark: https://github.com/holman/spark beetbox-beets-00724b7/docs/plugins/beatport.rst0000664000175000017500000000340515253035401021040 0ustar pieterpieterBeatport Plugin =============== .. deprecated:: 2.8 Beatport retired the API this plugin relies on. See :bug:`3862` and :bug:`4477`. The ``beatport`` plugin adds support for querying the Beatport_ catalogue during the autotagging process. This can potentially be helpful for users whose collection includes a lot of diverse electronic music releases, for which both MusicBrainz and (to a lesser degree) Discogs_ show no matches. .. _discogs: https://discogs.com Installation ------------ To use the ``beatport`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``beatport`` extra .. code-block:: bash pip install "beets[beatport]" You will also need to register for a Beatport_ account. The first time you run the :ref:`import-cmd` command after enabling the plugin, it will ask you to authorize with Beatport by visiting the site in a browser. On the site you will be asked to enter your username and password to authorize beets to query the Beatport API. You will then be displayed with a single line of text that you should paste as a whole into your terminal. This will store the authentication data for subsequent runs and you will not be required to repeat the above steps. Matches from Beatport should now show up alongside matches from MusicBrainz and other sources. If you have a Beatport ID or a URL for a release or track you want to tag, you can just enter one of the two at the "enter Id" prompt in the importer. You can also search for an id like so: :: beet import path/to/music/library --search-id id Configuration ------------- This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`. .. _beatport: https://www.beatport.com/ beetbox-beets-00724b7/docs/plugins/importfeeds.rst0000664000175000017500000000357415253035401021550 0ustar pieterpieterImportFeeds Plugin ================== This plugin helps you keep track of newly imported music in your library. To use the ``importfeeds`` plugin, enable it in your configuration (see :ref:`using-plugins`). Configuration ------------- To configure the plugin, make an ``importfeeds:`` section in your configuration file. The available options are: - **absolute_path**: Use absolute paths instead of relative paths. Some applications may need this to work properly. Default: ``no``. - **dir**: The output directory. Default: Your beets library directory. - **formats**: Select the kind of output. Use one or more of: - **m3u**: Catalog the imports in a centralized playlist. - **m3u_multi**: Create a new playlist for each import (uniquely named by appending the date and track/album name). - **m3u_session**: Create a new playlist for each import session. The file is named as ``m3u_name`` appending the date and time the import session was started. - **link**: Create a symlink for each imported item. This is the recommended setting to propagate beets imports to your iTunes library: just drag and drop the ``dir`` folder on the iTunes dock icon. - **echo**: Do not write a playlist file at all, but echo a list of new file paths to the terminal. Default: None. - **m3u_name**: Playlist name used by the ``m3u`` format and as a prefix used by the ``m3u_session`` format. Default: ``imported.m3u``. - **relative_to**: Make the m3u paths relative to another folder than where the playlist is being written. If you're using importfeeds to generate a playlist for MPD, you should set this to the root of your music library. Default: None. Here's an example configuration for this plugin: :: importfeeds: formats: m3u link dir: ~/imports/ relative_to: ~/Music/ m3u_name: newfiles.m3u beetbox-beets-00724b7/docs/plugins/replace.rst0000664000175000017500000000107715253035401020636 0ustar pieterpieterReplace Plugin ============== The ``replace`` plugin provides a command that replaces the audio file of a track, while keeping the name and tags intact. It should save some time when you get the wrong version of a song. Enable the ``replace`` plugin in your configuration (see :ref:`using-plugins`) and then type: :: $ beet replace The plugin will show you a list of files for you to pick from, and then ask for confirmation. Consider using the ``replaygain`` command from the :doc:`/plugins/replaygain` plugin, if you usually use it during imports. beetbox-beets-00724b7/docs/plugins/kodiupdate.rst0000664000175000017500000000301015253035401021341 0ustar pieterpieterKodiUpdate Plugin ================= The ``kodiupdate`` plugin lets you automatically update Kodi_'s music library whenever you change your beets library. To use ``kodiupdate`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then, you'll want to configure the specifics of your Kodi host. You can do that using a ``kodi:`` section in your ``config.yaml``, which looks like this: :: kodi: host: localhost port: 8080 user: kodi pwd: kodi To update multiple Kodi instances, specify them as an array: :: kodi: - host: x.x.x.x port: 8080 user: kodi pwd: kodi - host: y.y.y.y port: 8081 user: kodi2 pwd: kodi2 To use the ``kodiupdate`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``kodiupdate`` extra .. code-block:: bash pip install "beets[kodiupdate]" You'll also need to enable JSON-RPC in Kodi. In Kodi's interface, navigate to System/Settings/Network/Services and choose "Allow control of Kodi via HTTP." With that all in place, you'll see beets send the "update" command to your Kodi host every time you change your beets library. .. _kodi: https://kodi.tv/ Configuration ------------- The available options under the ``kodi:`` section are: - **host**: The Kodi host name. Default: ``localhost`` - **port**: The Kodi host port. Default: 8080 - **user**: The Kodi host user. Default: ``kodi`` - **pwd**: The Kodi host password. Default: ``kodi`` beetbox-beets-00724b7/docs/plugins/info.rst0000664000175000017500000000321615253035401020153 0ustar pieterpieterInfo Plugin =========== The ``info`` plugin provides a command that dumps the current tag values for any file format supported by beets. It works like a supercharged version of mp3info_ or id3v2_. Enable the ``info`` plugin in your configuration (see :ref:`using-plugins`) and then type: :: $ beet info /path/to/music.flac and the plugin will enumerate all the tags in the specified file. It also accepts multiple filenames in a single command-line. You can also enter a :doc:`query ` to inspect music from your library: :: $ beet info beatles If you just want to see specific properties you can use the ``--include-keys`` option to filter them. The argument is a comma-separated list of field names. For example: :: $ beet info -i 'title,mb_artistid' beatles Will only show the ``title`` and ``mb_artistid`` properties. You can add the ``-i`` option multiple times to the command line. Additional command-line options include: - ``--library`` or ``-l``: Show data from the library database instead of the files' tags. - ``--album`` or ``-a``: Show data from albums instead of tracks (implies ``--library``). - ``--summarize`` or ``-s``: Merge all the information from multiple files into a single list of values. If the tags differ across the files, print ``[various]``. - ``--format`` or ``-f``: Specify a specific format with which to print every item. This uses the same template syntax as beets’ :doc:`path formats `. - ``--keys-only`` or ``-k``: Show the name of the tags without the values. .. _id3v2: https://sourceforge.net/projects/id3v2/ .. _mp3info: https://www.ibiblio.org/mp3info/ beetbox-beets-00724b7/docs/plugins/permissions.rst0000664000175000017500000000121015253035401021563 0ustar pieterpieterPermissions Plugin ================== The ``permissions`` plugin allows you to set file permissions for imported music files and its directories. To use the ``permissions`` plugin, enable it in your configuration (see :ref:`using-plugins`). Permissions will be adjusted automatically on import. Configuration ------------- To configure the plugin, make an ``permissions:`` section in your configuration file. The ``file`` config value therein uses **octal modes** to specify the desired permissions. The default flags for files are octal 644 and 755 for directories. Here's an example: :: permissions: file: 644 dir: 755 beetbox-beets-00724b7/docs/plugins/bpm.rst0000664000175000017500000000217615253035401020002 0ustar pieterpieterBPM Plugin ========== This ``bpm`` plugin lets you to get the tempo (beats per minute) of a song by tapping out the beat on your keyboard. Usage ----- To use the ``bpm`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, play a song you want to measure in your favorite media player and type: :: beet bpm You'll be prompted to press Enter three times to the rhythm. This typically allows to determine the BPM within 5% accuracy. The plugin works best if you wrap it in a script that gets the playing song. for instance, with ``mpc`` you can do something like: :: beet bpm $(mpc |head -1|tr -d "-") If :ref:`import.write ` is ``yes``, the song's tags are written to disk. Configuration ------------- To configure the plugin, make a ``bpm:`` section in your configuration file. The available options are: - **max_strokes**: The maximum number of strokes to accept when tapping out the BPM. Default: 3. - **overwrite**: Overwrite the track's existing BPM. Default: ``yes``. Credit ------ This plugin is inspired by a similar feature present in the Banshee media player. beetbox-beets-00724b7/docs/plugins/bpd.rst0000664000175000017500000001230015253035401017757 0ustar pieterpieterBPD Plugin ========== BPD is a music player using music from a beets library. It runs as a daemon and implements the MPD protocol, so it's compatible with all the great MPD clients out there. I'm using Theremin_, gmpc_, Sonata_, and Ario_ successfully. .. _ario: https://sourceforge.net/projects/ario-player/ .. _gmpc: https://gmpc.fandom.com/wiki/Gnome_Music_Player_Client .. _sonata: https://www.nongnu.org/sonata/ .. _theremin: https://github.com/TheStalwart/Theremin Dependencies ------------ Before you can use BPD, you'll need the media library called GStreamer_ (along with its Python bindings) on your system. - On Mac OS X, you can use Homebrew_. Run ``brew install gstreamer gst-plugins-base pygobject3``. - On Linux, you need to install GStreamer 1.0 and the GObject bindings for python. Under Ubuntu, they are called ``python-gi`` and ``gstreamer1.0``. You will also need the various GStreamer plugin packages to make everything work. See the :doc:`/plugins/chroma` documentation for more information on installing GStreamer plugins. Once you have system dependencies installed, install ``beets`` with ``bpd`` extra which installs Python bindings for ``GStreamer``: .. code-block:: console pip install "beets[bpd]" .. _gstreamer: https://gstreamer.freedesktop.org/ .. _homebrew: https://brew.sh Usage ----- To use the ``bpd`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, you can run BPD by invoking: :: $ beet bpd Fire up your favorite MPD client to start playing music. The MPD site has `a long list of available clients`_. Here are my favorites: .. _a long list of available clients: https://mpd.fandom.com/wiki/Clients - Linux: gmpc_, Sonata_ - Mac: Theremin_ - Windows: I don't know. Get in touch if you have a recommendation. - iPhone/iPod touch: Rigelian_ .. _rigelian: https://www.rigelian.net/ One nice thing about MPD's (and thus BPD's) client-server architecture is that the client can just as easily on a different computer from the server as it can be run locally. Control your music from your laptop (or phone!) while it plays on your headless server box. Rad! Configuration ------------- To configure the plugin, make a ``bpd:`` section in your configuration file. The available options are: - **host**: Default: Bind to all interfaces. - **port**: Default: 6600 - **password**: Default: No password. - **volume**: Initial volume, as a percentage. Default: 100 - **control_port**: Port for the internal control socket. Default: 6601 Here's an example: :: bpd: host: 127.0.0.1 port: 6600 password: seekrit volume: 100 Implementation Notes -------------------- In the real MPD, the user can browse a music directory as it appears on disk. In beets, we like to abstract away from the directory structure. Therefore, BPD creates a "virtual" directory structure (artist/album/track) to present to clients. This is static for now and cannot be reconfigured like the real on-disk directory structure can. (Note that an obvious solution to this is just string matching on items' destination, but this requires examining the entire library Python-side for every query.) BPD plays music using GStreamer's ``playbin`` player, which has a simple API but doesn't support many advanced playback features. Differences from the real MPD ----------------------------- BPD currently supports version 0.16 of `the MPD protocol`_, but several of the commands and features are "pretend" implementations or have slightly different behaviour to their MPD equivalents. BPD aims to look enough like MPD that it can interact with the ecosystem of clients, but doesn't try to be a fully-fledged MPD replacement in terms of its playback capabilities. .. _the mpd protocol: https://mpd.readthedocs.io/en/latest/protocol.html These are some of the known differences between BPD and MPD: - BPD doesn't currently support versioned playlists. Many clients, however, use plchanges instead of playlistinfo to get the current playlist, so plchanges contains a dummy implementation that just calls playlistinfo. - Stored playlists aren't supported (BPD understands the commands though). - The ``stats`` command always send zero for ``playtime``, which is supposed to indicate the amount of time the server has spent playing music. BPD doesn't currently keep track of this. - The ``update`` command regenerates the directory tree from the beets database synchronously, whereas MPD does this in the background. - Advanced playback features like cross-fade, ReplayGain and MixRamp are not supported due to BPD's simple audio player backend. - Advanced query syntax is not currently supported. - Clients can't use the ``tagtypes`` mask to hide fields. - BPD's ``random`` mode is not deterministic and doesn't support priorities. - Mounts and streams are not supported. BPD can only play files from disk. - Stickers are not supported (although this is basically a flexattr in beets nomenclature so this is feasible to add). - There is only a single password, and is enabled it grants access to all features rather than having permissions-based granularity. - Partitions and alternative outputs are not supported; BPD can only play one song at a time. - Client channels are not implemented. beetbox-beets-00724b7/docs/plugins/ftintitle.rst0000664000175000017500000000545415253035401021230 0ustar pieterpieterFtInTitle Plugin ================ The ``ftintitle`` plugin automatically moves "featured" artists from the ``artist`` field to the ``title`` field. According to `MusicBrainz style`_, featured artists are part of the artist field. That means that, if you tag your music using MusicBrainz, you'll have tracks in your library like "Tellin' Me Things" by the artist "Blakroc feat. RZA". If you prefer to tag this as "Tellin' Me Things feat. RZA" by "Blakroc", then this plugin is for you. To use the ``ftintitle`` plugin, enable it in your configuration (see :ref:`using-plugins`). Configuration ------------- To configure the plugin, make a ``ftintitle:`` section in your configuration file. The available options are: - **auto**: Enable metadata rewriting during import and when fetched metadata is later applied by commands such as ``mbsync``. Default: ``yes``. - **drop**: Remove featured artists entirely instead of adding them to the title field. Default: ``no``. - **format**: Defines the format for the featuring X part of the new title field. In this format the ``{0}`` is used to define where the featured artists are placed. Default: ``feat. {0}`` - **keep_in_artist**: Keep the featuring X part in the artist field. This can be useful if you still want to be able to search for features in the artist field. Default: ``no``. - **preserve_album_artist**: If the artist and the album artist are the same, skip the ftintitle processing. Default: ``yes``. - **custom_words**: List of additional words that will be treated as a marker for artist features. Default: ``[]``. - **bracket_keywords**: Controls where the featuring text is inserted when the title includes bracketed qualifiers such as ``(Remix)`` or ``[Live]``. FtInTitle inserts the new text before the first bracket whose contents match any of these keywords. Supply a list of words to fine-tune the behavior or set the list to ``[]`` to match *any* bracket regardless of its contents. Default: :: ["abridged", "acapella", "club", "demo", "edit", "edition", "extended", "instrumental", "live", "mix", "radio", "release", "remaster", "remastered", "remix", "rmx", "unabridged", "unreleased", "version", "vip"] Path Template Values -------------------- This plugin provides the ``album_artist_no_feat`` :ref:`template value ` that you can use in your :ref:`path-format-config` in ``paths.default``. Any ``custom_words`` in the configuration are taken into account. Running Manually ---------------- From the command line, type: :: $ beet ftintitle [QUERY] The query is optional; if it's left off, the transformation will be applied to your entire collection. Use the ``-d`` flag to remove featured artists (equivalent of the ``drop`` config option). .. _musicbrainz style: https://musicbrainz.org/doc/Style beetbox-beets-00724b7/docs/plugins/limit.rst0000664000175000017500000000341315253035401020335 0ustar pieterpieterLimit Query Plugin ================== .. deprecated:: 2.14 Use the built-in ``-l`` / ``--limit`` flag on the :ref:`list-cmd` command instead. ``limit`` is a plugin to limit a query to the first or last set of results. We also provide a query prefix ``'`. On the command line, use ``beet web [HOSTNAME] [PORT]``. Or the configuration options below. Usage ----- Type queries into the little search box. Double-click a track to play it with HTML5 Audio. Configuration ------------- To configure the plugin, make a ``web:`` section in your configuration file. The available options are: - **host**: The server hostname. Set this to 0.0.0.0 to bind to all interfaces. Default: Bind to 127.0.0.1. - **port**: The server port. Default: 8337. - **cors**: The CORS allowed origin (see :ref:`web-cors`, below). Default: CORS is disabled. - **cors_supports_credentials**: Support credentials when using CORS (see :ref:`web-cors`, below). Default: CORS_SUPPORTS_CREDENTIALS is disabled. - **reverse_proxy**: If true, enable reverse proxy support (see :ref:`reverse-proxy`, below). Default: false. - **include_paths**: If true, includes paths in item objects. Default: false. - **readonly**: If true, DELETE and PATCH operations are not allowed. Only GET is permitted. Default: true. Implementation -------------- The Web backend is built using a simple REST+JSON API with the excellent Flask_ library. The frontend is a single-page application written with Backbone.js_. This allows future non-Web clients to use the same backend API. .. _backbone.js: https://backbonejs.org Eventually, to make the Web player really viable, we should use a Flash fallback for unsupported formats/browsers. There are a number of options for this: - audio.js_ - html5media_ - MediaElement.js_ .. _audio.js: https://kolber.github.io/audiojs/ .. _html5media: https://html5media.info/ .. _mediaelement.js: https://www.mediaelementjs.com/ .. _web-cors: Cross-Origin Resource Sharing (CORS) ------------------------------------ The ``web`` plugin's API can be used as a backend for an in-browser client. By default, browsers will only allow access from clients running on the same server as the API. (You will get an arcane error about ``XMLHttpRequest`` otherwise.) A technology called CORS_ lets you relax this restriction. If you want to use an in-browser client hosted elsewhere (or running from a different server on your machine), set the ``cors`` configuration option to the "origin" (protocol, host, and optional port number) where the client is served. Or set it to ``'*'`` to enable access from all origins. Note that there are security implications if you set the origin to ``'*'``, so please research this before using it. If the ``web`` server is behind a proxy that uses credentials, you might want to set the ``cors_supports_credentials`` configuration option to true to let in-browser clients log in. For example: :: web: host: 0.0.0.0 cors: 'http://example.com' .. _cors: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing .. _reverse-proxy: Reverse Proxy Support --------------------- When the server is running behind a reverse proxy, you can tell the plugin to respect forwarded headers. Specifically, this can help when you host the plugin at a base URL other than the root ``/`` or when you use the proxy to handle secure connections. Enable the ``reverse_proxy`` configuration option if you do this. Technically, this option lets the proxy provide ``X-Script-Name`` and ``X-Scheme`` HTTP headers to control the plugin's the ``SCRIPT_NAME`` and its ``wsgi.url_scheme`` parameter. Here's a sample Nginx_ configuration that serves the web plugin under the /beets directory: :: location /beets { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Scheme $scheme; proxy_set_header X-Script-Name /beets; } .. _nginx: https://www.f5.com/products/nginx JSON API -------- ``GET /item/`` ~~~~~~~~~~~~~~ Responds with a list of all tracks in the beets library. :: { "items": [ { "id": 6, "title": "A Song", ... }, { "id": 12, "title": "Another Song", ... } ... ] } ``GET /item/6`` ~~~~~~~~~~~~~~~ Looks for an item with id *6* in the beets library and responds with its JSON representation. :: { "id": 6, "title": "A Song", ... } If there is no item with that id responds with a *404* status code. ``DELETE /item/6`` ~~~~~~~~~~~~~~~~~~ Removes the item with id *6* from the beets library. If the *?delete* query string is included, the matching file will be deleted from disk. Only allowed if ``readonly`` configuration option is set to ``no``. ``PATCH /item/6`` ~~~~~~~~~~~~~~~~~ Updates the item with id *6* and write the changes to the music file. The body should be a JSON object containing the changes to the object. Returns the updated JSON representation. :: { "id": 6, "title": "A Song", ... } Only allowed if ``readonly`` configuration option is set to ``no``. ``GET /item/6,12,13`` ~~~~~~~~~~~~~~~~~~~~~ Response with a list of tracks with the ids *6*, *12* and *13*. The format of the response is the same as for `GET /item/`_. It is *not guaranteed* that the response includes all the items requested. If a track is not found it is silently dropped from the response. This endpoint also supports *DELETE* and *PATCH* methods as above, to operate on all items of the list. ``GET /item/path/...`` ~~~~~~~~~~~~~~~~~~~~~~ Look for an item at the given absolute path on the server. If it corresponds to a track, return the track in the same format as ``/item/*``. If the server runs UNIX, you'll need to include an extra leading slash: ``http://localhost:8337/item/path//Users/beets/Music/Foo/Bar/Baz.mp3`` ``GET /item/query/querystring`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Returns a list of tracks matching the query. The *querystring* must be a valid query as described in :doc:`/reference/query`. :: { "results": [ { "id" : 6, "title": "A Song" }, { "id" : 12, "title": "Another Song" } ] } Path elements are joined as parts of a query. For example, ``/item/query/foo/bar`` will be converted to the query ``foo,bar``. To specify literal path separators in a query, use a backslash instead of a slash. This endpoint also supports *DELETE* and *PATCH* methods as above, to operate on all items returned by the query. ``GET /item/6/file`` ~~~~~~~~~~~~~~~~~~~~ Sends the media file for the track. If the item or its corresponding file do not exist a *404* status code is returned. Albums ~~~~~~ For albums, the following endpoints are provided: - ``GET /album/`` - ``GET /album/5`` - ``GET /album/5/art`` - ``DELETE /album/5`` - ``GET /album/5,7`` - ``DELETE /album/5,7`` - ``GET /album/query/querystring`` - ``DELETE /album/query/querystring`` The interface and response format is similar to the item API, except replacing the encapsulation key ``"items"`` with ``"albums"`` when requesting ``/album/`` or ``/album/5,7``. In addition we can request the cover art of an album with ``GET /album/5/art``. You can also add the '?expand' flag to get the individual items of an album. ``DELETE`` is only allowed if ``readonly`` configuration option is set to ``no``. ``GET /stats`` ~~~~~~~~~~~~~~ Responds with the number of tracks and albums in the database. :: { "items": 5, "albums": 3 } .. _flask: https://flask.palletsprojects.com/en/stable/ beetbox-beets-00724b7/docs/plugins/bpsync.rst0000664000175000017500000000300515253035401020512 0ustar pieterpieterBPSync Plugin ============= .. deprecated:: 2.8 Depends on the deprecated :doc:`beatport` plugin. See :bug:`3862` and :bug:`4477`. This plugin provides the ``bpsync`` command, which lets you fetch metadata from Beatport for albums and tracks that already have Beatport IDs. This plugin works similarly to :doc:`/plugins/mbsync`. If you have downloaded music from Beatport, this can speed up the initial import if you just import "as-is" and then use ``bpsync`` to get up-to-date tags that are written to the files according to your beets configuration. Usage ----- Enable the ``bpsync`` plugin in your configuration (see :ref:`using-plugins`) and then run ``beet bpsync QUERY`` to fetch updated metadata for a part of your collection (or omit the query to run over your whole library). This plugin treats albums and singletons (non-album tracks) separately. It first processes all matching singletons and then proceeds on to full albums. The same query is used to search for both kinds of entities. The command has a few command-line options: - To preview the changes that would be made without applying them, use the ``-p`` (``--pretend``) flag. - By default, files will be moved (renamed) according to their metadata if they are inside your beets library directory. To disable this, use the ``-M`` (``--nomove``) command-line option. - If you have the ``import.write`` configuration option enabled, then this plugin will write new metadata to files' tags. To disable this, use the ``-W`` (``--nowrite``) option. beetbox-beets-00724b7/docs/plugins/fetchart.rst0000664000175000017500000003132515253035401021022 0ustar pieterpieterFetchArt Plugin =============== The ``fetchart`` plugin retrieves album art images from various sources on the Web and stores them as image files. ``fetchart`` supports fetching images in ``JPEG``, ``PNG``, and ``WebP`` formats. To use the ``fetchart`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``fetchart`` extra .. code-block:: bash pip install "beets[fetchart]" Fetching Album Art During Import -------------------------------- When the plugin is enabled, it automatically tries to get album art for every album you import. By default, beets stores album art image files alongside the music files for an album in a file called ``cover.jpg``. To customize the name of this file, use the :ref:`art-filename` config option. To embed the art into the files' tags, use the :doc:`/plugins/embedart`. (You'll want to have both plugins enabled.) Configuration ------------- To configure the plugin, make a ``fetchart:`` section in your configuration file. The available options are: - **auto**: Enable automatic album art fetching during import. Default: ``yes``. - **cautious**: Pick only trusted album art by ignoring filenames that do not contain one of the keywords in ``cover_names``. Default: ``no``. - **cover_names**: Prioritize images containing words in this list. Default: ``cover front art album folder``. - **fallback**: Path to a fallback album art file if no album art was found otherwise. Default: ``None`` (disabled). - **fetch_for_asis**: Fetch album art from online sources during import, even when the as-is option is selected in the Auto-Tagger. When ``no``, only local filesystem sources of art are considered for as-is imports. Default: ``no``. - **minwidth**: Only images with a width bigger or equal to ``minwidth`` are considered as valid album art candidates. Default: 0. - **maxwidth**: A maximum image width to downscale fetched images if they are too big. The resize operation reduces image width to at most ``maxwidth`` pixels. The height is recomputed so that the aspect ratio is preserved. See the section on :ref:`cover-art-archive-maxwidth` below for additional information regarding the Cover Art Archive source. Default: 0 (no maximum is enforced). - **quality**: The JPEG quality level to use when compressing images (when ``maxwidth`` is set). This should be either a number from 1 to 100 or 0 to use the default quality. 65–75 is usually a good starting point. The default behavior depends on the imaging tool used for scaling: ImageMagick tries to estimate the input image quality and uses 92 if it cannot be determined, and PIL defaults to 75. Default: 0 (disabled) - **max_filesize**: The maximum size of a target piece of cover art in bytes. When using an ImageMagick backend this sets ``-define jpeg:extent=max_filesize``. Using PIL this will reduce JPG quality by up to 50% to attempt to reach the target filesize. Neither method is *guaranteed* to reach the target size, however in most cases it should succeed. Default: 0 (disabled) - **enforce_ratio**: Only images with a width:height ratio of 1:1 are considered as valid album art candidates if set to ``yes``. It is also possible to specify a certain deviation to the exact ratio to still be considered valid. This can be done either in pixels (``enforce_ratio: 10px``) or as a percentage of the longer edge (``enforce_ratio: 0.5%``). Default: ``no``. - **sources**: List of sources to search for images. An asterisk ``*`` expands to all available sources. Default: ``filesystem coverart itunes amazon albumart``, i.e., everything but ``wikipedia``, ``google``, ``fanarttv`` and ``lastfm``. Enable those sources for more matches at the cost of some speed. They are searched in the given order, thus in the default config, no remote (Web) art source are queried if local art is found in the filesystem. To use a local image as fallback, move it to the end of the list. For even more fine-grained control over the search order, see the section on :ref:`album-art-sources` below. - **google_key**: Your Google API key (to enable the Google Custom Search backend). Default: None. - **google_engine**: The custom search engine to use. Default: The `beets custom search engine`_, which searches the entire web. - **fanarttv_key**: The personal API key for requesting art from fanart.tv. See below. - **lastfm_key**: The personal API key for requesting art from Last.fm. See below. - **store_source**: If enabled, fetchart stores the artwork's source in a flexible tag named ``art_source``. See below for the rationale behind this. Default: ``no``. - **high_resolution**: If enabled, fetchart retrieves artwork in the highest resolution it can find (warning: image files can sometimes reach >20MB). Default: ``no``. - **deinterlace**: If enabled, Pillow_ or ImageMagick_ backends are instructed to store cover art as non-progressive JPEG. You might need this if you use DAPs that don't support progressive images. Default: ``no``. - **cover_format**: If enabled, forced the cover image into the specified format. Most often, this will be either ``JPEG``, ``PNG``, or ``WEBP`` (see image-formats_). Also respects ``deinterlace``. Default: None (leave unchanged). Note: ``maxwidth`` and ``enforce_ratio`` options require either ImageMagick_ or Pillow_. .. note:: Previously, there was a ``remote_priority`` option to specify when to look for art on the filesystem. This is still respected, but a deprecation message will be shown until you replace this configuration with the new ``filesystem`` value in the ``sources`` array. .. _image-formats: .. admonition:: Image formats Other image formats are available, though the full list depends on your system and what backend you are using. If you're using the ImageMagick backend, you can use ``magick identify -list format`` to get a full list of all supported formats, and you can use the Python function PIL.features.pilinfo() to print a list of all supported formats in Pillow (``python3 -c 'import PIL.features as f; f.pilinfo()'``). .. _beets custom search engine: https://cse.google.com/cse?cx=001442825323518660753:hrh5ch1gjzm Here's an example that makes plugin select only images that contain ``front`` or ``back`` keywords in their filenames and prioritizes the iTunes source over others: :: fetchart: cautious: true cover_names: front back sources: itunes * Manually Fetching Album Art --------------------------- Use the ``fetchart`` command to download album art after albums have already been imported: :: $ beet fetchart [-f] [query] By default, the command will only look for album art when the album doesn't already have it; the ``-f`` or ``--force`` switch makes it search for art in Web databases regardless. If you specify a query, only matching albums will be processed; otherwise, the command processes every album in your library. Display Only Missing Album Art ------------------------------ Use the ``fetchart`` command with the ``-q`` switch in order to display only missing art: :: $ beet fetchart [-q] [query] By default the command will display all albums matching the ``query``. When the ``-q`` or ``--quiet`` switch is given, only albums for which artwork has been fetched, or for which artwork could not be found will be printed. .. _image-resizing: Image Resizing -------------- Beets can resize images using Pillow_, ImageMagick_, or a server-side resizing proxy. If either Pillow or ImageMagick is installed, beets will use those; otherwise, it falls back to the resizing proxy. If the resizing proxy is used, no resizing is performed for album art found on the filesystem---only downloaded art is resized. Server-side resizing can also be slower than local resizing, so consider installing one of the two backends for better performance. When using ImageMagick, beets looks for the ``convert`` executable in your path. On some versions of Windows, the program can be shadowed by a system-provided ``convert.exe``. On these systems, you may need to modify your ``%PATH%`` environment variable so that ImageMagick comes first or use Pillow instead. .. _album-art-sources: Album Art Sources ----------------- By default, this plugin searches for art in the local filesystem as well as on the Cover Art Archive, the iTunes Store, Amazon, and AlbumArt.org, in that order. You can reorder the sources or remove some to speed up the process using the ``sources`` configuration option. When looking for local album art, beets checks for image files located in the same folder as the music files you're importing. Beets prefers to use an image file whose name contains "cover", "front", "art", "album" or "folder", but in the absence of well-known names, it will use any image file in the same folder as your music files. For some of the art sources, the backend service can match artwork by various criteria. If you want finer control over the search order in such cases, you can use this alternative syntax for the ``sources`` option: :: fetchart: sources: - filesystem - coverart: release - itunes - coverart: releasegroup - '*' where listing a source without matching criteria will default to trying all available strategies. Entries of the forms ``coverart: release releasegroup`` and ``coverart: *`` are also valid. Currently, only the ``coverart`` source supports multiple criteria: namely, ``release`` and ``releasegroup``, which refer to the respective MusicBrainz IDs. When you choose to apply changes during an import, beets will search for art as described above. For "as-is" imports (and non-autotagged imports using the ``-A`` flag), beets only looks for art on the local filesystem. Google custom search ~~~~~~~~~~~~~~~~~~~~ To use the google image search backend you need to `register for a Google API key`_. Set the ``google_key`` configuration option to your key, then add ``google`` to the list of sources in your configuration. .. _register for a google api key: https://console.cloud.google.com/apis/credentials Optionally, you can `define a custom search engine`_. Get your search engine's token and use it for your ``google_engine`` configuration option. The default engine searches the entire web for cover art. .. _define a custom search engine: https://programmablesearchengine.google.com/about/ Note that the Google custom search API is limited to 100 queries per day. After that, the fetchart plugin will fall back on other declared data sources. Fanart.tv ~~~~~~~~~ Although not strictly necessary right now, you might think about `registering a personal fanart.tv API key`_. Set the ``fanarttv_key`` configuration option to your key, then add ``fanarttv`` to the list of sources in your configuration. .. _registering a personal fanart.tv api key: https://fanart.tv/get-an-api-key/ More detailed information can be found `on their Wiki`_. Specifically, the personal key will give you earlier access to new art. .. _on their wiki: https://wiki.fanart.tv/General/personal%20api/ Last.fm ~~~~~~~ To use the Last.fm backend, you need to `register for a Last.fm API key`_. Set the ``lastfm_key`` configuration option to your API key, then add ``lastfm`` to the list of sources in your configuration. .. _register for a last.fm api key: https://www.last.fm/api/account/create Spotify ~~~~~~~ Spotify backend is enabled by default and will update album art if a valid Spotify album id is found. .. _beautifulsoup: https://www.crummy.com/software/BeautifulSoup/bs4/doc/ .. _pip: https://pip.pypa.io Cover Art URL ~~~~~~~~~~~~~ The ``fetchart`` plugin can also use a flexible attribute field ``cover_art_url`` where you can manually specify the image URL to be used as cover art. Any custom plugin can use this field to provide the cover art and ``fetchart`` will use it as a source. .. _cover-art-archive-maxwidth: Cover Art Archive Pre-sized Thumbnails -------------------------------------- The CAA provides pre-sized thumbnails of width 250, 500, and 1200 pixels. If you set the ``maxwidth`` option to one of these values, the corresponding image will be downloaded, saving ``beets`` the need to scale down the image. It can also speed up the downloading process, as some cover arts can sometimes be very large. Storing the Artwork's Source ---------------------------- Storing the current artwork's source might be used to narrow down ``fetchart`` commands. For example, if some albums have artwork placed manually in their directories that should not be replaced by a forced album art fetch, you could do ``beet fetchart -f ^art_source:filesystem`` The values written to ``art_source`` are the same names used in the ``sources`` configuration value. .. _imagemagick: https://imagemagick.org/ .. _pillow: https://github.com/python-pillow/Pillow beetbox-beets-00724b7/docs/plugins/substitute.rst0000664000175000017500000000327615253035401021441 0ustar pieterpieterSubstitute Plugin ================= The ``substitute`` plugin lets you easily substitute values in your templates and path formats. Specifically, it is intended to let you *canonicalize* names such as artists: For example, perhaps you want albums from The Jimi Hendrix Experience to be sorted into the same folder as solo Hendrix albums. This plugin is intended as a replacement for the ``rewrite`` plugin. While the ``rewrite`` plugin modifies the metadata, this plugin does not. Enable the ``substitute`` plugin (see :ref:`using-plugins`), then make a ``substitute:`` section in your config file to contain your rules. Each rule consists of a case-insensitive regular expression pattern, and a replacement string. For example, you might use: .. code-block:: yaml substitute: .*jimi hendrix.*: Jimi Hendrix The replacement can be an expression utilising the matched regex, allowing us to create more general rules. Say for example, we want to sort all albums by multiple artists into the directory of the first artist. We can thus capture everything before the first ``,``, ``&`` or ``and``, and use this capture group in the output, discarding the rest of the string. .. code-block:: yaml substitute: ^(.*?)(,| &| and).*: \1 This would handle all the below cases in a single rule: | Bob Dylan and The Band -> Bob Dylan | Neil Young & Crazy Horse -> Neil Young | James Yorkston, Nina Persson & The Second Hand Orchestra -> James Yorkston To apply the substitution, you have to call the function ``%substitute{}`` in the paths section. For example: .. code-block:: yaml paths: default: \%substitute{$albumartist}/$year - $album\%aunique{}/$track - $title beetbox-beets-00724b7/docs/plugins/parentwork.rst0000664000175000017500000000524415253035401021417 0ustar pieterpieterParentWork Plugin ================= The ``parentwork`` plugin fetches the work title, parent work title and parent work composer from MusicBrainz. In the MusicBrainz database, a recording can be associated with a work. A work can itself be associated with another work, for example one being part of the other (what we call the *direct parent*). This plugin looks the work id from the library and then looks up the direct parent, then the direct parent of the direct parent and so on until it reaches the top. The work at the top is what we call the *parent work*. This plugin is especially designed for classical music. For classical music, just fetching the work title as in MusicBrainz is not satisfying, because MusicBrainz has separate works for, for example, all the movements of a symphony. This plugin aims to solve this problem by also fetching the parent work, which would be the whole symphony in this example. The plugin can detect changes in ``mb_workid`` so it knows when to re-fetch other metadata, such as ``parentwork``. To do this, when it runs, it stores a copy of ``mb_workid`` in the bookkeeping field ``parentwork_workid_current``. At any later run of ``beet parentwork`` it will check if the tags ``mb_workid`` and ``parentwork_workid_current`` are still identical. If it is not the case, it means the work has changed and all the tags need to be fetched again. This plugin adds seven tags: - **parentwork**: The title of the parent work. - **mb_parentworkid**: The MusicBrainz id of the parent work. - **parentwork_disambig**: The disambiguation of the parent work title. - **parent_composer**: The composer of the parent work. - **parent_composer_sort**: The sort name of the parent work composer. - **work_date**: The composition date of the work, or the first parent work that has a composition date. Format: yyyy-mm-dd. - **parentwork_workid_current**: The MusicBrainz id of the work as it was when the parentwork was retrieved. This tag exists only for internal bookkeeping, to keep track of recordings whose works have changed. - **parentwork_date**: The composition date of the parent work. Configuration ------------- To configure the plugin, make a ``parentwork:`` section in your configuration file. The available options are: - **force**: As a default, ``parentwork`` only fetches work info for recordings that do not already have a ``parentwork`` tag or where ``mb_workid`` differs from ``parentwork_workid_current``. If ``force`` is enabled, it fetches it for all recordings. Default: ``no`` - **auto**: If enabled, automatically fetches works at import. It takes quite some time, because beets is restricted to one MusicBrainz query per second. Default: ``no`` beetbox-beets-00724b7/docs/plugins/aura.rst0000664000175000017500000001664115253035401020156 0ustar pieterpieterAURA Plugin =========== This plugin is a server implementation of the AURA_ specification using the Flask_ framework. AURA is still a work in progress and doesn't yet have a stable version, but this server should be kept up to date. You are advised to read the :ref:`aura-issues` section. .. _aura: https://auraspec.readthedocs.io/en/latest/ .. _flask: https://palletsprojects.com/projects/flask/ Install ------- To use the ``aura`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``aura`` extra pip install "beets[aura]" Usage ----- Use ``beet aura`` to start the AURA server. By default Flask's built-in server is used, which will give a warning about using it in a production environment. It is safe to ignore this warning if the server will have only a few users. Alternatively, you can use ``beet aura -d`` to start the server in `development mode `__, which will reload the server every time the AURA plugin file is changed. You can specify the hostname and port number used by the server in your :doc:`configuration file `. For more detail see the :ref:`configuration` section below. If you would prefer to use a different WSGI server, such as gunicorn or uWSGI, then see :ref:`aura-external-server`. AURA is designed to separate the client and server functionality. This plugin provides the server but not the client, so unless you like looking at JSON you will need a separate client. Currently the only client is `AURA Web Client`_. In order to use a local browser client with ``file:///`` see :ref:`aura-cors`. By default the API is served under http://127.0.0.1:8337/aura/. For example information about the track with an id of 3 can be obtained at http://127.0.0.1:8337/aura/tracks/3. **Note the absence of a trailing slash**: http://127.0.0.1:8337/aura/tracks/3/ returns a ``404 Not Found`` error. .. _aura web client: https://sr.ht/~callum/aura-web-client/ .. _configuration: Configuration ------------- To configure the plugin, make an ``aura:`` section in your configuration file. The available options are: - **host**: The server hostname. Set this to ``0.0.0.0`` to bind to all interfaces. Default: ``127.0.0.1``. - **port**: The server port. Default: ``8337``. - **cors**: A YAML list of origins to allow CORS requests from (see :ref:`aura-cors`, below). Default: disabled. - **cors_supports_credentials**: Allow authenticated requests when using CORS. Default: disabled. - **page_limit**: The number of items responses should be truncated to if the client does not specify. Default ``500``. .. _aura-cors: Cross-Origin Resource Sharing (CORS) ------------------------------------ `CORS `__ allows browser clients to make requests to the AURA server. You should set the ``cors`` configuration option to a YAML list of allowed origins. For example: :: aura: cors: - http://www.example.com - https://aura.example.org In order to use the plugin with a local browser client accessed using ``file:///`` you must include ``'null'`` in the list of allowed origins (including quote marks): :: aura: cors: - 'null' Alternatively you use ``'*'`` to enable access from all origins. Note that there are security implications if you set the origin to ``'*'``, so please research this before using it. Note the use of quote marks when allowing all origins. If the server is behind a proxy that uses credentials, you might want to set the ``cors_supports_credentials`` configuration option to true to let in-browser clients log in. Note that this option has not been tested, so it may not work. .. _aura-external-server: Using an External WSGI Server ----------------------------- If you would like to use a different WSGI server (not Flask's built-in one), then you can! The ``beetsplug.aura`` module provides a WSGI callable called ``create_app()`` which can be used by many WSGI servers. For example to run the AURA server using gunicorn_ use ``gunicorn 'beetsplug.aura:create_app()'``, or for uWSGI_ use ``uwsgi --http :8337 --module 'beetsplug.aura:create_app()'``. Note that these commands just show how to use the AURA app and you would probably use something a bit different in a production environment. Read the relevant server's documentation to figure out what you need. .. _gunicorn: https://gunicorn.org .. _uwsgi: https://uwsgi-docs.readthedocs.io/en/latest/ Reverse Proxy Support --------------------- The plugin should work behind a reverse proxy without further configuration, however this has not been tested extensively. For details of what headers must be rewritten and a sample NGINX configuration see `Flask proxy setups`_. .. _flask proxy setups: https://flask.palletsprojects.com/en/stable/deploying/proxy_fix/ It is (reportedly) possible to run the application under a URL prefix (for example so you could have ``/foo/aura/server`` rather than ``/aura/server``), but you'll have to work it out for yourself :-) If using NGINX, do **not** add a trailing slash (``/``) to the URL where the application is running, otherwise you will get a 404. However if you are using Apache then you **should** add a trailing slash. .. _aura-issues: Issues ------ As of writing there are some differences between the specification and this implementation: - Compound filters are not specified in AURA, but this server interprets multiple ``filter`` parameters as AND. See `issue #19`_ for discussion. - The ``bitrate`` parameter used for content negotiation is not supported. Adding support for this is doable, but the way Flask handles acceptable MIME types means it's a lot easier not to bother with it. This means an error could be returned even if no transcoding was required. It is possible that some attributes required by AURA could be absent from the server's response if beets does not have a saved value for them. However, this has not happened so far. Beets fields (including flexible fields) that do not have an AURA equivalent are not provided in any resource's attributes section, however these fields may be used for filtering. The ``mimetype`` and ``framecount`` attributes for track resources are not supported. The first is due to beets storing the file type (e.g. ``MP3``), so it is hard to filter by MIME type. The second is because there is no corresponding beets field. Artists are defined by the ``artist`` field on beets Items, which means some albums have no ``artists`` relationship. Albums only have related artists when their beets ``albumartist`` field is the same as the ``artist`` field on at least one of it's constituent tracks. The only art tracked by beets is a single cover image, so only albums have related images at the moment. This could be expanded to looking in the same directory for other images, and relating tracks to their album's image. There are likely to be some performance issues, especially with larger libraries. Sorting, pagination and inclusion (most notably of images) are probably the main offenders. On a related note, the program attempts to import Pillow every time it constructs an image resource object, which is not good. The beets library is accessed using a so called private function (with a single leading underscore) ``beets.ui.__init__._open_library()``. This shouldn't cause any issues but it is probably not best practice. .. _issue #19: https://github.com/beetbox/aura/issues/19 beetbox-beets-00724b7/docs/plugins/unimported.rst0000664000175000017500000000133015253035401021401 0ustar pieterpieterUnimported Plugin ================= The ``unimported`` plugin allows one to list all files in the library folder which are not listed in the beets library database, including art files. Command Line Usage ------------------ To use the ``unimported`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then use it by invoking the ``beet unimported`` command. The command will list all files in the library folder which are not imported. You can exclude file extensions or entire subdirectories using the configuration file: :: unimported: ignore_extensions: jpg png ignore_subdirectories: NonMusic data temp The default configuration lists all unimported files, ignoring no extensions. beetbox-beets-00724b7/docs/plugins/plexupdate.rst0000664000175000017500000000777015253035401021404 0ustar pieterpieterPlexUpdate Plugin ================= The ``plexupdate`` plugin automatically refreshes the music library on your Plex_ Media Server whenever your beets library changes. Why Use the PlexUpdate Plugin? ------------------------------ The PlexUpdate plugin allows you to: - Keep the music library on your Plex Media Server in sync with beets - Avoid having to trigger a library scan in Plex manually - Refresh Plex automatically after imports, edits, moves, and other commands that modify your library Once configured, the refresh happens automatically whenever a beets command changes your library, so you don't need to think about it. Requirements ------------ - A running Plex Media Server instance that beets can reach over the network Installation ------------ To use the ``plexupdate`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with the ``plexupdate`` extra: .. code-block:: bash pip install "beets[plexupdate]" Authentication -------------- Plex requires an authentication token for API requests. The easiest way to obtain one is the interactive login: .. code-block:: bash beet plexupdate --auth This opens a browser window where you can log in to your Plex account and authorize beets. After a successful login, the access token is stored in the token file (see the ``tokenfile`` option below), and beets uses it to update your library on subsequent runs. .. dropdown:: Alternative Authentication Alternatively, the ``token`` configuration option provides a legacy way to authenticate: it accepts a token from your Plex account directly (see Plex's `documentation about tokens`_). It should not be used for new setups, though -- run ``beet plexupdate --auth`` instead, which stores the token in the token file and keeps it out of your configuration. Basic Usage ----------- Enable the ``plexupdate`` plugin (see :ref:`using-plugins`) and, optionally, configure your Plex server as described below. Whenever a beets command modifies your library (for example ``beet import``, ``beet modify``, or ``beet move``) the plugin tells Plex to refresh its music library when the command finishes. You can verify the refresh in the Plex web interface: the activity view of your music library shows the scan started by beets. Configuration ------------- The plugin is configured under the ``plex:`` section! Default ~~~~~~~ .. code-block:: yaml plex: host: localhost port: 32400 library_name: Music secure: no ignore_cert_errors: no tokenfile: plex_token.json .. conf:: host :default: localhost The hostname or IP address of the Plex Media Server. .. conf:: port :default: 32400 The port on which the Plex Media Server listens. .. conf:: library_name :default: Music The name of the Plex library to refresh. .. conf:: secure :default: no Use HTTPS instead of HTTP when connecting to the Plex Media Server. Enable this when your server is only reachable over a secure connection, for example through a reverse proxy. .. conf:: ignore_cert_errors :default: no Ignore TLS certificate errors when ``secure`` is enabled. Useful when the server uses a self-signed certificate. .. conf:: tokenfile :default: plex_token.json The file where the token obtained via ``beet plexupdate --auth`` is stored together with the client identifier used for the login. The file is created in the beets configuration directory. .. conf:: token :default: "" .. deprecated:: 2.14 Use ``beet plexupdate --auth`` instead. A Plex token that overrides the token stored by ``beet plexupdate --auth``. Kept for legacy configurations that cannot use the interactive login, for example Plex Home accounts. This value is never written to the token file and is redacted in beets' configuration listings. .. _documentation about tokens: https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/ .. _plex: https://www.plex.tv/ beetbox-beets-00724b7/docs/plugins/shared_metadata_source_config.rst0000664000175000017500000000344415253035401025236 0ustar pieterpieter.. _data_source_mismatch_penalty: .. conf:: data_source_mismatch_penalty :default: 0.5 Penalty applied when the data source of a match candidate differs from the original source of your existing tracks. Any decimal number between 0.0 and 1.0 This setting controls how much to penalize matches from different metadata sources during import. The penalty is applied when beets detects that a match candidate comes from a different data source than what appears to be the original source of your music collection. **Example configurations:** .. code-block:: yaml # Prefer MusicBrainz over Discogs when sources don't match plugins: musicbrainz discogs musicbrainz: data_source_mismatch_penalty: 0.3 # Lower penalty = preferred discogs: data_source_mismatch_penalty: 0.8 # Higher penalty = less preferred .. code-block:: yaml # Do not penalise candidates from Discogs at all plugins: musicbrainz discogs musicbrainz: data_source_mismatch_penalty: 0.5 discogs: data_source_mismatch_penalty: 0.0 .. code-block:: yaml # Disable cross-source penalties entirely plugins: musicbrainz discogs musicbrainz: data_source_mismatch_penalty: 0.0 discogs: data_source_mismatch_penalty: 0.0 .. tip:: The last configuration is equivalent to setting: .. code-block:: yaml match: distance_weights: data_source: 0.0 # Disable data source matching .. conf:: source_weight :default: 0.5 .. deprecated:: 2.5 Use `data_source_mismatch_penalty`_ instead. .. conf:: search_limit :default: 5 Maximum number of search results to return. beetbox-beets-00724b7/docs/plugins/importadded.rst0000664000175000017500000000356415253035401021522 0ustar pieterpieterImportAdded Plugin ================== The ``importadded`` plugin is useful when an existing collection is imported and the time when albums and items were added should be preserved. To use the ``importadded`` plugin, enable it in your configuration (see :ref:`using-plugins`). Usage ----- The :abbr:`mtime (modification time)` of files that are imported into the library are assumed to represent the time when the items were originally added. The ``item.added`` field is populated as follows: - For singleton items with no album, ``item.added`` is set to the item's file mtime before it was imported. - For items that are part of an album, ``album.added`` and ``item.added`` are set to the oldest mtime of the files in the album before they were imported. The mtime of album directories is ignored. This plugin can optionally be configured to also preserve mtimes at import using the ``preserve_mtimes`` option. When ``preserve_write_mtimes`` option is set, this plugin preserves mtimes after each write to files using the ``item.added`` attribute. File modification times are preserved as follows: - For all items: - ``item.mtime`` is set to the mtime of the file from which the item is imported from. - The mtime of the file ``item.path`` is set to ``item.mtime``. Note that there is no ``album.mtime`` field in the database and that the mtime of album directories on disk aren't preserved. Configuration ------------- To configure the plugin, make an ``importadded:`` section in your configuration file. There are two options available: - **preserve_mtimes**: After importing files, re-set their mtimes to their original value. Default: ``no``. - **preserve_write_mtimes**: After writing files, re-set their mtimes to their original value. Default: ``no``. Reimport -------- This plugin will skip reimported singleton items and reimported albums and all of their items. beetbox-beets-00724b7/docs/plugins/smartplaylist.rst0000664000175000017500000001644415253035401022137 0ustar pieterpieterSmart Playlist Plugin ===================== ``smartplaylist`` is a plugin to generate smart playlists in m3u format based on beets queries every time your library changes. This plugin is specifically created to work well with `MPD's`_ playlist functionality. .. _mpd's: https://www.musicpd.org/ To use it, enable the ``smartplaylist`` plugin in your configuration (see :ref:`using-plugins`). Then configure your smart playlists like the following example: :: smartplaylist: relative_to: ~/Music playlist_dir: ~/.mpd/playlists forward_slash: no playlists: - name: all.m3u query: '' - name: beatles.m3u query: 'artist:Beatles' You can generate as many playlists as you want by adding them to the ``playlists`` section, using beets query syntax (see :doc:`/reference/query`) for ``query`` and the file name to be generated for ``name``. The query will be split using shell-like syntax, so if you need to use spaces in the query, be sure to quote them (e.g., ``artist:"The Beatles"``). If you have existing files with the same names, you should back them up---they will be overwritten when the plugin runs. For more advanced usage, you can use template syntax (see :doc:`/reference/pathformat/`) in the ``name`` field. For example: :: - name: 'ReleasedIn$year.m3u' query: 'year::201(0|1)' This will query all the songs in 2010 and 2011 and generate the two playlist files ``ReleasedIn2010.m3u`` and ``ReleasedIn2011.m3u`` using those songs. You can also gather the results of several queries by putting them in a list. (Items that match both queries are not included twice.) For example: :: - name: 'BeatlesUniverse.m3u' query: ['artist:beatles', 'genre:"beatles cover"'] Note that since beets query syntax is in effect, you can also use sorting directives: :: - name: 'Chronological Beatles' query: 'artist:Beatles year+' - name: 'Mixed Rock' query: ['artist:Beatles year+', 'artist:"Led Zeppelin" bitrate+'] The former case behaves as expected, however please note that in the latter the sorts will be merged: ``year+ bitrate+`` will apply to both the Beatles and Led Zeppelin. If that bothers you, please get in touch. For querying albums instead of items (mainly useful with extensible fields), use the ``album_query`` field. ``query`` and ``album_query`` can be used at the same time. The following example gathers single items but also items belonging to albums that have a ``for_travel`` extensible field set to 1: :: - name: 'MyTravelPlaylist.m3u' album_query: 'for_travel:1' query: 'for_travel:1' By default, each playlist is automatically regenerated at the end of the session if an item or album it matches changed in the library database. To force regeneration, you can invoke it manually from the command line: :: $ beet splupdate This will regenerate all smart playlists. You can also specify which ones you want to regenerate: :: $ beet splupdate BeatlesUniverse.m3u MyTravelPlaylist You can also use this plugin together with the :doc:`mpdupdate`, in order to automatically notify MPD of the playlist change, by adding ``mpdupdate`` to the ``plugins`` line in your config file *after* the ``smartplaylist`` plugin. Plugin Event ------------ After writing updated playlist files, this plugin sends the ``smartplaylist_update`` event. See :ref:`plugin_events` for its listener parameters. The event is not sent in pretend mode. While working on smart playlist queries in the beets configuration it can help to use the ``--pretend`` option to find out if the edits work as expected before writing changes. To list the tracks matching the query, switch to the DEBUG log level. :: $ beet -v splupdate --pretend BeatlesUniverse.m3u The ``format`` configuration option defaults to ``$artist - $title``, and can be set up to a custom format string. In case you want to export additional fields from the beets database into the generated playlists, you can do so by specifying them within the ``fields`` configuration option and setting the ``output`` option to ``extm3u``. For instance the following configuration exports the ``id`` and ``genre`` fields: :: smartplaylist: playlist_dir: /data/playlists relative_to: /data/playlists output: extm3u fields: - id - genres playlists: - name: all.m3u query: '' Values of additional fields are URL-encoded. A resulting ``all.m3u`` file could look as follows: :: #EXTM3U #EXTINF:805 id="1931" genres="Rock%3B%20Pop",Led Zeppelin - Stairway to Heaven ../music/singles/Led Zeppelin/Stairway to Heaven.mp3 To give a usage example, the webm3u_ and Beetstream_ plugins read the exported ``id`` field, allowing you to serve your local m3u playlists via HTTP. .. _beetstream: https://github.com/BinaryBrain/Beetstream .. _webm3u: https://github.com/mgoltzsche/beets-webm3u Configuration ------------- To configure the plugin, make a ``smartplaylist:`` section in your configuration file. In addition to the ``playlists`` described above, the other configuration options are: - **auto**: Regenerate the playlist after every database change. Default: ``yes``. - **playlist_dir**: Where to put the generated playlist files. Default: The current working directory (i.e., ``'.'``). - **dest_regen**: Regenerate the destination path as ``move`` or ``convert`` commands would do. This operation will happen before ``relative_to`` and ``prefix``. Helpful to generate playlists compatible with the ``convert`` plugin when items have been imported with the ``-C -M`` options. Default: ``false``. - **relative_to**: Generate paths in the playlist files relative to a base directory. If you intend to use this plugin to generate playlists for MPD, point this to your MPD music directory. Default: Use absolute paths. - **forward_slash**: Forces forward slashes in the generated playlist files. If you intend to use this plugin to generate playlists for MPD on Windows, set this to yes. Default: Use system separator. - **prefix**: Prepend this string to every path in the playlist file. For example, you could use the URL for a server where the music is stored. Default: empty string. - **urlencode**: URL-encode all paths. Default: ``no``. - **uri_format**: Template with an ``$id`` placeholder used generate a playlist item URI, e.g. ``http://beets:8337/item/$id/file``. When this option is specified, the local path-related options ``dest_regen``, ``prefix``, ``relative_to``, ``forward_slash`` and ``urlencode`` are ignored. - **output**: Specify the playlist format: m3u|extm3u. Default ``m3u``. - **fields**: Specify the names of the additional item fields to export into the playlist. This allows using e.g. the ``id`` field within other tools such as the webm3u_ and Beetstream_ plugins. To use this option, you must set the ``output`` option to ``extm3u``. - **format**: Specify the format a playlist item is logged in ``DEBUG`` level. Default: ``$artist - $title``. For many configuration options, there is a corresponding CLI option, e.g. ``--playlist-dir``, ``--dest-regen``, ``--relative-to``, ``--prefix``, ``--forward-slash``, ``--urlencode``, ``--uri-format``, ``--output``, ``--format``. CLI options take precedence over those specified within the configuration file. beetbox-beets-00724b7/docs/plugins/lyrics.rst0000664000175000017500000002402715253035401020530 0ustar pieterpieterLyrics Plugin ============= The ``lyrics`` plugin fetches and stores song lyrics from databases on the Web. Namely, the current version of the plugin uses Genius.com_, Tekstowo.pl_, LRCLIB_, lrcmux_ and, optionally, the Google Custom Search API. .. _genius.com: https://genius.com/ .. _lrclib: https://lrclib.net/ .. _lrcmux: https://lrcmux.dev/ .. _tekstowo.pl: https://www.tekstowo.pl/ Install ------- Firstly, enable ``lyrics`` plugin in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``lyrics`` extra .. code-block:: bash pip install "beets[lyrics]" Fetch Lyrics During Import -------------------------- When importing new files, beets will now fetch lyrics for files that don't already have them. The lyrics will be stored in the beets database. The plugin also sets a few useful flexible attributes: - ``lyrics_backend``: name of the backend that provided the lyrics - ``lyrics_url``: URL of the page where the lyrics were found - ``lyrics_instrumental``: whether the backend marked the track as instrumental - ``lyrics_language``: original language of the lyrics - ``lyrics_translation_language``: language of the lyrics translation (if translation is enabled) When a backend reports an instrumental track, beets leaves the lyrics text empty and sets ``lyrics_instrumental`` instead. If the ``import.write`` config option is on, then the lyrics will also be written to the files' tags. Configuration ------------- To configure the plugin, make a ``lyrics:`` section in your configuration file. Default configuration: .. code-block:: yaml lyrics: auto: yes auto_ignore: null translate: api_key: from_languages: [] to_language: dist_thresh: 0.11 fallback: null force: no keep_synced: no google_API_key: null google_engine_ID: 009217259823014548361:lndtuqkycfu lrcmux: url: https://api.lrcmux.dev sources: [] print: no rest_directory: null sources: [lrclib, google, genius, lrcmux] synced: no The available options are: - **auto**: Fetch lyrics automatically during import. - **auto_ignore**: A beets query string of items to skip when fetching lyrics during auto import. For example, to skip tracks from Bandcamp or with a Techno genre: .. code-block:: yaml lyrics: auto_ignore: | data_source:bandcamp , genres:techno Default: ``null`` (nothing is ignored). See :doc:`/reference/query` for the query syntax. - **translate**: - **api_key**: Api key to access your Azure Translator resource. (see :ref:`lyrics-translation`) - **from_languages**: By default all lyrics with a language other than ``translate_to`` are translated. Use a list of language codes to restrict them. - **to_language**: Language code to translate lyrics to. - **dist_thresh**: The maximum distance between the artist and title combination of the music file and lyrics candidate to consider them a match. Lower values will make the plugin more strict, higher values will make it more lenient. This does not apply to the ``lrclib`` backend as it matches durations. - **fallback**: By default, the file will be left unchanged when no lyrics are found. Use the empty string ``''`` to reset the lyrics in such a case. - **force**: By default, beets won't fetch lyrics if the files already have ones. To instead always fetch lyrics, set the ``force`` option to ``yes``. - **keep_synced**: When enabled, tracks that already have synced lyrics are skipped even when ``force`` is set. Useful when re-fetching lyrics for a library that contains a mix of synced and plain lyrics and you only want to fill in the gaps. Default: ``no``. - **google_API_key**: Your Google API key (to enable the Google Custom Search backend). - **google_engine_ID**: The custom search engine to use. Default: The `beets custom search engine`_, which gathers an updated list of sources known to be scrapeable. - **lrcmux**: - **url**: Base URL of the lrcmux_ instance to use. Override this to point at a self-hosted instance. - **sources**: List of lrcmux provider IDs to restrict the search to, e.g. ``[ytmusic, kugou]``. Prefix an entry with ``!`` to exclude that provider instead, e.g. ``["!musixmatch"]``. Leave empty (the default) to use all providers. - **print**: Print lyrics to the console. - **rest_directory**: The directory to which reStructuredText_ (ReST) rendered lyric documents will be output. See :ref:`rendering-lyrics`. - **sources**: List of sources to search for lyrics. An asterisk ``*`` expands to all available sources. The ``google`` source will be automatically deactivated if no ``google_API_key`` is setup. By default, ``musixmatch`` and ``tekstowo`` are excluded because they block the beets User-Agent. - **synced**: Prefer synced lyrics over plain lyrics if a source offers them. ``lrclib`` and ``lrcmux`` both provide synced lyrics. Using this option, existing synced lyrics are not replaced by newly fetched plain lyrics (even when ``force`` is enabled). To allow that replacement, disable ``synced``. When synced lyrics are written to an ID3-tagged file (MP3, AIFF, etc.) the plugin stores the timestamped data in the ``SYLT`` (synchronized lyrics) frame and plain text (without timestamps) in the ``USLT`` (unsynchronized lyrics) frame, so players that support only one of the two formats can still show the correct lyrics. .. _beets custom search engine: https://cse.google.com/cse?cx=009217259823014548361:lndtuqkycfu Fetching Lyrics Manually ------------------------ The ``lyrics`` command provided by this plugin fetches lyrics for items that match a query (see :doc:`/reference/query`). For example, ``beet lyrics magnetic fields absolutely cuckoo`` will get the lyrics for the appropriate Magnetic Fields song, ``beet lyrics magnetic fields`` will get lyrics for all my tracks by that band, and ``beet lyrics`` will get lyrics for my entire library. The lyrics will be added to the beets database and, if ``import.write`` is on, embedded into files' metadata. The ``-p, --print`` option to the ``lyrics`` command makes it print lyrics out to the console so you can view the fetched (or previously-stored) lyrics. The ``-f, --force`` option forces the command to fetch lyrics, even for tracks that already have lyrics. The ``--keep-synced`` option skips tracks that already have synced lyrics, regardless of the ``force`` flag. This is handy when you want to re-fetch plain lyrics without touching tracks that already have a synced version. Use ``--no-keep-synced`` to override a ``keep_synced: yes`` configuration for a single command run. Inversely, the ``-l, --local`` option restricts operations to lyrics that are locally available, which show lyrics faster without using the network at all. .. _rendering-lyrics: Rendering Lyrics into Other Formats ----------------------------------- The ``-r directory, --write-rest directory`` option renders all lyrics as reStructuredText_ (ReST) documents in ``directory``. That directory, in turn, can be parsed by tools like Sphinx_ to generate HTML, ePUB, or PDF documents. Minimal ``conf.py`` and ``index.rst`` files are created the first time the command is run. They are not overwritten on subsequent runs, so you can safely modify these files to customize the output. Sphinx supports various builders_, see a few suggestions: .. admonition:: Build an HTML version :: sphinx-build -b html

/html .. admonition:: Build an ePUB3 formatted file, usable on ebook readers :: sphinx-build -b epub3 /epub .. admonition:: Build a PDF file, which incidentally also builds a LaTeX file :: sphinx-build -b latex /latex && make -C /latex all-pdf .. _builders: https://www.sphinx-doc.org/en/master/usage/builders/index.html .. _restructuredtext: https://sourceforge.net/projects/docutils/ .. _sphinx: https://www.sphinx-doc.org/en/master/ Activate Google Custom Search ----------------------------- You need to `register for a Google API key `__. Set the ``google_API_key`` configuration option to your key. Then add ``google`` to the list of sources in your configuration (or use default list, which includes it as long as you have an API key). If you use default ``google_engine_ID``, we recommend limiting the sources to ``google`` as the other sources are already included in the Google results. Optionally, you can `define a custom search engine`_. Get your search engine's token and use it for your ``google_engine_ID`` configuration option. By default, beets use a list of sources known to be scrapeable. Note that the Google custom search API is limited to 100 queries per day. After that, the lyrics plugin will fall back on other declared data sources. .. _define a custom search engine: https://programmablesearchengine.google.com/about/ .. _lyrics-translation: Activate On-the-Fly Translation ------------------------------- We use Azure to optionally translate your lyrics. To set up the integration, follow these steps: 1. `Create a Translator resource`_ on Azure. Make sure the region of the translator resource is set to Global. You will get 401 unauthorized errors if not. The region of the resource group does not matter. 2. `Obtain its API key`_. 3. Add the API key to your configuration as ``translate.api_key``. 4. Configure your target language using the ``translate.to_language`` option. For example, with the following configuration .. code-block:: yaml lyrics: translate: api_key: YOUR_TRANSLATOR_API_KEY to_language: de You should expect lyrics like this: :: Original verse / Ursprünglicher Vers Some other verse / Ein anderer Vers .. _create a translator resource: https://learn.microsoft.com/en-us/azure/ai-services/translator/create-translator-resource .. _obtain its api key: https://learn.microsoft.com/en-us/python/api/overview/azure/ai-translation-text-readme?view=azure-python&preserve-view=true#get-an-api-key beetbox-beets-00724b7/docs/plugins/subsonicplaylist.rst0000664000175000017500000000330215253035401022623 0ustar pieterpieterSubsonic Playlist Plugin ======================== The ``subsonicplaylist`` plugin allows to import playlists from a subsonic server. This is done by retrieving the track info from the subsonic server, searching for them in the beets library, and adding the playlist names to the ``subsonic_playlist`` tag of the found items. The content of the tag has the format: subsonic_playlist: ";first playlist;second playlist;" To get all items in a playlist use the query ``;playlist name;``. Command Line Usage ------------------ To use the ``subsonicplaylist`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then use it by invoking the ``subsonicplaylist`` command. Next, configure the plugin to connect to your Subsonic server, like this: :: subsonicplaylist: base_url: http://subsonic.example.com username: someUser password: somePassword After this you can import your playlists by invoking the ``subsonicplaylist`` command. By default only the tags of the items found for playlists will be updated. This means that, if one imported a playlist, then delete one song from it and imported the playlist again, the deleted song will still have the playlist set in its ``subsonic_playlist`` tag. To solve this problem one can use the ``-d/--delete`` flag. This resets all ``subsonic_playlist`` tag before importing playlists. Here's an example configuration with all the available options and their default values: :: subsonicplaylist: base_url: "https://your.subsonic.server" delete: no playlist_ids: [] playlist_names: [] username: '' password: '' The ``base_url``, ``username``, and ``password`` options are required. beetbox-beets-00724b7/docs/plugins/inline.rst0000664000175000017500000000514615253035401020502 0ustar pieterpieterInline Plugin ============= The ``inline`` plugin lets you use Python to customize your path formats. Using it, you can define template fields in your beets configuration file and refer to them from your template strings in the ``paths:`` section (see :doc:`/reference/config/`). To use the ``inline`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then, make a ``item_fields:`` block in your config file. Under this key, every line defines a new template field; the key is the name of the field (you'll use the name to refer to the field in your templates) and the value is a Python expression or function body. The Python code has all of a track's normal fields in scope, so you can refer to these attributes (such as ``artist`` or ``title``) as Python variables. The Python code also has direct access to the item or album object as ``db_obj``. This allows use of computed fields and plugin fields, for example, ``db_obj.albumtotal``, or ``db_obj.missing`` if the :doc:`/plugins/missing` plugin is enabled. Here are a couple of examples of expressions: :: item_fields: initial: albumartist[0].upper() + u'.' disc_and_track: f"{disc:02d}.{track:02d}" if disctotal > 1 else f"{track:02d}" Note that YAML syntax allows newlines in values if the subsequent lines are indented. These examples define ``$initial`` and ``$disc_and_track`` fields that can be referenced in path templates like so: :: paths: default: $initial/$artist/$album%aunique{}/$disc_and_track $title Block Definitions ----------------- If you need to use statements like ``import``, you can write a Python function body instead of a single expression. In this case, you'll need to ``return`` a result for the value of the path field, like so: :: item_fields: filename: | import os from beets.util import bytestring_path return bytestring_path(os.path.basename(path)) You might want to use the YAML syntax for "block literals," in which a leading ``|`` character indicates a multi-line block of text. Album Fields ------------ The above examples define fields for *item* templates, but you can also define fields for *album* templates. Use the ``album_fields`` configuration section. In this context, all existing album fields are available as variables along with ``items``, which is a list of items in the album. This example defines a ``$bitrate`` field for albums as the average of the tracks' fields: :: album_fields: bitrate: | total = 0 for item in items: total += item.bitrate return total / len(items) beetbox-beets-00724b7/docs/plugins/lastimport.rst0000664000175000017500000000363715253035401021425 0ustar pieterpieterLastImport Plugin ================= The ``lastimport`` plugin downloads play-count data from your Last.fm_ library into beets' database. You can later create :doc:`smart playlists ` by querying ``lastfm_play_count`` and do other fun stuff with this field. .. _last.fm: https://www.last.fm/ Installation ------------ To use the ``lastimport`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``lastimport`` extra .. code-block:: bash pip install "beets[lastimport]" Next, add your Last.fm username to your beets configuration file: :: lastfm: user: beetsfanatic Importing Play Counts --------------------- Simply run ``beet lastimport`` and wait for the plugin to request tracks from Last.fm and match them to your beets library. (You will be notified of tracks in your Last.fm profile that do not match any songs in your library.) Then, your matched tracks will be populated with the ``lastfm_play_count`` field, which you can use in any query or template. For example: :: $ beet ls -f '$title: $lastfm_play_count' lastfm_play_count:5.. Eple (Melody A.M.): 60 To see more information (namely, the specific play counts for matched tracks), use the ``-v`` option. .. versionchanged:: 2.8.0 The ``play_count`` field was renamed to ``lastfm_play_count`` to avoid confusion with ``play_count`` field populated by :doc:`mpdstats` plugin. Configuration ------------- Aside from the required ``lastfm.user`` field, this plugin has some specific options under the ``lastimport:`` section: - **per_page**: The number of tracks to request from the API at once. Default: 500. - **retry_limit**: How many times should we re-send requests to Last.fm on failure? Default: 3. By default, the plugin will use beets's own Last.fm API key. You can also override it with your own API key: :: lastfm: api_key: your_api_key beetbox-beets-00724b7/docs/plugins/titlecase.rst0000664000175000017500000001375715253035401021210 0ustar pieterpieterTitlecase Plugin ================ The ``titlecase`` plugin lets you format tags and paths in accordance with the titlecase guidelines in the `New York Times Manual of Style`_ and uses the `python titlecase library`_. Motivation for this plugin comes from a desire to resolve differences in style between databases sources. For example, `MusicBrainz style`_ follows standard title case rules, except in the case of terms that are deemed generic, like "mix" and "remix". On the other hand, `Discogs guidelines`_ recommend capitalizing the first letter of each word, even for small words like "of" and "a". This plugin aims to achieve a middle ground between disparate approaches to casing, and bring more consistency to titles in your library. .. _discogs guidelines: https://support.discogs.com/hc/en-us/articles/360005006334-Database-Guidelines-1-General-Rules#Capitalization_And_Grammar .. _musicbrainz style: https://musicbrainz.org/doc/Style .. _new york times manual of style: https://search.worldcat.org/en/title/946964415 .. _python titlecase library: https://pypi.org/project/titlecase/ Installation ------------ To use the ``titlecase`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``titlecase`` extra: .. code-block:: bash pip install "beets[titlecase]" If you'd like to just use the path format expression, call ``%titlecase`` in your path formatter, and set ``auto`` to ``no`` in the configuration. :: paths: default: %titlecase{$albumartist}/%titlecase{$album}/$track $title You can now configure ``titlecase`` to your preference. Configuration ------------- This plugin offers several configuration options to tune its function to your preference. Default ~~~~~~~ .. code-block:: yaml titlecase: auto: yes fields: [] preserve: [] replace: [] separators: [] force_lowercase: no small_first_last: yes the_artist: yes all_lowercase: no all_caps: no after_choice: no .. conf:: auto :default: yes Whether to automatically apply titlecase to new imports. .. conf:: fields :default: [] A list of fields to apply the titlecase logic to. You must specify the fields you want to have modified in order for titlecase to apply changes to metadata. A good starting point is below, which will titlecase album titles, track titles, and all artist fields. .. code-block:: yaml titlecase: fields: - album - title - albumartist - albumartist_credit - albumartist_sort - albumartists - albumartists_credit - albumartists_sort - artist - artist_credit - artist_sort - artists - artists_credit - artists_sort .. conf:: preserve :default: [] List of words and phrases to preserve the case of. Without specifying ``DJ`` on the list, titlecase will format it as ``Dj``, or specify ``The Beatles`` to make sure ``With The Beatles`` is not capitalized as ``With the Beatles``. .. conf:: replace :default: [] The replace function takes place before any titlecasing occurs, and is intended to help normalize differences in puncuation styles. It accepts a list of tuples, with the first being the target, and the second being the replacement. An example configuration that enforces one style of quotation mark is below. .. code-block:: yaml titlecase: replace: - "’": "'" - "‘": "'" - "“": '"' - "â€�": '"' .. conf:: separators :default: [] A list of characters to treat as markers of new sentences. Helpful for split titles that might otherwise have a lowercase letter at the start of the second string. .. conf:: force_lowercase :default: no Force all strings to lowercase before applying titlecase, but can cause problems with all caps acronyms titlecase would otherwise recognize. .. conf:: small_first_last :default: yes An option from the base titlecase library. Controls capitalizing small words at the start of a sentence. With this turned off ``a`` and similar words will not be capitalized under any circumstance. .. conf:: the_artist :default: yes If a field name contains ``artist``, then any lowercase ``the`` will be capitalized. Useful for bands with ``The`` as part of the proper name, like ``Amyl and The Sniffers``. .. conf:: all_caps :default: no If the letters a-Z in a string are all caps, do not modify the string. Useful if you encounter a lot of acronyms. .. conf:: all_lowercase :default: no If the letters a-Z in a string are all lowercase, do not modify the string. Useful if you encounter a lot of stylized lowercase spellings, but otherwise want titlecase applied. .. conf:: after_choice :default: no By default, titlecase runs on the candidates that are received, adjusting them before you make your selection and creating different weight calculations. If you'd rather see the data as received from the database, set this to true to run after you make your tag choice. Dangerous Fields ~~~~~~~~~~~~~~~~ ``titlecase`` only ever modifies string fields, however, this doesn't prevent you from selecting a case sensitive field that another plugin or feature may rely on. In particular, including any of the following in your configuration could lead to unintended behavior: .. code-block:: bash acoustid_fingerprint acoustid_id artists_ids asin deezer_track_id format id isrc mb_workid mb_trackid mb_albumid mb_artistid mb_artistids mb_albumartistid mb_albumartistids mb_releasetrackid mb_releasegroupid bitrate_mode encoder_info encoder_settings Running Manually ---------------- From the command line, type: :: $ beet titlecase [QUERY] Configuration is drawn from the config file. Without a query the operation will be applied to the entire collection. beetbox-beets-00724b7/docs/plugins/types.rst0000664000175000017500000000155615253035401020371 0ustar pieterpieterTypes Plugin ============ The ``types`` plugin lets you declare types for attributes you use in your library. For example, you can declare that a ``rating`` field is numeric so that you can query it with ranges---which isn't possible when the field is considered a string (the default). Enable the ``types`` plugin as described in :doc:`/plugins/index` and then add a ``types`` section to your :doc:`configuration file `. The configuration section should map field name to one of ``int``, ``float``, ``bool``, or ``date``. Here's an example: :: types: rating: int Now you can assign numeric ratings to tracks and albums and use :ref:`range queries ` to filter them.: :: beet modify "My favorite track" rating=5 beet ls rating:4..5 beet modify --album "My favorite album" rating=5 beet ls --album rating:4..5 beetbox-beets-00724b7/docs/plugins/thumbnails.rst0000664000175000017500000000262515253035401021371 0ustar pieterpieterThumbnails Plugin ================= The ``thumbnails`` plugin creates thumbnails for your album folders with the album cover. This works on freedesktop.org-compliant file managers such as Nautilus or Thunar, and is therefore POSIX-only. To use the ``thumbnails`` plugin, enable ``thumbnails`` and :doc:`/plugins/fetchart` in your configuration (see :ref:`using-plugins`) and install ``beets`` with ``thumbnails`` and ``fetchart`` extras .. code-block:: bash pip install "beets[fetchart,thumbnails]" ``thumbnails`` need to resize the covers, and therefore requires either ImageMagick_ or Pillow_. .. _imagemagick: https://imagemagick.org/ .. _pillow: https://github.com/python-pillow/Pillow Configuration ------------- To configure the plugin, make a ``thumbnails`` section in your configuration file. The available options are - **auto**: Whether the thumbnail should be automatically set on import. Default: ``yes``. - **force**: Generate the thumbnail even when there's one that seems fine (more recent than the cover art). Default: ``no``. - **dolphin**: Generate dolphin-compatible thumbnails. Dolphin (KDE file explorer) does not respect freedesktop.org's standard on thumbnails. This functionality replaces the :doc:`/plugins/freedesktop` Default: ``no`` Usage ----- The ``thumbnails`` command provided by this plugin creates a thumbnail for albums that match a query (see :doc:`/reference/query`). beetbox-beets-00724b7/docs/plugins/albumtypes.rst0000664000175000017500000000425415253035401021410 0ustar pieterpieterAlbumTypes Plugin ================= The ``albumtypes`` plugin adds the ability to format and output album types, such as "Album", "EP", "Single", etc. For the list of available album types, see the `MusicBrainz documentation`_. To use the ``albumtypes`` plugin, enable it in your configuration (see :ref:`using-plugins`). The plugin defines a new field ``$atypes``, which you can use in your path formats or elsewhere. .. _musicbrainz documentation: https://musicbrainz.org/doc/Release_Group/Type A bug introduced in beets 1.6.0 could have possibly imported broken data into the ``albumtypes`` library field. Please follow the instructions `described here `_ for a sanity check and potential fix. :bug:`4528` Configuration ------------- To configure the plugin, make a ``albumtypes:`` section in your configuration file. The available options are: - **types**: An ordered list of album type to format mappings. The order of the mappings determines their order in the output. If a mapping is missing or blank, it will not be in the output. - **ignore_va**: A list of types that should not be output for Various Artists albums. Useful for not adding redundant information - various artist albums are often compilations. - **bracket**: Defines the brackets to enclose each album type in the output. The default configuration looks like this: :: albumtypes: types: - ep: 'EP' - single: 'Single' - soundtrack: 'OST' - live: 'Live' - compilation: 'Anthology' - remix: 'Remix' ignore_va: compilation bracket: '[]' Examples -------- With path formats configured like: :: paths: default: $albumartist/[$year]$atypes $album/... albumtype:soundtrack: Various Artists/$album [$year]$atypes/... comp: Various Artists/$album [$year]$atypes/... The default plugin configuration generates paths that look like this, for example: :: Aphex Twin/[1993][EP][Remix] On Remixes Pink Floyd/[1995][Live] p·u·l·s·e Various Artists/20th Century Lullabies [1999] Various Artists/Ocean's Eleven [2001][OST] beetbox-beets-00724b7/docs/plugins/mpdstats.rst0000664000175000017500000000746015253035401021064 0ustar pieterpieterMPDStats Plugin =============== ``mpdstats`` is a plugin for beets that collects statistics about your listening habits from MPD_. It collects the following information about tracks: - ``play_count``: The number of times you *fully* listened to this track. - ``skip_count``: The number of times you *skipped* this track. - ``last_played``: UNIX timestamp when you last played this track. - ``rating``: A rating based on ``play_count`` and ``skip_count``. To gather these statistics it runs as an MPD client and watches the current state of MPD. This means that ``mpdstats`` needs to be running continuously for it to work. .. _mpd: https://www.musicpd.org/ Installing Dependencies ----------------------- This plugin requires the python-mpd2 library in order to talk to the MPD server. To use the ``mpdstats`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``mpdstats`` extra pip install "beets[mpdstats]" Usage ----- Use the ``mpdstats`` command to fire it up: :: $ beet mpdstats Configuration ------------- To configure the plugin, make an ``mpd:`` section in your configuration file. The available options are: - **host**: The MPD server hostname. Default: The ``$MPD_HOST`` environment variable if set, falling back to ``localhost`` otherwise. - **port**: The MPD server port. Default: The ``$MPD_PORT`` environment variable if set, falling back to 6600 otherwise. - **password**: The MPD server password. Default: None. - **music_directory**: If your MPD library is at a different location from the beets library (e.g., because one is mounted on a NFS share), specify the path here. - **strip_path**: If your MPD library contains local path, specify the part to remove here. Combining this with **music_directory** you can mangle MPD path to match the beets library one. Default: The beets library directory. - **rating**: Enable rating updates. Default: ``yes``. - **rating_mix**: Tune the way rating is calculated (see below). Default: 0.75. - **played_ratio_threshold**: If a song was played for less than this percentage of its duration it will be considered a skip. Default: 0.85 A Word on Ratings ----------------- Ratings are calculated based on the *play_count*, *skip_count* and the last *action* (play or skip). It consists in one part of a *stable_rating* and in another part on a *rolling_rating*. The *stable_rating* is calculated like this: :: stable_rating = (play_count + 1.0) / (play_count + skip_count + 2.0) So if the *play_count* equals the *skip_count*, the *stable_rating* is always 0.5. More *play_counts* adjust the rating up to 1.0. More *skip_counts* adjust it down to 0.0. One of the disadvantages of this rating system, is that it doesn't really cover *recent developments*. e.g. a song that you loved last year and played over 50 times will keep a high rating even if you skipped it the last 10 times. That's were the *rolling_rating* comes in. If a song has been fully played, the *rolling_rating* is calculated like this: :: rolling_rating = old_rating + (1.0 - old_rating) / 2.0 If a song has been skipped, like this: :: rolling_rating = old_rating - old_rating / 2.0 So *rolling_rating* adapts pretty fast to *recent developments*. But it's too fast. Taking the example from above, your old favorite with 50 plays will get a negative rating (<0.5) the first time you skip it. Also not good. To take the best of both worlds, we mix the ratings together with the ``rating_mix`` factor. A ``rating_mix`` of 0.0 means all *rolling* and 1.0 means all *stable*. We found 0.75 to be a good compromise, but fell free to play with that. Warning ------- This has only been tested with MPD versions >= 0.16. It may not work on older versions. If that is the case, please report an issue_. .. _issue: https://github.com/beetbox/beets/issues beetbox-beets-00724b7/docs/plugins/scrub.rst0000664000175000017500000000330515253035401020335 0ustar pieterpieterScrub Plugin ============ The ``scrub`` plugin lets you remove extraneous metadata from files' tags. If you'd prefer never to see crufty tags that come from other tools, the plugin can automatically remove all non-beets-tracked tags whenever a file's metadata is written to disk by removing the tag entirely before writing new data. The plugin also provides a command that lets you manually remove files' tags. Automatic Scrubbing ------------------- To automatically remove files' tags before writing new ones, enable ``scrub`` plugin in your configuration (see :ref:`using-plugins`) and install ``beets`` with ``scrub`` extra .. code-block:: bash pip install "beets[scrub]" When importing new files (with ``import.write`` turned on) or modifying files' tags with the ``beet modify`` command, beets will first strip all types of tags entirely and then write the database-tracked metadata to the file. This behavior can be disabled with the ``auto`` config option (see below). Manual Scrubbing ---------------- The ``scrub`` command provided by this plugin removes tags from files and then rewrites their database-tracked metadata. To run it, just type ``beet scrub QUERY`` where ``QUERY`` matches the tracks to be scrubbed. Use this command with caution, however, because any information in the tags that is out of sync with the database will be lost. The ``-W`` (or ``--nowrite``) option causes the command to just remove tags but not restore any information. This will leave the files with no metadata whatsoever. Configuration ------------- To configure the plugin, make a ``scrub:`` section in your configuration file. There is one option: - **auto**: Enable metadata stripping during import. Default: ``yes``. beetbox-beets-00724b7/docs/plugins/convert.rst0000664000175000017500000003140515253035401020701 0ustar pieterpieterConvert Plugin ============== The ``convert`` plugin lets you convert parts of your collection to a directory of your choice, transcoding audio and embedding album art along the way. It can transcode to and from any format using a configurable command line. Optionally an m3u playlist file containing all the converted files can be saved to the destination path. Installation ------------ To use the ``convert`` plugin, first enable it in your configuration (see :ref:`using-plugins`). By default, the plugin depends on FFmpeg_ to transcode the audio, so you might want to install it. .. _ffmpeg: https://ffmpeg.org Usage ----- To convert a part of your collection, run ``beet convert QUERY``. The command will transcode all the files matching the query to the destination directory given by the ``-d`` (``--dest``) option or the ``dest`` configuration. The path layout mirrors that of your library, but it may be customized through the ``paths`` configuration. Files that have been previously converted---and thus already exist in the destination directory---will be skipped. The plugin uses a command-line program to transcode the audio. With the ``-f`` (``--format``) option you can choose the transcoding command and customize the available commands :ref:`through the configuration `. Unless the ``-y`` (``--yes``) flag is set, the command will list all the items to be converted and ask for your confirmation. The ``-a`` (or ``--album``) option causes the command to match albums instead of tracks. By default, the command places converted files into the destination directory and leaves your library pristine. To instead back up your original files into the destination directory and keep converted files in your library, use the ``-k`` (or ``--keep-new``) option. To test your configuration without taking any actions, use the ``--pretend`` flag. The plugin will print out the commands it will run instead of executing them. By default, files that do not need to be transcoded will be copied to their destination. Passing the ``-l`` (``--link``) flag creates symbolic links instead, passing ``-H`` (``--hardlink``) creates hard links. Note that album art embedding is disabled for files that are linked. Refer to the ``link`` and ``hardlink`` options below. The ``-F`` (or ``--force``) option forces transcoding even when safety options such as ``no_convert``, ``never_convert_lossy_files``, or ``max_bitrate`` would normally cause a file to be copied or skipped instead. This can be combined with ``--format`` to explicitly transcode lossy inputs to a chosen target format. The default value for this flag comes from the ``force`` configuration option. The ``-m`` (or ``--playlist``) option enables the plugin to create an m3u8 playlist file in the destination folder given by the ``-d`` (``--dest``) option or the ``dest`` configuration. The path to the playlist file can either be absolute or relative to the ``dest`` directory. The contents will always be relative paths to media files, which tries to ensure compatibility when read from external drives or on computers other than the one used for the conversion. There is one caveat though: A list generated on Unix/macOS can't be read on Windows and vice versa. Depending on the beets user's settings a generated playlist potentially could contain unicode characters. This is supported, playlists are written in `M3U8 format`_. The ``-r`` (or ``--refresh``) option allows to refresh the converted files if the originals ones are modified. It instructs the plugin to compare the timestamps of the latest modification for both the originals and the converted files. If an original file is newer than a converted file, the converted file will be removed from the filesystem, and the original file will be converted once again. Plugin Event ------------ After successfully converting or copying an item, this plugin sends the ``after_convert`` event. See :ref:`plugin_events` for its listener parameters. Configuration ------------- To configure the plugin, make a ``convert:`` section in your configuration file. The available options are: - **auto**: Import transcoded versions of your files automatically during imports. With this option enabled, the importer will transcode all (in the default configuration) non-MP3 files over the maximum bitrate before adding them to your library. Default: ``no``. - **auto_keep**: Convert your files automatically on import to **dest** but import the non transcoded version. It uses the default format you have defined in your config file. Default: ``no``. This import behavior is fixed and is not affected by ``keep_new``. .. note:: You probably want to use only one of the ``auto`` and ``auto_keep`` options, not both. Enabling both will convert your files twice on import, which you probably don't want. - **tmpdir**: The directory where temporary files will be stored during import. Default: none (system default), - **copy_album_art**: Copy album art when copying or transcoding albums matched using the ``-a`` option. Default: ``no``. - **album_art_maxwidth**: Downscale album art if it's too big. The resize operation reduces image width to at most ``maxwidth`` pixels while preserving the aspect ratio. The specified image size will apply to both embedded album art and external image files. - **dest**: The directory where the files will be converted (or copied) to. Default: none. - **embed**: Embed album art in converted items. Default: ``yes``. - **id3v23**: Can be used to override the global ``id3v23`` option. Default: ``inherit``. - **write_metadata**: Can be used to disable writing metadata to converted files. Default: ``true``. - **max_bitrate**: By default, the plugin does not transcode files that are already in the destination format. This option instead also transcodes files with high bitrates, even if they are already in the same format as the output. Note that this does not guarantee that all converted files will have a lower bitrate---that depends on the encoder and its configuration. Default: none. This option is ignored when ``force`` is enabled (via config or ``--force``). - **no_convert**: Does not transcode items matching the query string provided (see :doc:`/reference/query`). For example, to not convert AAC or WMA formats, you can use ``format:AAC, format:WMA`` or ``path::\.(m4a|wma)$``. If you only want to transcode WMA format, you can use a negative query, e.g., ``^path::\.(wma)$``, to not convert any other format except WMA. This option is ignored when ``force`` is enabled (via config or ``--force``). - **never_convert_lossy_files**: Cross-conversions between lossy codecs---such as mp3, ogg vorbis, etc.---makes little sense as they will decrease quality even further. If set to ``yes``, lossy files are always copied. Default: ``no``. When ``never_convert_lossy_files`` is enabled, lossy source files (for example MP3 or Ogg Vorbis) are normally not transcoded and are instead copied or linked as-is. To explicitly transcode lossy files in spite of this, use the ``force`` setting (from config or ``--force``) with the ``convert`` command (optionally together with ``--format`` to choose a target format) - **force**: Force transcoding by default. When enabled, items are transcoded even when ``no_convert``, ``never_convert_lossy_files``, or ``max_bitrate`` would otherwise copy or skip them. This applies to both ``beet convert`` and automatic conversion during import (``auto`` and ``auto_keep``). Default: ``false``. - **keep_new**: Enable ``--keep-new`` behavior by default for ``beet convert``. Converted files stay in your library and originals are moved to the external destination. This option applies only to ``beet convert`` and does not change ``auto_keep`` import semantics. Default: ``false``. - **paths**: The directory structure and naming scheme for the converted files. Uses the same format as the top-level ``paths`` section (see :ref:`path-format-config`). Default: Reuse your top-level path format settings. - **quiet**: Prevent the plugin from announcing every file it processes. Default: ``false``. - **threads**: The number of threads to use for parallel encoding. By default, the plugin will detect the number of processors available and use them all. - **link**: By default, files that do not need to be transcoded will be copied to their destination. This option creates symbolic links instead. Note that options such as ``embed`` that modify the output files after the transcoding step will cause the original files to be modified as well if ``link`` is enabled. For this reason, album-art embedding is disabled for files that are linked. Default: ``false``. - **hardlink**: This options works similar to ``link``, but it creates hard links instead of symlinks. This option overrides ``link``. Only works when converting to a directory on the same filesystem as the library. Default: ``false``. - **delete_originals**: Transcoded files will be copied or moved to their destination, depending on the import configuration. By default, the original files are not modified by the plugin. This option deletes the original files after the transcoding step has completed. Default: ``false``. - **playlist**: The name of a playlist file that should be written on each run of the plugin. A relative file path (e.g ``playlists/mylist.m3u8``) is allowed as well. The final destination of the playlist file will always be relative to the destination path (``dest``, ``--dest``, ``-d``). This configuration is overridden by the ``-m`` (``--playlist``) command line option. Default: none. - **refresh**: Refresh the converted files if needed by re-converting modified original files. This configuration is overridden by the ``-r`` (``--refresh``) command line option. Default: ``false``. You can also configure the format to use for transcoding (see the next section): - **format**: The name of the format to transcode to when none is specified on the command line. Default: ``mp3``. - **formats**: A set of formats and associated command lines for transcoding each. .. _convert-format-config: Configuring the transcoding command ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can customize the transcoding command through the ``formats`` map and select a command with the ``--format`` command-line option or the ``format`` configuration. :: convert: format: speex formats: speex: command: ffmpeg -i $source -y -acodec speex $dest extension: spx wav: ffmpeg -i $source -y -acodec pcm_s16le $dest In this example ``beet convert`` will use the *speex* command by default. To convert the audio to ``wav``, run ``beet convert -f wav``. This will also use the format key (``wav``) as the file extension. Each entry in the ``formats`` map consists of a key (the name of the format) as well as the command and optionally the file extension. ``extension`` is the filename extension to be used for newly transcoded files. If only the command is given as a string or the extension is not provided, the file extension defaults to the format's name. ``command`` is the command to use to transcode audio. The tokens ``$source`` and ``$dest`` in the command are replaced with the paths to the existing and new file. The plugin in comes with default commands for the most common audio formats: ``mp3``, ``alac``, ``flac``, ``aac``, ``opus``, ``ogg``, ``wma``. For details have a look at the output of ``beet config -d``. For a one-command-fits-all solution use the ``convert.command`` and ``convert.extension`` options. If these are set, the formats are ignored and the given command is used for all conversions. :: convert: command: ffmpeg -i $source -y -vn -aq 2 $dest extension: mp3 Gapless MP3 encoding ~~~~~~~~~~~~~~~~~~~~ While FFmpeg cannot produce "gapless_" MP3s by itself, you can create them by using LAME_ directly. Use a shell script like this to pipe the output of FFmpeg into the LAME tool: :: #!/bin/sh ffmpeg -i "$1" -f wav - | lame -V 2 --noreplaygain - "$2" Then configure the ``convert`` plugin to use the script: :: convert: command: /path/to/script.sh $source $dest extension: mp3 This strategy configures FFmpeg to produce a WAV file with an accurate length header for LAME to use. Using ``--noreplaygain`` disables gain analysis; you can use the :doc:`/plugins/replaygain` to do this analysis. See the LAME documentation_ and the `HydrogenAudio wiki`_ for other LAME configuration options and a thorough discussion of MP3 encoding. .. _documentation: https://sourceforge.net/projects/lame/ .. _gapless: https://wiki.hydrogenaudio.org/index.php?title=Gapless_playback .. _hydrogenaudio wiki: https://wiki.hydrogenaudio.org/index.php?title=LAME .. _lame: https://sourceforge.net/projects/lame/ .. _m3u8 format: https://en.wikipedia.org/wiki/M3U#M3U8 beetbox-beets-00724b7/docs/plugins/deezer.rst0000664000175000017500000000317015253035401020475 0ustar pieterpieterDeezer Plugin ============= The ``deezer`` plugin provides metadata matches for the importer using the Deezer_ Album_ and Track_ APIs. .. _album: https://developers.deezer.com/api/album .. _deezer: https://www.deezer.com/en/ .. _track: https://developers.deezer.com/api/track Basic Usage ----------- First, enable the ``deezer`` plugin (see :ref:`using-plugins`). You can enter the URL for an album or song on Deezer at the ``enter Id`` prompt during import: :: Enter search, enter Id, aBort, eDit, edit Candidates, plaY? i Enter release ID: https://www.deezer.com/en/album/572261 Configuration ------------- This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`. Default ~~~~~~~ .. code-block:: yaml deezer: search_query_ascii: no data_source_mismatch_penalty: 0.5 search_limit: 5 .. conf:: search_query_ascii :default: no If enabled, the search query will be converted to ASCII before being sent to Deezer. Converting searches to ASCII can enhance search results in some cases, but in general, it is not recommended. For instance, ``artist:deadmau5 album:4×4`` will be converted to ``artist:deadmau5 album:4x4`` (notice ``×!=x``). .. include:: ./shared_metadata_source_config.rst Commands -------- The ``deezer`` plugin provides an additional command ``deezerupdate`` to update the ``rank`` information from Deezer. The ``rank`` (ranges from 0 to 1M) is a global indicator of a song's popularity on Deezer that is updated daily based on streams. The higher the ``rank``, the more popular the track is. beetbox-beets-00724b7/docs/plugins/bucket.rst0000664000175000017500000000617315253035401020502 0ustar pieterpieterBucket Plugin ============= The ``bucket`` plugin groups your files into buckets folders representing *ranges*. This kind of organization can classify your music by periods of time (e.g,. *1960s*, *1970s*, etc.), or divide overwhelmingly large folders into smaller subfolders by grouping albums or artists alphabetically (e.g. *A-F*, *G-M*, *N-Z*). To use the ``bucket`` plugin, first enable it in your configuration (see :ref:`using-plugins`). The plugin provides a :ref:`template function ` called ``%bucket`` for use in path format expressions: :: paths: default: /%bucket{$year}/%bucket{$artist}/$albumartist-$album-$year Then, define your ranges in the ``bucket:`` section of the config file: :: bucket: bucket_alpha: ['A-F', 'G-M', 'N-Z'] bucket_year: ['1980s', '1990s', '2000s'] The ``bucket_year`` parameter is used for all substitutions occurring on the ``$year`` field, while ``bucket_alpha`` takes care of textual fields. The definition of a range is somewhat loose, and multiple formats are allowed: - For alpha ranges: the range is defined by the lowest and highest (ASCII-wise) alphanumeric characters in the string you provide. For example, ``ABCD``, ``A-D``, ``A->D``, and ``[AD]`` are all equivalent. - For year ranges: digits characters are extracted and the two extreme years define the range. For example, ``1975-77``, ``1975,76,77`` and ``1975-1977`` are equivalent. If no upper bound is given, the range is extended to current year (unless a later range is defined). For example, ``1975`` encompasses all years from 1975 until now. The ``%bucket`` template function guesses whether to use alpha- or year-style buckets depending on the text it receives. It can guess wrong if, for example, an artist or album happens to begin with four digits. Provide ``alpha`` as the second argument to the template to avoid this automatic detection: for example, use ``%bucket{$artist,alpha}``. Configuration ------------- To configure the plugin, make a ``bucket:`` section in your configuration file. The available options are: - **bucket_alpha**: Ranges to use for all substitutions occurring on textual fields. Default: none. - **bucket_alpha_regex**: A ``range: regex`` mapping (one per line) where ``range`` is one of the ``bucket_alpha`` ranges and ``value`` is a regex that overrides original range definition. Default: none. - **bucket_year**: Ranges to use for all substitutions occurring on the ``$year`` field. Default: none. - **extrapolate**: Enable this if you want to group your files into multiple year ranges without enumerating them all. This option will generate year bucket names by reproducing characteristics of declared buckets. Default: ``no`` Here's an example: :: bucket: bucket_year: ['2000-05'] extrapolate: true bucket_alpha: ['A - D', 'E - L', 'M - R', 'S - Z'] bucket_alpha_regex: 'A - D': ^[0-9a-dA-D…äÄ] This configuration creates five-year ranges for any input year. The ``A - D`` bucket now matches also all artists starting with ä or Ä and 0 to 9 and … (ellipsis). The other alpha buckets work as ranges. beetbox-beets-00724b7/docs/plugins/random.rst0000664000175000017500000000623615253035401020505 0ustar pieterpieterRandom Plugin ============= The ``random`` plugin provides a command that randomly selects tracks or albums from your library. This can be helpful if you need some help deciding what to listen to. First, enable the plugin named ``random`` (see :ref:`using-plugins`). You'll then be able to use the ``beet random`` command: .. code-block:: shell beet random >> Aesop Rock - None Shall Pass - The Harbor Is Yours Usage ----- The basic command selects and displays a single random track. Several options allow you to customize the selection: .. code-block:: shell Usage: beet random [options] Options: -h, --help show this help message and exit -n NUMBER, --number=NUMBER number of objects to choose -e, --equal-chance each field has the same chance -t TIME, --time=TIME total length in minutes of objects to choose --field=FIELD field to use for equal chance sampling (default: albumartist) -a, --album match albums instead of tracks -p PATH, --path=PATH print paths for matched items or albums -f FORMAT, --format=FORMAT print with custom format Detailed Options ---------------- ``-n, --number=NUMBER`` Select multiple items at once. The default is 1. ``-e, --equal-chance`` Give each distinct value of a field an equal chance of being selected. This prevents artists with many albums/tracks from dominating the selection. **Implementation note:** When this option is used, the plugin: 1. Groups items by the specified field 2. Shuffles items within each group 3. Randomly selects groups, then items from those groups 4. Continues until all groups are exhausted Items without the specified field (``--field``) value are excluded from the selection. ``--field=FIELD`` Specify which field to use for equal chance sampling. Default is ``albumartist``. ``-t, --time=TIME`` Select items whose total duration (in minutes) is approximately equal to TIME. The plugin will continue adding items until the total exceeds the requested time. ``-a, --album`` Operate on albums instead of tracks. ``-p, --path`` Output filesystem paths instead of formatted metadata. ``-f, --format=FORMAT`` Use a custom format string for output. See :doc:`/reference/query` for format syntax. Examples -------- Select multiple items: .. code-block:: shell # Select 5 random tracks beet random -n 5 # Select 3 random albums beet random -a -n 3 Control selection fairness: .. code-block:: shell # Ensure equal chance per artist (default field: albumartist) beet random -e # Ensure equal chance per genre beet random -e --field genre Select by total playtime: .. code-block:: shell # Select tracks totaling 60 minutes (1 hour) beet random -t 60 # Select albums totaling 120 minutes (2 hours) beet random -a -t 120 Custom output formats: .. code-block:: shell # Print only artist and title beet random -f '$artist - $title' # Print file paths beet random -p # Print album paths beet random -a -p beetbox-beets-00724b7/docs/plugins/lastgenre.rst0000664000175000017500000003441215253035401021206 0ustar pieterpieterLastGenre Plugin ================ The ``lastgenre`` plugin fetches *tags* from Last.fm_ and assigns them as genres to your albums and items. .. _last.fm: https://www.last.fm/ Installation ------------ To use the ``lastgenre`` plugin, first enable it in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``lastgenre`` extra .. code-block:: bash pip install "beets[lastgenre]" Usage ----- The plugin chooses genres based on a *whitelist*, meaning that only certain tags can be considered genres. This way, tags like "my favorite music" or "seen live" won't be considered genres. The plugin ships with a fairly extensive `internal whitelist`_, but you can set your own in the config file using the ``whitelist`` configuration value or forgo a whitelist altogether by setting the option to ``no``. The genre list file should contain one genre per line. Blank lines are ignored. For the curious, the default genre list is generated by a `script that scrapes Wikipedia`_. .. _internal whitelist: https://raw.githubusercontent.com/beetbox/beets/master/beetsplug/lastgenre/genres.txt .. _script that scrapes wikipedia: https://gist.github.com/sampsyo/1241307 Canonicalization ~~~~~~~~~~~~~~~~ The plugin can also *canonicalize* genres, meaning that more obscure genres can be turned into coarser-grained ones that are present in the whitelist. This works using a `tree of nested genre names`_, represented using YAML_, where the leaves of the tree represent the most specific genres. The most common way to use this would be with a custom whitelist containing only a desired subset of genres. Consider for a example this minimal whitelist: :: rock heavy metal pop together with the default genre tree. Then an item that has its genre specified as *viking metal* would actually be tagged as *heavy metal* because neither *viking metal* nor its parent *black metal* are in the whitelist. It always tries to use the most specific genre that's available in the whitelist. The relevant subtree path in the default tree looks like this: :: - rock: - heavy metal: - black metal: - viking metal Considering that, it's not very useful to use the default whitelist (which contains about any genre contained in the tree) with canonicalization because nothing would ever be matched to a more generic node since all the specific subgenres are in the whitelist to begin with. If you use canonicalization *without* a whitelist, the plugin will simply map every genre to its top-most root category in the tree (e.g., ``Viking Metal`` → ``Rock``). This is a great way to keep your library broad without needing to maintain a manual list of allowed genres. .. _tree of nested genre names: https://raw.githubusercontent.com/beetbox/beets/master/beetsplug/lastgenre/genres-tree.yaml .. _yaml: https://yaml.org/ Genre Source ~~~~~~~~~~~~ When looking up genres for albums or individual tracks, you can choose whether to use Last.fm tags on the album, the artist, or the track. For example, you might want all the albums for a certain artist to carry the same genre. The default is "album". When set to "track", the plugin will fetch *both* album-level and track-level genres for your music when importing albums. Multiple Genres ~~~~~~~~~~~~~~~ By default, the plugin chooses the most popular tag on Last.fm as a genre. If you prefer to use a *list* of popular genre tags, you can increase the number of the ``count`` config option. Lists of up to *count* genres will be stored in the ``genres`` field as a list and written to your media files as separate genre tags. Last.fm_ provides a popularity factor, a.k.a. *weight*, for each tag ranging from 100 for the most popular tag down to 0 for the least popular. The plugin uses this weight to discard unpopular tags. The default is to ignore tags with a weight less then 10. You can change this by setting the ``min_weight`` config option. Specific vs. Popular Genres ~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, the plugin sorts genres by popularity. However, you can use the ``prefer_specific`` option to override this behavior and instead sort genres by specificity, as determined by your whitelist and canonicalization tree. For instance, say you have both ``folk`` and ``americana`` in your whitelist and canonicalization tree and ``americana`` is a leaf within ``folk``. If Last.fm returns both of those tags, lastgenre is going to use the most popular, which is often the most generic (in this case ``folk``). By setting ``prefer_specific`` to true, lastgenre would use ``americana`` instead. Handling pre-populated tags ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``force``, ``keep_existing`` and ``whitelist`` options control how pre-existing genres are handled. As you would assume, setting ``force: no`` **won't touch pre-existing genre tags** and will only **fetch new genres for empty tags**. When ``force`` is ``yes`` the setting of the ``whitelist`` option (as documented in Usage_) applies to any existing or newly fetched genres. The following configurations are possible: **Setup 1** (default) Add new last.fm genres when **empty**. Any present tags stay **untouched**. .. code-block:: yaml force: no keep_existing: no **Setup 2** **Overwrite all**. Only fresh last.fm genres remain. .. code-block:: yaml force: yes keep_existing: no **Setup 3** **Combine** genres in present tags with new ones (be aware of that with an enabled ``whitelist`` setting, of course some genres might get cleaned up - existing genres take precedence over new ones though. To make sure any existing genres remain, set ``whitelist: no``). .. code-block:: yaml force: yes keep_existing: yes .. attention:: If ``force`` is disabled the ``keep_existing`` option is simply ignored (since ``force: no`` means ``not touching`` existing tags anyway). Genre Ignorelist ---------------- Last.fm tags are crowd-sourced, so they can be wrong — especially for artists whose names are shared with or confused with others. For example, a "Drum And Bass" artist named "Fracture" might incorrectly receive "Metal" tags. The ignorelist lets you reject specific genres globally or per-artist. Another example for the ignorelist is to exclude genres that are technically correct but not useful to you. For example, you might want to exclude "Ska" for "Bob Marley", even though it is a valid genre for his music. Filtering is done in two places: when fetching genres from Last.fm and when resolving to a final genre list (during canonicalization and whitelisting). This means that existing genres are also filtered when ``force`` and ``keep_existing`` options are enabled (or ``cleanup_existing`` is enabled with ``force`` disabled). To enable this feature, add an ``ignorelist`` section to your ``lastgenre`` configuration: .. code-block:: yaml lastgenre: ignorelist: fracture: - ^(heavy|black|power|death)?\s?(metal|rock)$|\w+-metal\d*$ - progressive metal bob marley: - ska '*': - electronic A combination of regex patterns and plain genre names is possible. The ``'*'`` key applies globally to all artists — use it to block genres you never want, regardless of artist. Patterns are matched against the full genre string, so a plain ``metal`` will not match ``heavy metal`` unless you write a regex like ``.*metal``. .. attention:: - The global key ``'*'`` **must** be surrounded by single quotes so that YAML does not interpret it as an anchor. - Any regex pattern that starts with a special YAML character (``[``, ``*``, or ``:``) or ends with ``:`` **must** be surrounded by quotes. - Prefer **single quotes** (``'...'``) when quoting is necessary, as they treat backslashes literally (no double-escaping required). - Because the ignorelist uses plain YAML, you do **not** need to double-escape backslashes in unquoted or single-quoted strings (e.g., use ``\w``, not ``\\w``). Genre Normalization (Aliases) ----------------------------- Last.fm tags often contain variant spellings, abbreviations, or inconsistent formatting (e.g., "hip-hop", "hiphop", and "hip hop"). The normalization feature uses an ordered list of regular expression aliases to map these variants to a single canonical name *before* any other filtering or canonicalization takes place. This feature is enabled by default and uses a built-in alias table that covers many common cases, such as mapping "dnb" to "drum and bass" or "r&b" to "rhythm and blues". Set ``aliases: no`` to turn it off entirely. You can replace these aliases with your own by setting ``aliases`` to an inline mapping in your configuration. The keys are the canonical genre names (which support ``\1`` / ``\g`` back-references to regex capture groups) and the values are lists of regex patterns. .. note:: The same formatting and quoting rules regarding YAML special characters and backslashes mentioned in the **Attention** box in the **Genre Ignorelist** section apply here as well. The full default mappings are shown below - copy and paste this into your config below the ``lastgenre.aliases`` section to customize it: .. literalinclude:: ../../beetsplug/lastgenre/aliases.yaml :language: yaml Choosing the Right Tool ----------------------- With multiple ways to filter and map genres, here is a quick guide on when to use what: - **Aliases**: Use these first to fix spelling variants and abbreviations (e.g., ``dnb`` → ``drum and bass``). - **Ignorelist**: Use this for error correction when Last.fm results are not accurate, or for precise per-artist or global exclusions (e.g., rejecting ``Metal`` for specific electronic artists). - **Canonicalization**: Use this to automatically map specific sub-genres to broader categories (e.g., ``Grindcore`` → ``Metal``). - **Whitelist**: Use this to finally limit your library to a predefined set of genres. When combined with canonicalization, the plugin will try to map a sub-genre to its closest whitelisted parent. Anything else is dropped. Configuration ------------- To configure the plugin, make a ``lastgenre:`` section in your configuration file. Default configuration: .. code-block:: yaml lastgenre: auto: yes canonical: no cleanup_existing: no count: 1 fallback: null force: no keep_existing: no min_weight: 10 prefer_specific: no source: album whitelist: yes title_case: yes ignorelist: no aliases: yes The available options are: - **auto**: Fetch genres automatically during import. Default: ``yes``. - **canonical**: Use a canonicalization tree. Setting this to ``yes`` will use a built-in tree. You can also set it to a path, like the ``whitelist`` config value, to use your own tree. Default: ``no`` (disabled). - **cleanup_existing**: This option only takes effect with ``force: no``, Setting this to ``yes`` will result in cleanup of existing genres. That includes canonicalization and whitelisting, if enabled. If no matching genre can be determined, the ``fallback`` is used instead. Default: ``no`` (disabled). - **count**: Number of genres to fetch. Default: 1 - **fallback**: A string to use as a fallback genre when no genre is found ``or`` the original genre is not desired to be kept (``keep_existing: no``). You can use the empty string ``''`` to reset the genre. Default: None. - **force**: By default, lastgenre will fetch new genres for empty tags only, enable this option to always try to fetch new last.fm genres. Enable the ``keep_existing`` option to combine existing and new genres. (see `Handling pre-populated tags`_). Default: ``no``. - **keep_existing**: This option alters the ``force`` behavior. If both ``force`` and ``keep_existing`` are enabled, existing genres are combined with new ones. Depending on the ``whitelist`` setting, existing and new genres are filtered accordingly. To ensure only fresh last.fm genres, disable this option. (see `Handling pre-populated tags`_) Default: ``no``. - **min_weight**: Minimum popularity factor below which genres are discarded. Default: 10. - **prefer_specific**: Sort genres by the most to least specific, rather than most to least popular. Note that this option requires a ``canonical`` tree, and if not configured it will automatically enable and use the built-in tree. Default: ``no``. - **source**: Which entity to look up in Last.fm. Can be either ``artist``, ``album`` or ``track``. Default: ``album``. - **whitelist**: The filename of a custom genre list, ``yes`` to use the internal whitelist, or ``no`` to consider all genres valid. Default: ``yes``. - **title_case**: Convert the new tags to TitleCase before saving. Default: ``yes``. - **ignorelist**: A mapping of artist names (or the global ``'*'`` key) to lists of genres to exclude. See `Genre Ignorelist`_ for more details. Default: ``no``. - **aliases**: Controls genre alias normalization. Set to ``yes`` (default) to use the built-in alias table, ``no`` to disable normalization entirely, or an inline mapping of canonical genre names to lists of regex patterns to replace the built-in table with your own. See `Genre Normalization (Aliases)`_ for details. Running Manually ---------------- In addition to running automatically on import, the plugin can also be run manually from the command line. Use the command ``beet lastgenre [QUERY]`` to fetch genres for albums or items matching a certain query. By default, ``beet lastgenre`` matches albums. To match individual tracks or singletons, use the ``-A`` switch: ``beet lastgenre -A [QUERY]``. To preview the changes that would be made without applying them, use the ``-p`` or ``--pretend`` flag. This shows which genres would be set but does not write or store any changes. To disable automatic genre fetching on import, set the ``auto`` config option to false. Tuning Logs ----------- To enable tuning logs, run ``beet -vvv lastgenre ...`` or ``beet -vvv import ...``. This enables additional messages at the ``DEBUG`` log level, showing for example what data was received from last.fm at each stage of genre fetching (artist, album, and track levels) before any canonicalization or whitelist filtering is applied. Tuning logs are useful for adjusting the plugin’s settings and understanding its behavior, though they can be quite verbose. beetbox-beets-00724b7/docs/plugins/edit.rst0000664000175000017500000000520415253035401020144 0ustar pieterpieterEdit Plugin =========== The ``edit`` plugin lets you modify music metadata using your favorite text editor. Enable the ``edit`` plugin in your configuration (see :ref:`using-plugins`) and then type: :: beet edit QUERY Your text editor (i.e., the command in your ``$VISUAL`` or ``$EDITOR`` environment variable) will open with a list of tracks to edit. Make your changes and exit your text editor to apply them to your music. Command-Line Options -------------------- The ``edit`` command has these command-line options: - ``-a`` or ``--album``: Edit albums instead of individual items. - ``-f FIELD`` or ``--field FIELD``: Specify an additional field to edit (in addition to the defaults set in the configuration). - ``--all``: Edit *all* available fields. Interactive Usage ----------------- The ``edit`` plugin can also be invoked during an import session. If enabled, it adds two new options to the user prompt: :: [A]pply, More candidates, Skip, Use as-is, as Tracks, Group albums, Enter search, enter Id, aBort, eDit, edit Candidates? - ``eDit``: use this option for using the original items' metadata as the starting point for your edits. - ``edit Candidates``: use this option for using a candidate's metadata as the starting point for your edits. When editing an album during import (i.e., after you have chosen ``eDit`` or ``edit Candidates`` for an album import), the fields listed in ``albumfields`` are shown as a YAML header section before the per-track documents. This allows you to edit album-level fields (such as ``album``, ``albumartist``, or any configured ``albumfields`` entry) for all tracks at once. Fields accepted into the album header are omitted from the per-track documents. Fields unsuitable for the header remain per-track when also configured in ``itemfields``. Also, please be aware that the ``edit Candidates`` choice can only be used with the matches found during the initial search (and currently not supporting the candidates found via the ``Enter search`` or ``enter Id`` choices). You might find the ``--search-id SEARCH_ID`` :ref:`import-cmd` option useful for those cases where you already have a specific candidate ID that you want to edit. Configuration ------------- To configure the plugin, make an ``edit:`` section in your configuration file. The available options are: - **itemfields**: A space-separated list of item fields to include in the editor by default. Default: ``track title artist album`` - **albumfields**: The same when editing albums (with the ``-a`` option). Default: ``album albumartist``. These fields are also shown as a YAML header during interactive import when editing an album import. beetbox-beets-00724b7/docs/plugins/the.rst0000664000175000017500000000316315253035401020001 0ustar pieterpieterThe Plugin ========== The ``the`` plugin allows you to move patterns in path formats. It's suitable, for example, for moving articles from string start to the end. This is useful for quick search on filesystems and generally looks good. Plugin does not change tags. By default plugin supports English "the, a, an", but custom regexp patterns can be added by user. How it works: :: The Something -> Something, The A Band -> Band, A An Orchestra -> Orchestra, An To use the ``the`` plugin, enable it (see :doc:`/plugins/index`) and then use a template function called ``%the`` in path format expressions: :: paths: default: %the{$albumartist}/($year) $album/$track $title The default configuration moves all English articles to the end of the string, but you can override these defaults to make more complex changes. Configuration ------------- To configure the plugin, make a ``the:`` section in your configuration file. The available options are: - **a**: Handle "A/An" moves. Default: ``yes``. - **the**: handle "The" moves. Default: ``yes``. - **patterns**: Custom regexp patterns, space-separated. Custom patterns are case-insensitive regular expressions. Patterns can be matched anywhere in the string (not just the beginning), so use ``^`` if you intend to match leading words. Default: ``[]``. - **strip**: Remove the article altogether instead of moving it to the end. Default: ``no``. - **format**: A Python format string for the output. Use ``{0}`` to indicate the part without the article and ``{1}`` for the article. Spaces are already trimmed from ends of both parts. Default: ``'{0}, {1}'``. beetbox-beets-00724b7/docs/plugins/mbpseudo.rst0000664000175000017500000000706315253035401021042 0ustar pieterpieterMusicBrainz Pseudo-Release Plugin ================================= The ``mbpseudo`` plugin can be used *instead of* the ``musicbrainz`` plugin to search for MusicBrainz pseudo-releases_ during the import process, which are added to the normal candidates from the MusicBrainz search. .. _pseudo-releases: https://musicbrainz.org/doc/Style/Specific_types_of_releases/Pseudo-Releases This is useful for releases whose title and track titles are written with a script_ that can be translated or transliterated into a different one. .. _script: https://en.wikipedia.org/wiki/ISO_15924 Pseudo-releases will only be included if the initial search in MusicBrainz returns releases whose script is *not* desired and whose relationships include pseudo-releases with desired scripts. Configuration ------------- Since this plugin first searches for official releases from MusicBrainz, all options from the ``musicbrainz`` plugin's :ref:`musicbrainz-config` are supported, but they must be specified under ``mbpseudo`` in the configuration file. Additionally, the configuration expects an array of scripts that are desired for the pseudo-releases. For ``artist`` in particular, keep in mind that even pseudo-releases might specify it with the original script, so you should also configure import :ref:`languages` to give artist aliases more priority. Therefore, the minimum configuration for this plugin looks like this: .. code-block:: yaml plugins: mbpseudo # remove musicbrainz import: languages: en mbpseudo: scripts: - Latn Note that the ``search_limit`` configuration applies to the initial search for official releases, and that the ``data_source`` in the database will be "MusicBrainz". Nevertheless, ``data_source_mismatch_penalty`` must also be specified under ``mbpseudo`` if desired (see also :ref:`metadata-source-plugin-configuration`). An example with multiple data sources may look like this: .. code-block:: yaml plugins: mbpseudo deezer import: languages: en mbpseudo: data_source_mismatch_penalty: 0 scripts: - Latn deezer: data_source_mismatch_penalty: 0.2 By default, the data from the pseudo-release will be used to create a proposal that is independent from the official release and sets all properties in its metadata. It's possible to change the configuration so that some information from the pseudo-release is instead added as custom tags, keeping the metadata from the official release: .. code-block:: yaml mbpseudo: # other config not shown custom_tags_only: yes The default custom tags with this configuration are specified as mappings where the keys define the tag names and the values define the pseudo-release property that will be used to set the tag's value: .. code-block:: yaml mbpseudo: album_custom_tags: album_transl: album album_artist_transl: artist track_custom_tags: title_transl: title artist_transl: artist Note that the information for each set of custom tags corresponds to different metadata levels (album or track level), which is why ``artist`` appears twice even though it effectively references album artist and track artist respectively. If you want to modify any mapping under ``album_custom_tags`` or ``track_custom_tags``, you must specify *everything* for that set of tags in your configuration file because any customization replaces the whole dictionary of mappings for that level. .. note:: These custom tags are also added to the music files, not only to the database. beetbox-beets-00724b7/docs/plugins/chroma.rst0000664000175000017500000001656115253035401020500 0ustar pieterpieterChromaprint/Acoustid Plugin =========================== Acoustic fingerprinting is a technique for identifying songs from the way they "sound" rather from their existing metadata. That means that beets' autotagger can theoretically use fingerprinting to tag files that don't have any ID3 information at all (or have completely incorrect data). This plugin uses an open-source fingerprinting technology called Chromaprint_ and its associated Web service, called Acoustid_. .. _acoustid: https://acoustid.org/ .. _chromaprint: https://acoustid.org/chromaprint Turning on fingerprinting can increase the accuracy of the autotagger---especially on files with very poor metadata---but it comes at a cost. First, it can be trickier to set up than beets itself (you need to set up the native fingerprinting library, whereas all of the beets core is written in pure Python). Also, fingerprinting takes significantly more CPU and memory than ordinary tagging---which means that imports will go substantially slower. If you're willing to pay the performance cost for fingerprinting, read on! Installing Dependencies ----------------------- To get fingerprinting working, you'll need to install three things: 1. pyacoustid_ Python library (version 0.6 or later). You can install it by installing ``beets`` with ``chroma`` extra .. code-block:: bash pip install "beets[chroma]" 2. the Chromaprint_ library_ or |command-line-tool|_ 3. an |audio-decoder|_ .. |command-line-tool| replace:: command line tool .. |audio-decoder| replace:: audio decoder .. _command-line-tool: Installing the Binary Command-Line Tool ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The simplest way to get up and running, especially on Windows, is to download_ the appropriate Chromaprint binary package and place the ``fpcalc`` (or ``fpcalc.exe``) on your shell search path. On Windows, this means something like ``C:\\Program Files``. On OS X or Linux, put the executable somewhere like ``/usr/local/bin``. .. _download: https://acoustid.org/chromaprint .. _library: Installing the Library ~~~~~~~~~~~~~~~~~~~~~~ On OS X and Linux, you can also use a library installed by your package manager, which has some advantages (automatic upgrades, etc.). The Chromaprint site has links to packages for major Linux distributions. If you use Homebrew_ on Mac OS X, you can install the library with ``brew install chromaprint``. .. _audio-decoder: .. _homebrew: https://brew.sh/ Audio Decoder ~~~~~~~~~~~~~ You will also need a mechanism for decoding audio files supported by the audioread_ library: - OS X has a number of decoders already built into Core Audio, so there's no need to install anything. - On Linux, you can install GStreamer_ with PyGObject_, FFmpeg_, or MAD_ with pymad_. How you install these will depend on your distribution. For example, on Ubuntu, run ``apt-get install gstreamer1.0 python-gi``. On Arch Linux, you want ``pacman -S gstreamer python2-gobject``. If you use GStreamer, be sure to install its codec plugins also (``gst-plugins-good``, etc.). Note that if you install beets in a virtualenv, you'll need it to have ``--system-site-packages`` enabled for Python to see the GStreamer bindings. - On Windows, builds are provided by GStreamer_ .. _audioread: https://github.com/beetbox/audioread .. _core audio: https://developer.apple.com/documentation/coreaudio .. _ffmpeg: https://ffmpeg.org/ .. _gstreamer: https://gstreamer.freedesktop.org/ .. _mad: https://www.underbit.com/products/mad/ .. _pyacoustid: https://github.com/beetbox/pyacoustid .. _pygobject: https://wiki.gnome.org/Projects/PyGObject .. _pymad: https://spacepants.org/src/pymad/ To decode audio formats (MP3, FLAC, etc.) with GStreamer, you'll need the standard set of Gstreamer plugins. For example, on Ubuntu, install the packages ``gstreamer1.0-plugins-good``, ``gstreamer1.0-plugins-bad``, and ``gstreamer1.0-plugins-ugly``. Usage ----- Once you have all the dependencies sorted out, enable the ``chroma`` plugin in your configuration (see :ref:`using-plugins`) to benefit from fingerprinting the next time you run ``beet import``. (The plugin doesn't produce any obvious output by default. If you want to confirm that it's enabled, you can try running in verbose mode once with ``beet -v import``.) You can also use the ``beet fingerprint`` command to generate fingerprints for items already in your library. (Provide a query to fingerprint a subset of your library.) The generated fingerprints will be stored in the library database. If you have the ``import.write`` config option enabled, they will also be written to files' metadata. .. note:: The ``chroma`` plugin turns Acoustid fingerprint matches into autotagger candidates by resolving them through the :doc:`musicbrainz` plugin, so you need to enable ``musicbrainz`` alongside ``chroma`` to get album and track candidates from acoustid lookups. If ``musicbrainz`` is not enabled, the ``chroma`` plugin will still fingerprint your files and store the ``acoustid_id`` and ``acoustid_fingerprint`` fields, but it will not contribute candidates during autotagging. .. _submitfp: Configuration ------------- There is one configuration option in the ``chroma:`` section, ``auto``, which controls whether to fingerprint files during the import process. To disable fingerprint-based autotagging, set it to ``no``, like so: :: chroma: auto: no Submitting Fingerprints ----------------------- You can help expand the Acoustid_ database by submitting fingerprints for the music in your collection. To do this, first `get an API key`_ from the Acoustid service. Just use an OpenID or MusicBrainz account to log in and you'll get a short token string. Then, add the key to your ``config.yaml`` as the value ``apikey`` in a section called ``acoustid`` like so: :: acoustid: apikey: AbCd1234 Then, run ``beet submit``. (You can also provide a query to submit a subset of your library.) The command will use stored fingerprints if they're available; otherwise it will fingerprint each file before submitting it. .. _get an api key: https://acoustid.org/api-key Fingerprint Search ------------------ The ``chromasearch`` command lets you search your local beets library for tracks with similar audio fingerprints. This is useful for identifying duplicate files, finding alternate encodings of the same recording, or locating tracks when metadata is missing or incorrect. To perform a search, run: .. code-block:: shell beet chromasearch -s FINGERPRINT The fingerprint must be provided using the ``-s`` (``--search``) option. You can generate a fingerprint using the external ``fpcalc`` tool from the Chromaprint_ project. For example: .. code-block:: shell fpcalc -plain somefile.mp3 By default the whole library is searched, use a :doc:`query ` to restrict the search: .. code-block:: shell beet chromasearch -s FINGERPRINT artist:"rolling stones" By default, the command returns the top 5 closest matches in your library. You can change the number of results using the ``-c`` (``--count``) option. When an exact match is found, the search normally stops early. To continue searching for additional similar items even after an exact match, use the ``--full`` flag. The ``-w`` (``--write``) option causes the plugin to store fingerprints for files that do not already have them. This can improve search results over time by ensuring more items in your library are indexed. beetbox-beets-00724b7/docs/plugins/rewrite.rst0000664000175000017500000000440415253035401020701 0ustar pieterpieterRewrite Plugin ============== The ``rewrite`` plugin lets you easily substitute values in your templates and path formats. Specifically, it is intended to let you *canonicalize* names such as artists: for example, perhaps you want albums from The Jimi Hendrix Experience to be sorted into the same folder as solo Hendrix albums. To use field rewriting, first enable the ``rewrite`` plugin (see :ref:`using-plugins`). Then, make a ``rewrite:`` section in your config file to contain your rewrite rules. Each rule consists of a field name, a regular expression pattern, and a replacement value. Rules are written ``fieldname regex: replacement``. For example, this line implements the Jimi Hendrix example above: :: rewrite: artist The Jimi Hendrix Experience: Jimi Hendrix This will make ``$artist`` in your templates expand to "Jimi Hendrix" where it would otherwise be "The Jimi Hendrix Experience". The pattern is a case-insensitive regular expression. This means you can use ordinary regular expression syntax to match multiple artists. For example, you might use: :: rewrite: artist .*jimi hendrix.*: Jimi Hendrix Rules also apply to matching elements in multi-valued fields. For example, this rewrites the ``rock`` entry in ``genres`` while leaving other genre values unchanged: :: rewrite: genres rock: Classic Rock Rules are applied in the order they appear in the config. This means a multi-valued field can have several entries rewritten by different rules: :: rewrite: genres rock: Classic Rock genres pop: Pop With this configuration, a ``genres`` value such as ``rock; pop; techno`` is rewritten to ``Classic Rock; Pop; techno``. As a convenience, the plugin applies patterns for the ``artist`` field to the ``albumartist`` field as well. (Otherwise, you would probably want to duplicate every rule for ``artist`` and ``albumartist``.) A word of warning: This plugin theoretically only applies to templates and path formats; it initially does not modify files' metadata tags or the values tracked by beets' library database, but since it *rewrites all field lookups*, it modifies the file's metadata anyway. See comments in issue :bug:`2786`. As an alternative to this plugin the :doc:`/plugins/substitute` could be used. beetbox-beets-00724b7/docs/plugins/listenbrainz.rst0000664000175000017500000000310715253035401021723 0ustar pieterpieter.. _listenbrainz: ListenBrainz Plugin =================== The ListenBrainz plugin for beets allows you to interact with the ListenBrainz service. Configuration ------------- To enable the ListenBrainz plugin, add the following to your beets configuration file (config.yaml_): .. code-block:: yaml plugins: - listenbrainz You can then configure the plugin by providing your Listenbrainz token (see intructions here_) and username: :: listenbrainz: token: TOKEN username: LISTENBRAINZ_USERNAME Usage ----- Once the plugin is enabled, you can import the listening history using the ``lbimport`` command in beets. The command has two command-line options: - To import the listening history from a ListenBrainz export file, use the ``-f`` (``--export-file``) flag followed by the path to the export file. - To limit the number of listens fetched via the API during import, the ``--max`` flag can be used. By default, the plugin will fetch all listens. This option will be ignored when an export file is provided. Matched tracks are populated with the ``listenbrainz_play_count`` field, which you can use in queries and templates. For example: :: $ beet ls -f '$title: $listenbrainz_play_count' listenbrainz_play_count:1.. This field is separate from ``lastfm_play_count`` used by :doc:`lastimport` and ``play_count`` used by :doc:`mpdstats`, so importing play counts from one plugin does not overwrite the others. .. _config.yaml: ../reference/config.rst .. _here: https://listenbrainz.readthedocs.io/en/latest/users/api/index.html#get-the-user-token beetbox-beets-00724b7/docs/plugins/playlist.rst0000664000175000017500000000453115253035401021062 0ustar pieterpieterPlaylist Plugin =============== ``playlist`` is a plugin to use playlists in m3u format. To use it, enable the ``playlist`` plugin in your configuration (see :ref:`using-plugins`). Then configure your playlists like this: :: playlist: auto: no relative_to: ~/Music playlist_dir: ~/.mpd/playlists forward_slash: no It is possible to query the library based on a playlist by specifying its absolute path: :: $ beet ls playlist:/path/to/someplaylist.m3u The plugin also supports referencing playlists by name. The playlist is then searched in the playlist_dir and the ".m3u" extension is appended to the name: :: $ beet ls playlist:anotherplaylist A playlist query will use the paths found in the playlist file to match items in the beets library. ``playlist:`` submits a regular beets :ref:`query ` similar to a :ref:`specific fields query `. If you want the list in any particular order, you can use the standard beets query syntax for :ref:`sorting `: :: $ beet ls playlist:/path/to/someplaylist.m3u artist+ year+ Playlist queries do not reflect the original order in the m3u file. The plugin can also update playlists in the playlist directory automatically every time an item is moved or deleted. This can be controlled by the ``auto`` configuration option. Configuration ------------- To configure the plugin, make a ``playlist:`` section in your configuration file. In addition to the ``playlists`` described above, the other configuration options are: - **auto**: If this is set to ``yes``, then anytime an item in the library is moved or removed, the plugin will update all playlists in the ``playlist_dir`` directory that contain that item to reflect the change. Default: ``no`` - **playlist_dir**: Where to read playlist files from. Default: The current working directory (i.e., ``'.'``). - **relative_to**: Interpret paths in the playlist files relative to a base directory. Instead of setting it to a fixed path, it is also possible to set it to ``playlist`` to use the playlist's parent directory or to ``library`` to use the library directory. Default: ``library`` - **forward_slash**: Forces forward slashes in the generated playlist files. If you intend to use this plugin to generate playlists for MPD on Windows, set this to yes. Default: Use system separator. beetbox-beets-00724b7/docs/plugins/musicbrainz.rst0000664000175000017500000001115515253035401021547 0ustar pieterpieterMusicBrainz Plugin ================== The ``musicbrainz`` plugin extends the autotagger's search capabilities to include matches from the MusicBrainz_ database. .. _musicbrainz: https://musicbrainz.org/ Installation ------------ To use the ``musicbrainz`` plugin, enable it in your configuration (see :ref:`using-plugins`) .. _musicbrainz-config: Configuration ------------- This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`. Default ~~~~~~~ .. code-block:: yaml musicbrainz: host: musicbrainz.org https: no ratelimit: 1 ratelimit_interval: 1.0 extra_tags: [] genres: no genres_tag: genre external_ids: discogs: no bandcamp: no spotify: no deezer: no beatport: no tidal: no data_source_mismatch_penalty: 0.5 search_limit: 5 aliases_as_credits: no .. conf:: host :default: musicbrainz.org The Web server hostname (and port, optionally) that will be contacted by beets. You can use this to configure beets to use `your own MusicBrainz database `__ instead of the `main server`_. The server must have search indices enabled (see `Building search indexes`_). Example: .. code-block:: yaml musicbrainz: host: localhost:5000 .. conf:: https :default: no Makes the client use HTTPS instead of HTTP. This setting applies only to custom servers. The official MusicBrainz server always uses HTTPS. .. conf:: ratelimit :default: 1 Controls the number of Web service requests per second. This setting applies only to custom servers. The official MusicBrainz server enforces a rate limit of 1 request per second. .. conf:: ratelimit_interval :default: 1.0 The time interval (in seconds) for the rate limit. Only applies to custom servers. .. conf:: enabled :default: yes .. deprecated:: 2.4 Add ``musicbrainz`` to the ``plugins`` list instead. .. conf:: extra_tags :default: [] By default, beets will use only the album and either artist or the MusicBrainz Various Artists ID to query MusicBrainz. Additional tags, including track count, can be queried by using the ``extra_tags`` setting. This setting should improve the autotagger results if the metadata with the given tags match the metadata returned by MusicBrainz. Tags supported by this setting: * ``alias`` (also search for release aliases matching the query) * ``barcode`` * ``catalognum`` * ``country`` * ``label`` * ``media`` * ``tracks`` (number of tracks on the release) * ``year`` Example: .. code-block:: yaml musicbrainz: extra_tags: [alias, barcode, catalognum, country, label, media, tracks, year] .. conf:: genres :default: no Use MusicBrainz genre tags to populate (and replace if it's already set) the ``genre`` tag. This will make it a list of all the genres tagged for the release and the release-group on MusicBrainz, separated by "; " and sorted by the total number of votes. .. conf:: external_ids **Default** .. code-block:: yaml musicbrainz: external_ids: discogs: no spotify: no bandcamp: no beatport: no deezer: no tidal: no Set any of the ``external_ids`` options to ``yes`` to enable the MusicBrainz importer to look for links to related metadata sources. If such a link is available the release ID will be extracted from the URL provided and imported to the beets library. The library fields of the corresponding :ref:`autotagger_extensions` are used to save the data as flexible attributes (``discogs_album_id``, ``bandcamp_album_id``, ``spotify_album_id``, ``beatport_album_id``, ``deezer_album_id``, ``tidal_album_id``). On re-imports existing data will be overwritten. .. conf:: genres_tag :default: genre Either ``genre`` or ``tag``. Specify ``genre`` to use just musicbrainz genre and ``tag`` to use all user-supplied musicbrainz tags. .. conf:: aliases_as_credits :default: no Use the "aliases" data from MusicBrainz as the value for ``*_credit`` fields. .. include:: ./shared_metadata_source_config.rst .. _building search indexes: https://wiki.musicbrainz.org/History:Development/Search_server_setup .. _limited: https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting .. _main server: https://musicbrainz.org/ beetbox-beets-00724b7/docs/modd.conf0000664000175000017500000000012115253035401016567 0ustar pieterpieter**/*.rst { prep: make html } _build/html/** { daemon: devd -m _build/html } beetbox-beets-00724b7/docs/_static/0000775000175000017500000000000015253035401016431 5ustar pieterpieterbeetbox-beets-00724b7/docs/_static/beets_logo_nobg.png0000664000175000017500000002635615253035401022302 0ustar pieterpieter‰PNG  IHDRññËQ pHYsgŸÒR IDATxí} xTU–ÿÉJB!„-„€�FYdy…ˆ¨ ¶�6nñß.ðµÝ­Žmw›Ô§ú¹àLk£Ì×.ô¨#(Ú(öÈPOqd[�„ì�9§’Wuï«JR•ÚÞ{uî÷UêÞûî{ïÞß©_îvι1MMMÀ�`Ì‹@¬y«Î5gB€IÌ¿FÀä0‰}`yy¹âcQ.Æ„&±p?ÿüóÊ€O>ù¤âCq.„�^Øjïï¾ûN¹ë®»”cÇŽåk¥Þÿ}Û‚ T-Íߌ@¤àž¸ ÄÇǃH`*ºpáBÇæÍ›•6nãKŒ@Xàž¸¸ûõëW 'r¯^½`Û¶m6üVÛ¹�/3!G€{âv ¾ãŽ;#JxuÚGtû÷ï_PRRâÚ/Öß†Ê °eË[ff¦ª¿ÆiF ”pOì#ºwÞy§\R‡\qq1`�­È…8Å„ÝO1ô/4ëô«Ô1ˆ\çÁrkTUÍ_¼x±"çrŠ-Lbñ=z´š››ëZ¥njHÎèÔG~Ào¼áxë­·9—SŒ@è`û�­~H]] Ðã&€ø4ù!Ø;°WVä\N1¡A€Iì®úUꚀ˜8$òÍø�à~Pcc#à¶”ãðáÊ;—cŒ@h`û�«·!uÍ€Ä €ÌiòƒÎœ9ê™2$œ Lb?�Õ©/l~@J.@úXùa¸wœ?wî\EÎå#\˜Ä~â©R×–\nh~H×Q)WÊ\³f�ãOú“"çZ7UYY© Fd‹mÝV¬e¤qÄÿ08p`бIûàPº©ÿ#ÍŸœ‡ )±‡ûšVæƒ>P¬Ž3î•+W]u•´ÅnZ¾|¹åÛl™rOŒ,ó7x ©¹Ÿ� ]3âRÜy{à�hù¤È¹ÖIQÛÐXıwï^g£hqr¼òÊ+–m³Q¤Ç$î€$ôŠ´J­ ©éqñ©ÍD\¹ÖBmm-Ìž=Û�¶ÈŠ–g•o2™2eŠ£¬¬LjRLL L›¦[ñ“Jp"0‰;€âÈ‘#Õ¼¼<—â\¨Á=c1tê Ð]sJKKÁj ]¨Ü¢Ð?§êêj¹±˜ºï¾ûì„•ÇÎ*LâÂÙÖ�Z{dê €´‘ZªùýsåãÐZ‘sÍ™"Ørùòe�¤¤¤À’%KT� œt˜Ä„T¿J]s‡ÔõžK‡ê™9rþ;ï¼cú¹"¶_Áù®Cn™;õÔSO±27!�±)bð^yå•Ì×Ñýê}õ�È}b5@c¥ûJll,|ñŶ3f¨î\ãÇȉ>Ÿ•M›6¹Ú­¯uŸ>}ìÇ�/Ðçs:4pO®ú!uµ°J->66 ë<3§“;—† ¸@æ(,,TܹƎá?,eìØ±Ž¶L-xá…Tc·ÄZµc O�!u‰÷!5½"¡+ªfNÇHŒû…çÏŸ‡™3g:HAÂ�kÌ)o�‹ŠŠÚ¬à¨Q£ì÷ß¿Úf!¾T˜ÄÀI+¯ƒ r¯RãúY6µÈt±ÛõòÕC‡Þ™À‡~¨àV‘£¢¢B®¼—_Ï«¯¾ªÊ…8j¼ˆ!Ô¯´Öó}Rk­NŽóæ«´Tó÷úõë ëL€”5î¾ûnG]]�TéΨ^—,eÁœ9s슢¨r.§B�“8@„=?h•Zþ½{¼!c:è-g“3�+V(rndS�<òˆ‚ÛHR-C×18=@Ë­Kݹ ðòË/«îŽ… &q€H6L2dˆ<¤>ÜöC�6ÈèL ®‹\îÑGuÅp€N¸@%©†øk¡ø.WœÛ*]�Ç{ÌŽ 0ªœË©p À$ÊCêóĶMCѬ›q� u­µÐÐÐ@]u&@j¡×^{mªRJ¦•õž³š·Ð*· õG‹åÕ½[·n�ŸŸ¯jíàïð"À$Þ«ÔÇÚRÓk»ãŠ5ölbÀ}؈©f’ïì1cÆ8¶nÝš/Ö‰F ½æ$õ¨Çµ­ªfW‘gŸ}Ö–žž®º28V˜ÄA€Ûë�ºØ·§  9¦~úé§|ÒˆóBÇÅ5åúë¯wà �ҫЬzߎsànÍÙg7áw“»­Î?þøãª;‡cáF€I$ÄçÏŸ/=éb+ŠR¡–Dúht&p…|eÕªU»Ý®È¹¡I¡¨róÍ7;hßZ ɹ8„ží6«$ÕÒZüˆá¥—^RÅ4ÇÃ�“8H˜Ï›7OU‹Ú¥vV©ÅòÝm8¼Îs HfEÎ nŠþQ�­3ÙÿŠ¡ËðfsÊØ€M¸îì……B¸�dÇm%UÈâh` tR:TZ¥Ö›'¶õ*" yÍŒÕí½Þ{ï½^+mÝÛÑkdMEÿ(ô÷w›�1ÝbÜWhÜ èz�­ðÒ¥KUw ŽE &q‘ׯRkNô|}9ÈB¯ H¥¦¦†¼f:ÈðÀ×ç´WŽÔ·�æ¡YO-ÇýÝxàüwšbl+,ãé“8ÈÀ­!鉭™'J…¼$º�Ç}Ù~òTËt¼þú늜ë[ª5?X¤þI{À iÞŸsv3æ_r_#[aVìpãa„“8ÈRÀy±*>Ò¹Jíç�šî§S{܈N÷°—ÃO<áøê«¯1¯½xk~°Ròšµ°âp(í-Ô•¡U–NûŒm…½!Ù<&q�ñ§!õˆ#ÜCê&$BÛ&¸­Ö€T�ª™‰î"—.]Ü“v��¾;·õXk~°Ò®i>z†³Z gÿ[¾Â¶Â2FI1‰C ‰` ©©j Ø÷˜Ža»çܹspë­·¶ëL€´¾<ü`ás2pá¬Û8y I­¬SO,¶Ñ0NœIYà‰ˆªøXç*µ°º+^ó%žŒscš#‹aÿþýp×]w)bž§í¨ñãÇ�Ö—–Gßtr#¹ ê2TÌõŒ7ḒæÂB`[a ƒE™Ä! ©Ñë‡<¤.ìE´wÛy°ü œçÓpYÌÕü`‘k\1?®3.`Íñô¼)–Ñâ´M«ÒZ`[a c~3‰C$TÔžÜÑUjñ!´¬ß¢á2é>S¹Öü`‘¯Û=Õ:ÅgkñK8b`[a s|³ËÚɉzDtiëÎâ\4û>O—6þ¾þR5º¿]%{ÕHLL„§Ÿ~ÚŽÆùz7:IÙ8§¾ •À„ű¶Þyæ[45Üí.A¶Âè�M Ý�.Æ$¡H®¹æš2+Ô^‘1¹Ù+†–îèwýi€“kÐ"°±í'�Ò-bÑv•/�l…Oü–lr—Fýh›ºñ0bÌGñ±êƯS0W©ÅÖ’�o÷©bŽg<ý:,có�Àô„³ÿƒ³­°'®FÌa‡P*Š¥8 Æáp0Bç+ЙÀµ^ž„%?X^¯y)®e9m…K´Tó7Û Ëx5Å$¡dÈq)H¸^�½\Gt©]÷ë"ä$y€;SôƒåÎm?ƶÂícdäLâKG?¤ö×<±­ê‘½/ùèJèŽê™‚¬¶îñv­ª�m…½áb–<&qˆ%…*’ªøŠº ©é¹äL€T3i Ióƒ%¾¯½8öFÞ+ÅÀ¶Â"Æ�3‰C,£ÜÜ\uôèÑî!5¾¯£ºÔ­U•zḔ֮¶�϶Âmãc†«Lâ0H)”Cê@ªÏ¶Â� gœ{yŸ8 ² o pˆ¯r*~t°÷ŸHüôײ©avv¶ýèÑ£�<“ï ?ñáeô½QR£g�|­õäÒ–W‹Tðf+üÜsÏ©�Ô‡þYUUU)ÕÕÕ@ç/ÇÇÇi“edd¨ø" gR/«ßË$“„iH�$v½�t©#IâŽÚ £a…²cÇeçÎ�€ª¥¤’ 䌈‹ÁõOÊÕÐæåÛSSSÿ¡ÁÀ�ÝÁðáÃaܸq*ý“Ó•ç¤ðpÚ°)êmHÝ÷^ÜBë¢pÚæ*Ç¡´KZ æQœ¼ˆ|ýõ× Wª�B}}}kDÕßêsš†ñS§N%i˜>}ºÊGÂø �³ “Ø?¼*=vìØ‚-[¶¸HÐmbø{c².ý@65¼í¶Ûà³Ï>£¶Ùñ@5øä“OœiUUCBÚ¶@¤á÷-·Übÿå/©êí²Ûº/š¯1‰Ã(}4,@û_‰É=-9© g8·M6ø'[aæïÞ½Þ{ï=À^È�¿!!&ºà³:ÅÅB§ØXtDƒjØMЀsãj|^ž0Ñp¹É¯Ç’S¾_ýêW€G¾ª™™™ª_7GQa&q…�sG¥_¿~ñ•áR“­ðñGTðÐÂÕW_ ¸" ús˜´ëúï¬N� 75ú¥¤@Ÿä$ÈJJ‚ÌN‰�‚‹Xí… xtky]=”¢CücÕ5PTuÑù©G¢·:á;ñÀsûþð&³ ˜Ä^@ e¹Í½nt»‡Ô:Ó¡z¿ÞVØ—÷tKL€Ÿ¥§Ãðô®0(-Ò°· fhDB2o?[ ?VTÂÉÚÖ]ƒvîÜp$cc—¹²˜Ä2!O½öÚk¿ûÝïÂ>¤n8‹sá�°y>ŒhûwN�ëºg y»B?Œ‡3#¡¿;]îüÔ^òÞCãê¶ýÍ7ßTg̘¡†³nF}“8Ì’¡!uNNŽ£©Éͦ¾÷à*5žÃÊPöKZÒúºb;!³;LÌêÙ8TŽt¨Áyôw§Êa]éI8S/Œÿ…ŠÝ}÷ÝN2Gûj6“XøQ„+Їyб,ÚûèBý!fÚµ`|“­ð©µÞŸ44­ ÜÔ§ŒÀ^7§Œh¸í(; ?^ ç<]™à?DøÛßþf›8q¢j´º‡«>Lâ M§ VTT(ø úùˆÖçáJpþ™3g\o&çwd…Š@¶Â'>–M é=×÷è3z÷‚œ0—;ÚÆZì™?9z¾>QúAv\\àÊÔºbã¯Ê_ФlYÕuõªý‘†jH]µàÌɵúõà<•ÑMÎ4Iªäb5üÛ¡b8Œßú°páBÛòåËU}¾ÕÓ– 1‘°åãÑëyë ERCÀ$ ô‡ª!5õÄváÉ†è ž¶©þÿy­nDï§!öª’ã°îÄI�z Ö™ µÏT� Î0 ‰I-ÑÛ#!õ„¨lqvø7‚ÓPr«ãt-{c‡ŸÒê�M¦ì ã²p^y¦÷ê ¸¯k…°³òüeÿ!§2‰Ø²ß^·n]Ôì)GœÄ‹/VèÔ>‚i‰ƒœˆC"Æà‡ü;)]ßb\»¦å%a¹àn»Š¿eÈ.K…ey�r9„/‘ÞþÄÉšZx­p?”ÕÖI/:t(|óÍ7¶hÐôj_ÍF‚&ø ìI|jD L$”ˆ§¥5²‰ßbËѽF[ÔMlˆ…9ÇÀ°ÊŒà Ì`Oì…ZcùÇÂë…`ÿ…*WíöìÙ7Üpƒƒˆlõ-¨È“¸ê¼ ø@"1Ø’x<(ÛIF"šŽl®|� -ßF$a 8ä�Oƒ9% ­%¡3ª|>qÕ ø×}a×9÷ï M&aÖ¬YÊÆ�U+Cq÷<µÕµA˜NCh¤ĸ�—Œç¡Èä:¡ ª5ÒwÊœ{öm>“H#¼ÑzÑŽþØ.Ç­GsàÞ¢ÁQE` ¯N¸Íôø�+ad·t-Ëù�&”ùDd)Ób‰ˆÏ‰ O´SUpø£ìÝ» �†Bdp,ÛUê¥É¤þCDöõˆ#Ë=ûbg¸½d dÖá$;ÊYM½²w?ž¿ !�gUÙ–,Y¢J™I‚Ä­a‰„VvíÚE‡}ûö9ÉMçò¢‰àÌ¡qB‡x;É�ÓGÉ»"¹ãZ«•qòc›påùd˜RÖÈø�C3¤²ùâîB�½ä÷ßß¶`ÁÕj8šÄ­�M'RÏM½6õÞDrŠã"YpÈ�|ˆG"»H�½x"~â‘ð¡\Mn­½Þò3k“`Þ‘�з&®A¼UÈ`yçê `ç¨ô®“Ðlòûï¿·¡k Õ`Õ ¨:¦$qk-&ã"7‘Z$wyyypÈ�/&Ï.rSïÝÒ“ÓÂYXö¾c˳`zi?HhŠø’FXšÜÑ—F‹¨çwàÖ“Õ^ :úL#Þg)·0ºœ¡^["7óƒFî8ì]äæß´È¬�VŸsqåùŠ*&pð �Íåg`Ù�"©¬ÕÔ3£‚Ä’…iˆyë¹KJJ‚¦‹kM¹[æÞþ:È~6fëÉ—"¾+( hŽè;E‡�–Pbm?ýôSÛœ9sT1Ϭñ¨&q[BC¿SN‚‹ÃrrÏÚØØ”Þ;•¨´á8~;çÜ4ïÆáº¸í•ܳŽåF…âF[òäZ=:(عŽ£v—zöìIë(–PakRõñ›VËé#n‡ÑŠy0·Ãh_»ÛX€hTÜðQ ~;†~±ówì�FÁÃý÷ßoÿë_ÿZà÷à v“8Hi™s{¬˜wd;,cL ÌïÙÆžACcACàóc¥°m’Å€Þ=mÓ¦MSÅ<³Å™Ä!–Á ¶oßžÿüóÏÃÖ­[}zÛCWåÂÄô>•åB¾#p {áü»á(zÚÔ‚V«y�B“fˆ¾SÐ_ÕK/½ä•ÀcÐ0~ÿlP²zÀ .©Ð9¾YÃäŠN!v¸¢¶ý±q¸Øðà$µ\ØÌýõ×£×½­úqOÜ:^£Å±Ù³g;JKK¥'¥ žïÃW„Ÿéô|©ÐyôÍœŠ ýFôw%5Âĉw‹ŽÀ†²S®¤¥¥Á¡C‡Lk¶È=±K”Á�¬Y³F™4i’�{·˜Îy#0Õ€ü:3�ƒ+ ýÓæõë ô�T äXÂn·+ZÚlß܇@bo½õ–òØc�9èxO1�çG®¼’[†Íâ5އr¸·òp‰ë¥tœ î2ØrssUW¦I"ÜYPô�ñ ð­è–Lå˜ÀA¼ƒ�›Ú+ z&¹uepcÖÞ˜{âþ¼Ý†GŒ(è:Õ!^#Û¢ÿwE.LÆÅ+ÆBàP%ó-A%3‚C½jÛ�!CTcÕ´íÚpOÜ6>>_%_azÇãjèbtËöư‹GÕd§¸•Ûiúƒ6ÇJX+„—qOó›ß(¸M!õÀIxÄçワ„«º¢ç†EàÇŠ³N·>Zãqg ¸¸Ø†Ÿ«ZžÑ¿¹'PB¿ÿýï=Ü¿:„  ¶á¸}nóõÅ- n<¼üòËŠ–6Ã7÷ÄH‰”°–z`'�¯}…aZ¯à[ÀܶO•Ð)è9rÄ4ûÆÜk’óó{åÊ•Êoû[‰À¤¤ñôÕƒ™À~béâã23 #ÑíõÝaÅŠJ¤ëåëû™Ä¾"%”CŠÊƒ>(Oš„+›ä6ÕÇ‚ Uå¨Ä£ìnê-›¼ýöÛ>ÜiŒ"Lb?å@ÇÍ 1¹M]wÒ*ô¯qx@*û»r�b²Èä¬LHD2kåœOZwZÚÈßîZ¹–ªÛܹsñXRªÚ¼0”W¡ $%ÿ«’‚S!:d] Ë–-SÄ´QãLb?$óÀ(è#;_¼åvÔï¾x�ãæAàÔâÚçÓÈKÌ3bœIì£TÞyç?ÒBÖ˜îÝ`vvŸÀÅŒŽ¸~%š„j¡ í�ß}÷]EKõ›IìƒdÈÏõ¢E‹$ÓÞâCh›ÊÁZÐÜX ø�[L2Î$öA,÷ÝwŸrñ"ôÛhdÑ < ó8X �1¨Š©_àRUU1r+™ÄíHõ¡•M›6Ióà¹9Ї•9ÚAΜ—“ñóhô¸"£©™Ä¢´tqZÔxöÙg¥aô5¨¦7¥'[$é ²Tr¢nH�[M†n“¸ ñ�aCM�Û©ùÀº`nwð%+ pUZèš�àj 2�¿víZÅ•a°“¸�¬_¿^ÁÿÀÒ0z~ÿ~�žèn+·r¶É ÷H´ó †�?þXÓFŠ3‰[‘ø‹—òRSaRyåR¼Îqk!@ \bøüóÏŤ¡âLb/â ã½RÇ=rðx>Ø \–Ì"Âú!õW_}¥±±Lb/RÑ{w�V.¹¬í)ëfÑ�Z¿J½nÝ:ň-f뤲jÕ*:HÍ5&€Hµ’Cô!0<]öʲaÃC‚À$Ö‰eéÒ¥Š˜5¾GwÈÂæ9DCЩ¼ð¼-1i˜8“X΃=;föí-”àh4!@î…3;¹�б¶ô1LbA"zÓ³ah^Ø'Ùí Q(ÊÑ(A€NìñcÇ1m„8“X�·…À4�išt‘Q�«#†S§Üg8‰ù‘Œ3‰[Ð'/®­´„xáåÀ³H ‹ß~Ä3›èíUUUá¯D;od·´zõjEÄjúÓQ˜¢½n€þ|-# Ã$n‘—_~)ɃÎæÀ\FÇb çòF Lb”�#,¥ÉwtžàáÁhBãú„�‹èL^ ééébÒq&1ŠAoôMNïøŒ`Cü>#^‰ L∠Á— lܸQ*6MÑ80„Àéº: ˆ\ž_Ì=1ЇӒ ˜ÄQ› ùpy�Û¿8a6l˜j4@¢žÄhð­”––º¶–pEº�nƒßhBãú„�“µµpIXØêÓǘžM£žÄ;vìPÄŸièð|XD$zã%«¥Æ�1BJ%õ$.**’dÁj–Q�(ªr{8% FŽiH<¢žÄ8”–ÓMPx—.p"ê8pAÖÎ3fŒ!1ˆz—••I‚I×éÊJ95Ô]ºGtÃéÉ“'«F êIŒJ’\ô ïÒEND û±µ dÏÌÌT�@Ô“¸W Å�ËúÒ"ÑßQyNjúÔ©S¥´‘QObñœa �5Ì�øél¥­·ÞªJJD=‰õV)z«ÉŠ«&Nà�§jÝšZIIIö™3gªaz½ß¯‰z§¢?i1Ђ‡èF`[…Ü +Šbh@˜Ä:×^ºlh�qåB�ÀVÝPzÖ¬Y¡ioˆz§é<êMÏÀ–o5!çà nø¶ÛnS�Ü”¨'qß¾²Oé3õ’»‘eÇu ´ %º=z´=;;[ Á«‚öȨ'qNNަÎjEºÆ ë#ð£n><{ölÃ7:êI¬·=Y#ï^‚\Á !P‹‹š»uûÃsæÌQƒö‚=(êIŒÃ%ý&Ù5|ËPùƒW¨54¢ë›<Óü¼t´Ú}°¸ëG,�À�g¥6b/,¥�š`£dF�%ÉG¿:)]ä„%h¼|¶Ÿ•U-çÍ›§š¡±Lb”Òõ×_/ÉjϹóRšÖG`ïù P#(úôêÕË>nÜ8Õ -g£”P¹]V! T´`1ƒ ¹Ž�!ðÃs¥©ÕLbaÈ�!*úOr-nÕáÐj™Ct @ñ¶ž•Il–¡4IˆIÜò;½å–[¤_ì–3²�±t‘–B€¬ÿ‡¢×í±LbÊ;î¸CH8ÊNKiNX�bôh)êË£iªÝ ZZ¢$˜Ä=ô�*$�”á+äÄË·z‘™®ULbAd¤‚‰Š®!5iom(3ÞÉðB•9 ß›|(MÍgë~�<òˆ*f­?y jÙÛ‡ˆ‰UâÇQ½–Žjѹá™?¾ª¥ÍòÍ$ÖIjáÂ…*iëhÙ¤Åó_ÜkpXê[?”F¥S¶�IìEl‹/–r¿*= d¦ÆÁZè=ZÎ�;×” d{Û£�>ªŠn{h»i™ƒu¸€nxij–ÈË©‘=Z¶…<“Ø :¨±£>ùä“6ñ‘ø\}ƒ˜Åq#@¶Ã¢žk¯½ÖŽÓ(ÕŒMb·"µ?þñ�Òܘô©W=ÖJiÎ6ú¡´^íÖLía·!­üü|U¼üÍ©rOˆâuŽ›R§ÝU)››¢[ZÕµ÷¬%“ØWÎÃ?¬6̵RMÞ-:Ì:Õ.„Ì¡¹pµ°P™••e's¶†÷‰Û•Û²eË$á–àÞâž��Cm÷!\ÀPèuâÑbÉPõó·2Ü·ƒØÄ‰Õ{ï½Wê�W•ƒR<¯‡ƒ9Ø­óÜrã�7š³!-µfû ¾W_}•,œ\%É#âòƒÅ<¬v!bžißÒ�ð@læi�gM™Äž˜xäÐáÒo¾ù¦´åDóª¿?áQ–3Œ�@áùópY¨"­yNr€ ”IDAT˜ukIk“XC¢�oÒ©½óÎ;¥aõ§G�ùãâ`ôò2«ª¥ˆ8“XD£�8öÆjÏž=]¥HY`ÙþCèÚ…•@\ <¢'ñ”)S ^ãö«Ç$n#W V¯\¹Ò놭 üö�"ž»P2n¤Õg�\¬vU�T-'Ož¬º2LqÿMÚ€pW›¨=óÌ3Òüx®vÒŠ5c#°´DUËáÇÛé³±kÝ~í˜ÄícäQâ¹çžSñ?¸4?þu«7—Ÿñ(ËÆA€¼ZŠe(&MgwPt}ôùª–î^q¨ãª5c" ?žgüøñƬ¨Ÿµbû ˜Vœ¶%>ûì3[§N�´,h¸Ü¯ìÝÇø@6&F‰�¾´hzHõš0a‚j”úR&q葾íŠ+¤ù1Ù¿¸»�·žÀ5·­®†z´DÓ�ø¡?›Z»f¶o&q€[°`�úôÓO{%òj\ì8¾Šo�â*÷ª4=K àiƺ•Iy,Y²D]´h‘DdZý5ºþiÛNø &ؽO€àúÓ½¹‡×V ñViˆÚ�Ãj­žl>ø ²ÿþ|±NµHÜ�§Ë�ŸNøƒ’Ö†vMƒAi©�“’ñº™x/ÇG A‡/“8pL-û2]Ü·oŸúÊ+¯¨/½ô’R^^.‘™N®~¶c�L ¨9”Ó9úwè—’ }ñ“ç¼ÎG 16FzH­àoZº`ÂDL.½so¼ñ†‚:×Jaa¡™Û{k÷ÄDè“’½““¡wRôJÆ~wKLRäà;4�¡í?- ù¡}ݺuZÚÌß<œ±ôpÁ‹½ÔÍ›7«¨ ¢¬Y³>ì¡é /úìÔùƒ¢ù]ϤNNR¹‰ä}‰ìIÉ�ÇËÞDj徊IìMâ!ÈÃ- •>K—.ì•Õõë×+‡6mÚ'Ožô‰ÔZµhÛê(*”ÐG Ô7g!¹ûá›†ç¹ø¹"5RXÌ"N�Xô×Ì–féF@bC† Qéƒ=´óíØ3«[·nU¶oß;vì€]»vQo ���~‘» ŸVV[çüˆgS¯�×%†¦¥9Ó2:%F ÕüÊP!À$²~<—4‡èsûí·Kw!™Õ={öÐJ78pè›>~‘[#öŸn6Ðèƒsëk3ºÁ˜îÝœ‹iÒK-šh’ì—¬ÕH&±�剮cÈe®ª¯"®x«Hf'¹q%œ†ç~õÞ¥5µPŠŠ(ä^ˆzi[Ï,˜Ô#ÓÒÃîFݤ8 ­˜Ä&”$ÙÀÒø=jÿÃ?¨?ýô“²mÛ6ÀÅ4çð¼­a9õÒ9 ¤":)«ÌêÛ¬8ÜÖ«¿¦àº�U“Ø*’lieè¡«¾ùæÓˆØùHj�V“O:PýÛS§áÆÞ=aNvKíS7àb ˜Ä"7<Š¢¨ôÁci ²²R]»v­²zõjøòË/óëq K 4ì¤ÃãÈÁÁ½úÃ(œ;[!Ô]’IŒŠ[¡YÎ6ð¦¢eDé[CèÄG´¼*øôÓO Ž?nC­22ɳëï>‹'@þ˾ƒðoèèÀ Ƥ%'+õÄLbQ²Q§yõSO=UP\\\°|ùr›72‹‡ÈýqûnØor×¼ä$O ]»v“¦Ž3‰M-¾àU~áÂ…*‘�tµ%$$H>]WÿŒŽ>ÆÅ/³Z`]Ä“Ä žè!æ›1Î$6£ÔBXgr¸eË›þ4HR$Y‹[RDæ3Hj³…‹ºž˜Il6 r}ýB`äÈ‘êÎ�; üq›ÞÐâ:üÓŽÝ ?¤Û¯D p“8¨ó+#Žêy«6l°eggKu¡¡éÒÂÎýåK:% © �äûL Ü‹hpÜÒÐÖöʶÛn»Íc›¶¢–àðú®d=TêꈎòT£×Ù×úñœØW¤¢¸mK¡{Þ‚—_~Ù/ë‘Cöü�»¡ØÀþ¶i1NNcL¢øsd‹hp¼Mžxâ uãÆ�¶~ýúIåhOù…]{aS‹�…tщsºï²²² P«àU�I<,£âId�æ’¶éÓ§KÃkRÛ|û`|€Nõž%# ý“ƒþäñšãLb3J-Âu¦áõ?þñ�ì™múª|…îy_ÇE¯ºKò¾¬¾\8ÓgêdÕRýB]8ëŠw1‰C�j”<çÈêûï¿oÓë!“ÀpÁ«R§—)XHYE ¨™&&Mg›^„‘m�€Aód}ïFçÛwîÅs©"ïß¹\GâþýûG´ ¿�Id@£ñqdúøý÷ßÛð[š'“ãüçwÂn<¿9’á4ÚL‹aàÀ�bÒôq&±éEhŒÐ)‘Hä‚9sæHóäœ¿Š®b·œ©ˆXEõÃi$±±Ê„àÅLâ€Í�DG�s©H«ë/û�Zv:ìÐб®'¶{syöŠñ…Lâ ‚É�jF€Î¥B•MIïš (þZt¾D#Šp†S8-‰srrÂùú°¼‹I˜£ï%h<¡¾÷Þ{^¡9ã O¯p…èP ƒ “–ˆ3‰-!Fc6‚V®qxí±õê\¿ƒ½r8”Bô$F߯+€Z1‰�om�™3gª_ýµ- ׋Á�óãèú'ÔD.­‘OÉ,žü€ZevÒû¤ F¼—IlD©X¸Ntæ”7"‡Cë`ù¨NåsĈ–D–IlI±»Qm™V­ƒJP[ Lb Ž3"Б¿A?×Î>²ÞÛÈ5×\`­�y;÷ÄÆ”KTÔJ#²Þj݉“ð÷c¥aЄ‹Z‡u=ñu×]§ôPƒÞÌ$6¨`¢¥ZDd‡ÃaÓ»ÌYuô8l8yªÃ0Ði�d|¡<킎«Qµ´•¾™ÄV’¦IÛB«Öè)Ħ?Zå½â#ð¿x°[GB‘Îqn-uä1¦¸‡Il 1Y¿’´�Œ§5Ú’““]�%£‰·Ã޳ç\y¾FŠªª¤¢8”–ÒVJ0‰­$M“·…4»>ùäé,(RØxcÿA8rñ¢_­#Wºb3fŒ˜´TœIl)qš¿13fÌpZ?ÅÆºšt,ék{ø|T=žE|´ZV·œ0a‚j~t¼·À�”÷ëœË„�ùóç«o¾ù¦ä!¤}G¿ŠD®Ñ�nè­r4”�—AóC;ãê­¬ò˜ÄV�¢Ûððëz—¸ÇÑ"é_qhÝÞñªûtCiì…-ˆ�»ILb73ä{e©GÞƒN÷Þ):ÒfM÷éDŸ4iR›åÍ~‘Ilv Z¼þ|ð�Š=©]læÆÓå­*ƒÐ0Z¿¨5yòdU¼ßjq&±Õ$jÁöàan*î%K-[�Ê Û*ÎJy” ùp=.„i�l±Ó>´–¶â7“ØŠRµX›hQjݺu¶îÝ»»ZF{Èo(Bçôò*ôžs\e(2uêT)mœ؊Rµ`›¨7]µj•äx¯{\:÷©ªÁ}€8Í™Å`³ISjñ’eâLbˈÒú ¡ÏÑ®ÄJr ÿ—‡œè7ý|{bÕêÈ0‰­.a‹µ�¶žð#™Ž‰Y…®p qUZ¿?lU£Q¬Lb Ž›�eË–©¸â,­X“\Zìž¡,&-g[V´ÖnØêÕ«Uýaát£nºé&UL[5CÆÓ3"°yóf{dGªdêž™l¯©©)Ðç[1Í=±¥%m7nœúÚk¯Ióc­é¸¦E-ÿÍ$¶¼ˆ­ÝÀE‹©wÜq‡4?¦Ïš5ËÚ ZÇÃi Žš�ÊÊJ� 8Ž9âl@LL ”””ØÐw—jÎùWkî‰ýËKr¿råJ›fƒ<~üx{´˜ÄÁ$6à�’«ä?ää™gžqÎ�çÍ›çÿL|§M,<®º'cÇŽ- í§hꉙĞ¿Î11åå劕½xx “Ø*œÇ˜ž›HX\UFÀLbo¨p#`"þûkŒßR—íIEND®B`‚beetbox-beets-00724b7/docs/_static/beets.css0000664000175000017500000000047215253035401020250 0ustar pieterpieterhtml[data-theme="light"] { --pst-color-secondary: #a23632; } html[data-theme="light"] { --pst-color-inline-code: #a23632; } /* beetroot red: #a23632 */ /* beetroot green: #1B5801 */ /* beetroot green light: rgb(27, 150, 50) */ /* pydata teal (primary): #126A7E */ /* pydata violet (secondary): #7D0E70 */ beetbox-beets-00724b7/docs/code_of_conduct.rst0000664000175000017500000000007115253035401020650 0ustar pieterpieter.. code_of_conduct: .. include:: ../CODE_OF_CONDUCT.rst beetbox-beets-00724b7/docs/dev/0000775000175000017500000000000015253035401015561 5ustar pieterpieterbeetbox-beets-00724b7/docs/dev/paths.rst0000664000175000017500000000417115253035401017435 0ustar pieterpieterHandling Paths ============== ``pathlib`` provides a clean, cross-platform API for working with filesystem paths. Use the ``.filepath`` property on ``Item`` and ``Album`` library objects to access paths as ``pathlib.Path`` objects. This produces a readable, native representation suitable for printing, logging, or further processing. Normalize paths using ``Path(...).expanduser().resolve()``, which expands ``~`` and resolves symlinks. Cross-platform differences—such as path separators, Unicode handling, and long-path support (Windows) are automatically managed by ``pathlib``. When storing paths in the database, however, convert them to bytes with ``bytestring_path()``. Paths in Beets are currently stored as bytes, although there are plans to eventually store ``pathlib.Path`` objects directly. To access media file paths from library objects, use ``.path`` for the absolute path as ``bytes`` or ``.filepath`` for the absolute path as a ``pathlib.Path``. The database still stores these paths relative to the configured library root. Legacy utilities ---------------- Historically, Beets used custom utilities to ensure consistent behavior across Linux, macOS, and Windows before ``pathlib`` became reliable: - ``syspath()``: worked around Windows Unicode and long-path limitations by converting to a system-safe string (adding the ``\\?\`` prefix where needed). - ``normpath()``: normalized slashes and removed ``./`` or ``..`` parts but did not expand ``~``. - ``bytestring_path()``: converted paths to bytes for database storage (still used for that purpose today). - ``displayable_path()``: converted byte paths to Unicode for display or logging. These functions remain safe to use in legacy code, but new code should rely solely on ``pathlib.Path``. Examples -------- Old style .. code-block:: python displayable_path(item.path) normpath("~/Music/../Artist") syspath(path) New style .. code-block:: python item.filepath Path("~/Music/../Artist").expanduser().resolve() Path(path) When storing paths in the database .. code-block:: python path_bytes = bytestring_path(Path("/some/path/to/file.mp3")) beetbox-beets-00724b7/docs/dev/index.rst0000664000175000017500000000113215253035401017417 0ustar pieterpieterFor Developers ============== This section contains information for developers. Read on if you're interested in hacking beets itself or creating plugins for it. See also the documentation for the MediaFile_ and Confuse_ libraries. These are maintained by the beets team and used to read and write metadata tags and manage configuration files, respectively. .. _confuse: https://confuse.readthedocs.io/en/latest/ .. _mediafile: https://mediafile.readthedocs.io/en/latest/ .. toctree:: :maxdepth: 3 :titlesonly: plugins/index library paths importer cli ../api/index beetbox-beets-00724b7/docs/dev/cli.rst0000664000175000017500000000063215253035401017063 0ustar pieterpieterProviding a CLI =============== The ``beets.ui`` module houses interactions with the user via a terminal, the :doc:`/reference/cli`. The main function is called when the user types beet on the command line. The CLI functionality is organized into commands, some of which are built-in and some of which are provided by plugins. The built-in commands are all implemented in the ``beets.ui.commands`` submodule. beetbox-beets-00724b7/docs/dev/plugins/0000775000175000017500000000000015253035401017242 5ustar pieterpieterbeetbox-beets-00724b7/docs/dev/plugins/index.rst0000664000175000017500000000640715253035401021112 0ustar pieterpieterPlugin Development ================== Beets plugins are Python modules or packages that extend the core functionality of beets. The plugin system is designed to be flexible, allowing developers to add virtually any type of features to beets. For instance you can create plugins that add new commands to the command-line interface, listen for events in the beets lifecycle or extend the autotagger with new metadata sources. .. _basic-plugin-setup: Basic Plugin Setup ------------------ A beets plugin is just a Python module or package inside the ``beetsplug`` namespace [1]_ package. To create the basic plugin layout, create a directory called ``beetsplug`` and add either your plugin module: .. code-block:: shell beetsplug/ └── myawesomeplugin.py or your plugin subpackage .. code-block:: shell beetsplug/ └── myawesomeplugin/ ├── __init__.py └── myawesomeplugin.py .. attention:: You do not need to add an ``__init__.py`` file to the ``beetsplug`` directory. Python treats your plugin as a namespace package automatically, thus we do not depend on ``pkgutil``-based setup in the ``__init__.py`` file anymore. The meat of your plugin goes in ``myawesomeplugin.py``. Every plugin has to extend the |BeetsPlugin| abstract base class [2]_ . For instance, a minimal plugin without any functionality would look like this: .. code-block:: python # beetsplug/myawesomeplugin.py from beets.plugins import BeetsPlugin class MyAwesomePlugin(BeetsPlugin): pass .. attention:: If your plugin is composed of intermediate |BeetsPlugin| subclasses, make sure that your plugin is defined *last* in the namespace. We only load the last subclass of |BeetsPlugin| we find in your plugin namespace. To use your new plugin, you need to package [3]_ your plugin and install it into your ``beets`` (virtual) environment. To enable your plugin, add it it to the beets configuration .. code-block:: yaml # config.yaml plugins: - myawesomeplugin and you're good to go! .. [1] Check out `this article`_ and `this Stack Overflow question`_ if you haven't heard about namespace packages. .. [2] Abstract base classes allow us to define a contract which any plugin must follow. This is a common paradigm in object-oriented programming, and it helps to ensure that plugins are implemented in a consistent way. For more information, see for example pep-3119_. .. [3] There are a variety of packaging tools available for python, for example you can use setuptools_ or hatchling_. .. _hatchling: https://hatch.pypa.io/latest/config/build/#build-system .. _pep-3119: https://peps.python.org/pep-3119/#rationale .. _setuptools: https://setuptools.pypa.io/en/latest/userguide/package_discovery.html#finding-simple-packages .. _this article: https://realpython.com/python-namespace-package/#setting-up-some-namespace-packages .. _this stack overflow question: https://stackoverflow.com/questions/1675734/how-do-i-create-a-namespace-package-in-python/27586272#27586272 More information ---------------- For more information on writing plugins, feel free to check out the following resources: .. toctree:: :maxdepth: 3 :includehidden: commands events autotagger other/index beetbox-beets-00724b7/docs/dev/plugins/events.rst0000664000175000017500000001767315253035401021316 0ustar pieterpieter.. _plugin_events: Listen for Events ================= .. currentmodule:: beets.plugins Event handlers allow plugins to hook into whenever something happens in beets' operations. For instance, a plugin could write a log message every time an album is successfully autotagged or update MPD's index whenever the database is changed. You can "listen" for events using :py:meth:`BeetsPlugin.register_listener`. Here's an example: .. code-block:: python from beets.plugins import BeetsPlugin def loaded(): print("Plugin loaded!") class SomePlugin(BeetsPlugin): def __init__(self): super().__init__() self.register_listener("pluginload", loaded) Note that if you want to access an attribute of your plugin (e.g. ``config`` or ``log``) you'll have to define a method and not a function. Here is the usual registration process in this case: .. code-block:: python from beets.plugins import BeetsPlugin class SomePlugin(BeetsPlugin): def __init__(self): super().__init__() self.register_listener("pluginload", self.loaded) def loaded(self): self._log.info("Plugin loaded!") .. rubric:: Plugin Events ``pluginload`` :Parameters: (none) :Description: Called after all plugins have been loaded after the ``beet`` command starts. ``import`` :Parameters: ``lib`` (|Library|), ``paths`` (list of byte paths) :Description: Called after the ``import`` command finishes. ``album_imported`` :Parameters: ``lib`` (|Library|), ``album`` (|Album|) :Description: Called every time the importer finishes adding an album to the library. ``album_removed`` :Parameters: ``album`` (|Album|) :Description: Called every time an album is removed from the library (even when its files are not deleted from disk). ``art_set`` :Parameters: ``album`` (|Album|) :Description: Called after cover art is copied or moved into place for an album. ``item_copied`` :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path) :Description: Called whenever an item file is copied. ``item_imported`` :Parameters: ``lib`` (|Library|), ``item`` (|Item|) :Description: Called every time the importer adds a singleton to the library (not called for full-album imports). ``before_item_moved`` :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path) :Description: Called with an ``Item`` object immediately before its file is moved. ``item_moved`` :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path) :Description: Called with an ``Item`` object whenever its file is moved. ``item_linked`` :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path) :Description: Called with an ``Item`` object whenever a symlink is created for a file. ``item_hardlinked`` :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path) :Description: Called with an ``Item`` object whenever a hardlink is created for a file. ``item_reflinked`` :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path) :Description: Called with an ``Item`` object whenever a reflink is created for a file. ``item_removed`` :Parameters: ``item`` (|Item|) :Description: Called with an ``Item`` object every time an item (singleton or part of an album) is removed from the library (even when its file is not deleted from disk). ``write`` :Parameters: ``item`` (|Item|), ``path`` (path), ``tags`` (dict) :Description: Called just before a file's metadata is written to disk. Handlers may modify ``tags`` or raise ``library.FileOperationError`` to abort. ``after_write`` :Parameters: ``item`` (|Item|), ``path`` (path) :Description: Called after a file's metadata is written to disk. ``import_task_created`` :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|) :Description: Called immediately after an import task is initialized. May return a list (possibly empty) of replacement tasks. ``import_task_start`` :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|) :Description: Called before an import task begins processing. ``import_task_apply`` :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|) :Description: Called after metadata changes have been applied in an import task (on the UI thread; keep fast). Prefer a pipeline stage otherwise (see :ref:`plugin-stage`). ``import_task_before_choice`` :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|) :Description: Called after candidate search and before deciding how to import. May return an importer action (only one handler may return non-None). ``import_task_choice`` :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|) :Description: Called after a decision has been made about an import task. Use ``task.choice_flag`` to inspect or change the action. ``import_task_files`` :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|) :Description: Called after filesystem manipulation (copy/move/write) for an import task. ``library_opened`` :Parameters: ``lib`` (|Library|) :Description: Called after beets starts and initializes the main Library object. ``database_change`` :Parameters: ``lib`` (|Library|), ``model`` (|Album| or |Item|) :Description: A modification has been made to the library database (may not yet be committed). ``cli_exit`` :Parameters: ``lib`` (|Library|) :Description: Called just before the ``beet`` command-line program exits. ``import_begin`` :Parameters: ``session`` (|ImportSession|) :Description: Called just before a ``beet import`` session starts. ``trackinfo_received`` :Parameters: ``info`` (|TrackInfo|) :Description: Called after metadata for a track is fetched (e.g., from MusicBrainz). Handlers can modify the tags seen by later pipeline stages or adjustments (e.g., ``mbsync``). ``albuminfo_received`` :Parameters: ``info`` (|AlbumInfo|) :Description: Like ``trackinfo_received`` but for album-level metadata. ``album_matched`` :Parameters: ``match`` (``AlbumMatch``) :Description: Called each time an ``AlbumMatch`` candidate is created while importing. This applies to both ID-driven and text-search matching. Missing and extra tracks, if any, are included in the match. ``before_choose_candidate`` :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|) :Description: Called before prompting the user during interactive import. May return a list of ``PromptChoices`` to append to the prompt (see :ref:`append_prompt_choices`). ``mb_track_extract`` :Parameters: ``data`` (dict) :Description: Called after metadata is obtained from MusicBrainz for a track. Must return a (possibly empty) dict of additional ``field: value`` pairs to apply (overwriting existing fields). ``mb_album_extract`` :Parameters: ``data`` (dict) :Description: Like ``mb_track_extract`` but for album tags. Overwrites tags set at the track level with the same field. ``after_convert`` :Parameters: ``item`` (|Item|), ``dest`` (path), ``keepnew`` (bool) :Description: Called by the :doc:`/plugins/convert` plugin after it successfully converts or copies an item. When ``keepnew`` is false, ``dest`` is the converted file. When ``keepnew`` is true, ``dest`` is where the original file was moved and ``item.path`` identifies the converted file retained in the library. ``smartplaylist_update`` :Parameters: (none) :Description: Called by the :doc:`/plugins/smartplaylist` plugin after it writes updated playlist files. It is not called in pretend mode. The included ``mpdupdate`` plugin provides an example use case for event listeners. beetbox-beets-00724b7/docs/dev/plugins/other/0000775000175000017500000000000015253035401020363 5ustar pieterpieterbeetbox-beets-00724b7/docs/dev/plugins/other/fields.rst0000664000175000017500000000241115253035401022361 0ustar pieterpieterFlexible Field Types ==================== If your plugin uses flexible fields to store numbers or other non-string values, you can specify the types of those fields. A rating plugin, for example, might want to declare that the ``rating`` field should have an integer type: .. code-block:: python from beets.plugins import BeetsPlugin from beets.dbcore import types class RatingPlugin(BeetsPlugin): item_types = {"rating": types.INTEGER} @property def album_types(self): return {"rating": types.INTEGER} A plugin may define two attributes: ``item_types`` and ``album_types``. Each of those attributes is a dictionary mapping a flexible field name to a type instance. You can find the built-in types in the ``beets.dbcore.types`` and ``beets.library`` modules or implement your own type by inheriting from the ``Type`` class. Specifying types has several advantages: - Code that accesses the field like ``item['my_field']`` gets the right type (instead of just a string). - You can use advanced queries (like :ref:`ranges `) from the command line. - User input for flexible fields may be validated and converted. - Items missing the given field can use an appropriate null value for querying and sorting purposes. beetbox-beets-00724b7/docs/dev/plugins/other/index.rst0000664000175000017500000000035715253035401022231 0ustar pieterpieterFurther Reading =============== For more information on writing plugins, feel free to check out the following resources: .. toctree:: :maxdepth: 2 config templates mediafile import fields logging prompts beetbox-beets-00724b7/docs/dev/plugins/other/config.rst0000664000175000017500000000261315253035401022364 0ustar pieterpieterRead Configuration Options ========================== Plugins can configure themselves using the ``config.yaml`` file. You can read configuration values in two ways. The first is to use ``self.config`` within your plugin class. This gives you a view onto the configuration values in a section with the same name as your plugin's module. For example, if your plugin is in ``greatplugin.py``, then ``self.config`` will refer to options under the ``greatplugin:`` section of the config file. For example, if you have a configuration value called "foo", then users can put this in their ``config.yaml``: :: greatplugin: foo: bar To access this value, say ``self.config['foo'].get()`` at any point in your plugin's code. The ``self.config`` object is a *view* as defined by the Confuse_ library. .. _confuse: https://confuse.readthedocs.io/en/latest/ If you want to access configuration values *outside* of your plugin's section, import the ``config`` object from the ``beets`` module. That is, just put ``from beets import config`` at the top of your plugin and access values from there. If your plugin provides configuration values for sensitive data (e.g., passwords, API keys, ...), you should add these to the config so they can be redacted automatically when users dump their config. This can be done by setting each value's ``redact`` flag, like so: :: self.config['password'].redact = True beetbox-beets-00724b7/docs/dev/plugins/other/import.rst0000664000175000017500000000651415253035401022435 0ustar pieterpieter.. _plugin-stage: Add Import Pipeline Stages ========================== Many plugins need to add high-latency operations to the import workflow. For example, a plugin that fetches lyrics from the Web would, ideally, not block the progress of the rest of the importer. Beets allows plugins to add stages to the parallel import pipeline. Each stage is run in its own thread. Plugin stages run after metadata changes have been applied to a unit of music (album or track) and before file manipulation has occurred (copying and moving files, writing tags to disk). Multiple stages run in parallel but each stage processes only one task at a time and each task is processed by only one stage at a time. Plugins provide stages as functions that take two arguments: ``config`` and ``task``, which are ``ImportSession`` and ``ImportTask`` objects (both defined in ``beets.importer``). Add such a function to the plugin's ``import_stages`` field to register it: .. code-block:: python from beets.importer import ImportSession, ImportTask from beets.plugins import BeetsPlugin class ExamplePlugin(BeetsPlugin): def __init__(self): super().__init__() self.import_stages = [self.stage] def stage(self, session: ImportSession, task: ImportTask): print("Importing something!") It is also possible to request your function to run early in the pipeline by adding the function to the plugin's ``early_import_stages`` field instead: .. code-block:: python self.early_import_stages = [self.stage] .. _extend-query: Extend the Query Syntax ----------------------- You can add new kinds of queries to beets' :doc:`query syntax `. There are two ways to add custom queries: using a prefix and using a name. Prefix-based query extension can apply to *any* field, while named queries are not associated with any field. For example, beets already supports regular expression queries, which are indicated by a colon prefix---plugins can do the same. For either kind of query extension, define a subclass of the ``Query`` type from the ``beets.dbcore.query`` module. Then: - To define a prefix-based query, define a ``queries`` method in your plugin class. Return from this method a dictionary mapping prefix strings to query classes. - To define a named query, defined dictionaries named either ``item_queries`` or ``album_queries``. These should map names to query types. So if you use ``{ "foo": FooQuery }``, then the query ``foo:bar`` will construct a query like ``FooQuery("bar")``. For prefix-based queries, you will want to extend ``FieldQuery``, which implements string comparisons on fields. To use it, create a subclass inheriting from that class and override the ``value_match`` class method. (Remember the ``@classmethod`` decorator!) The following example plugin declares a query using the ``@`` prefix to delimit exact string matches. The plugin will be used if we issue a command like ``beet ls @something`` or ``beet ls artist:@something``: .. code-block:: python from beets.plugins import BeetsPlugin from beets.dbcore import FieldQuery class ExactMatchQuery(FieldQuery): @classmethod def value_match(self, pattern, val): return pattern == val class ExactMatchPlugin(BeetsPlugin): def queries(self): return {"@": ExactMatchQuery} beetbox-beets-00724b7/docs/dev/plugins/other/logging.rst0000664000175000017500000000340215253035401022542 0ustar pieterpieter.. _plugin-logging: Logging ======= Each plugin object has a ``_log`` attribute, which behaves like a logger from the `standard Python logging module`_ but is provided by beets' ``BeetsLogger`` class. The logger is set up to `PEP 3101`_, str.format-style string formatting. So you can write logging calls like this: .. code-block:: python self._log.debug("Processing {0.title} by {0.artist}", item) For especially noisy diagnostics, plugins can use ``self._log.extra_debug(...)``. These messages are logged at ``DEBUG`` level only when beets is run with verbosity level 3 or higher, such as ``-vvv``. .. _pep 3101: https://peps.python.org/pep-3101/ .. _standard python logging module: https://docs.python.org/3/library/logging.html When beets is in verbose mode, plugin messages are prefixed with the plugin name to make them easier to see. Which messages will be logged depends on the logging level and the action performed: - Inside import stages and event handlers, the default is ``WARNING`` messages and above. - Everywhere else, the default is ``INFO`` or above. The verbosity can be increased with ``--verbose`` (``-v``) flags: each flags lowers the level by a notch. That means that, with a single ``-v`` flag, event handlers won't have their ``DEBUG`` messages displayed, but command functions (for example) will. With ``-vv`` on the command line, ``DEBUG`` messages will be displayed everywhere. This addresses a common pattern where plugins need to use the same code for a command and an import stage, but the command needs to print more messages than the import stage. (For example, you'll want to log "found lyrics for this song" when you're run explicitly as a command, but you don't want to noisily interrupt the importer interface when running automatically.) beetbox-beets-00724b7/docs/dev/plugins/other/templates.rst0000664000175000017500000000357415253035401023124 0ustar pieterpieterAdd Path Format Functions and Fields ==================================== Beets supports *function calls* in its path format syntax (see :doc:`/reference/pathformat`). Beets includes a few built-in functions, but plugins can register new functions by adding them to the ``template_funcs`` dictionary. Here's an example: .. code-block:: python class MyPlugin(BeetsPlugin): def __init__(self): super().__init__() self.template_funcs["initial"] = _tmpl_initial def _tmpl_initial(text: str) -> str: if text: return text[0].upper() else: return "" This plugin provides a function ``%initial`` to path templates where ``%initial{$artist}`` expands to the artist's initial (its capitalized first character). Plugins can also add template *fields*, which are computed values referenced as ``$name`` in templates. To add a new field, add a function that takes an ``Item`` object to the ``template_fields`` dictionary on the plugin object. Here's an example that adds a ``$disc_and_track`` field: .. code-block:: python class MyPlugin(BeetsPlugin): def __init__(self): super().__init__() self.template_fields["disc_and_track"] = _tmpl_disc_and_track def _tmpl_disc_and_track(item: Item) -> str: """Expand to the disc number and track number if this is a multi-disc release. Otherwise, just expands to the track number. """ if item.disctotal > 1: return "%02i.%02i" % (item.disc, item.track) else: return "%02i" % (item.track) With this plugin enabled, templates can reference ``$disc_and_track`` as they can any standard metadata field. This field works for *item* templates. Similarly, you can register *album* template fields by adding a function accepting an ``Album`` argument to the ``album_template_fields`` dict. beetbox-beets-00724b7/docs/dev/plugins/other/mediafile.rst0000664000175000017500000000204115253035401023031 0ustar pieterpieterExtend MediaFile ================ MediaFile_ is the file tag abstraction layer that beets uses to make cross-format metadata manipulation simple. Plugins can add fields to MediaFile to extend the kinds of metadata that they can easily manage. The ``MediaFile`` class uses ``MediaField`` descriptors to provide access to file tags. If you have created a descriptor you can add it through your plugins :py:meth:`beets.plugins.BeetsPlugin.add_media_field` method. .. _mediafile: https://mediafile.readthedocs.io/en/latest/ Here's an example plugin that provides a meaningless new field "foo": .. code-block:: python class FooPlugin(BeetsPlugin): def __init__(self): field = mediafile.MediaField( mediafile.MP3DescStorageStyle("foo"), mediafile.StorageStyle("foo") ) self.add_media_field("foo", field) FooPlugin() item = Item.from_path("/path/to/foo/tag.mp3") assert item["foo"] == "spam" item["foo"] == "ham" item.write() # The "foo" tag of the file is now "ham" beetbox-beets-00724b7/docs/dev/plugins/other/prompts.rst0000664000175000017500000000507315253035401022626 0ustar pieterpieter.. _append_prompt_choices: Append Prompt Choices ===================== Plugins can also append choices to the prompt presented to the user during an import session. To do so, add a listener for the ``before_choose_candidate`` event, and return a list of ``PromptChoices`` that represent the additional choices that your plugin shall expose to the user: .. code-block:: python from beets.plugins import BeetsPlugin from beets.util import PromptChoice class ExamplePlugin(BeetsPlugin): def __init__(self): super().__init__() self.register_listener( "before_choose_candidate", self.before_choose_candidate_event ) def before_choose_candidate_event(self, session, task): return [ PromptChoice("p", "Print foo", self.foo), PromptChoice("d", "Do bar", self.bar), ] def foo(self, session, task): print('User has chosen "Print foo"!') def bar(self, session, task): print('User has chosen "Do bar"!') The previous example modifies the standard prompt: .. code-block:: shell # selection (default 1), Skip, Use as-is, as Tracks, Group albums, Enter search, enter Id, aBort? by appending two additional options (``Print foo`` and ``Do bar``): .. code-block:: shell # selection (default 1), Skip, Use as-is, as Tracks, Group albums, Enter search, enter Id, aBort, Print foo, Do bar? If the user selects a choice, the ``callback`` attribute of the corresponding ``PromptChoice`` will be called. It is the responsibility of the plugin to check for the status of the import session and decide the choices to be appended: for example, if a particular choice should only be presented if the album has no candidates, the relevant checks against ``task.candidates`` should be performed inside the plugin's ``before_choose_candidate_event`` accordingly. Please make sure that the short letter for each of the choices provided by the plugin is not already in use: the importer will emit a warning and discard all but one of the choices using the same letter, giving priority to the core importer prompt choices. As a reference, the following characters are used by the choices on the core importer prompt, and hence should not be used: ``a``, ``s``, ``u``, ``t``, ``g``, ``e``, ``i``, ``b``. Additionally, the callback function can optionally specify the next action to be performed by returning a ``importer.Action`` value. It may also return a ``autotag.Proposal`` value to update the set of current proposals to be considered. beetbox-beets-00724b7/docs/dev/plugins/autotagger.rst0000664000175000017500000001233315253035401022140 0ustar pieterpieterExtending the Autotagger ======================== .. currentmodule:: beets.metadata_plugins Beets supports **metadata source plugins**, which allow it to fetch and match metadata from external services (such as Spotify, Discogs, or Deezer). This guide explains how to build your own metadata source plugin by extending either :py:class:`MetadataSourcePlugin` or :py:class:`SearchApiMetadataSourcePlugin`. These plugins integrate directly with the autotagger, providing candidate metadata during lookups. To implement one, you must subclass :py:class:`MetadataSourcePlugin` (or the search API helper base class) and implement its abstract methods. Overview -------- Creating a metadata source plugin is very similar to writing a standard plugin (see :ref:`basic-plugin-setup`). The main difference is that your plugin must: 1. Subclass :py:class:`MetadataSourcePlugin` or :py:class:`SearchApiMetadataSourcePlugin`. 2. Implement all required abstract methods. Here`s a minimal example: .. code-block:: python # beetsplug/myawesomeplugin.py from typing import Sequence from beets.library import Item from beets.metadata_plugins import MetadataSourcePlugin class MyAwesomePlugin(MetadataSourcePlugin): def candidates( self, items: Sequence[Item], artist: str, album: str, va_likely: bool, ): ... def item_candidates(self, item: Item, artist: str, title: str): ... def track_for_id(self, track_id: str): ... def album_for_id(self, album_id: str): ... For API-backed metadata sources, prefer :py:class:`SearchApiMetadataSourcePlugin` to reuse shared search orchestration: .. code-block:: python from beets.metadata_plugins import SearchApiMetadataSourcePlugin, SearchParams class MyApiPlugin(SearchApiMetadataSourcePlugin): def get_search_query_with_filters(self, query_type, items, artist, name, va_likely): query = f'album:"{name}"' if query_type == "album" else name if query_type == "track" or not va_likely: query += f' artist:"{artist}"' return query, {} def get_search_response(self, params: SearchParams): # Execute provider API request and return results with "id" fields. ... def track_for_id(self, track_id: str): ... def album_for_id(self, album_id: str): ... The shared base class centralizes query normalization, ``search_limit`` handling, candidate wiring, and consistent error logging for search requests. Provider-specific behavior is implemented in :py:meth:`~SearchApiMetadataSourcePlugin.get_search_query_with_filters` and :py:meth:`~SearchApiMetadataSourcePlugin.get_search_response`. Each metadata source plugin automatically gets a unique identifier. You can access this identifier using the :py:meth:`~MetadataSourcePlugin.data_source` class property to tell plugins apart. Metadata lookup --------------- When beets runs the autotagger, it queries **all enabled metadata source plugins** for potential matches: - For **albums**, it calls :py:meth:`~MetadataSourcePlugin.candidates`. - For **singletons**, it calls :py:meth:`~MetadataSourcePlugin.item_candidates`. The results are combined and scored. By default, candidate ranking is handled automatically by the beets core, but you can customize weighting by overriding: - :py:meth:`~MetadataSourcePlugin.album_distance` - :py:meth:`~MetadataSourcePlugin.track_distance` This is optional, if not overridden, both methods return a constant distance of `0.5`. ID-based lookups ---------------- Your plugin must also define: - :py:meth:`~MetadataSourcePlugin.album_for_id` — fetch album metadata by ID. - :py:meth:`~MetadataSourcePlugin.track_for_id` — fetch track metadata by ID. IDs are expected to be strings. If your source uses specific formats, consider contributing an extractor regex to the core module: :py:mod:`beets.util.id_extractors`. When beets matches by explicit IDs (for example via ``--search-id`` or existing ``mb_*id`` fields), it asks every enabled metadata source plugin for candidates using :py:meth:`~MetadataSourcePlugin.albums_for_ids` and :py:meth:`~MetadataSourcePlugin.tracks_for_ids`. Candidate identity is tracked by ``(data_source, id)``, so identical IDs from different providers remain separate options. If you need to query one specific provider, use the module helpers :py:func:`beets.metadata_plugins.album_for_id` and :py:func:`beets.metadata_plugins.track_for_id` and pass both the ID and the provider ``data_source`` name. Best practices -------------- Beets already ships with several metadata source plugins. Studying these implementations can help you follow conventions and avoid pitfalls. Good starting points include: - ``spotify`` - ``deezer`` - ``discogs`` Migration guidance ------------------ Older metadata plugins that extend |BeetsPlugin| should be migrated to :py:class:`MetadataSourcePlugin`. API-backed sources should generally migrate to :py:class:`SearchApiMetadataSourcePlugin` to avoid duplicating search orchestration. Legacy support will be removed in **beets v3.0.0**. .. seealso:: - :py:mod:`beets.autotag` - :py:mod:`beets.metadata_plugins` - :ref:`autotagger_extensions` - :ref:`using-the-auto-tagger` beetbox-beets-00724b7/docs/dev/plugins/commands.rst0000664000175000017500000000424115253035401021576 0ustar pieterpieter.. _add_subcommands: Add Commands to the CLI ======================= Plugins can add new subcommands to the ``beet`` command-line interface. Define the plugin class' ``commands()`` method to return a list of ``Subcommand`` objects. (The ``Subcommand`` class is defined in the ``beets.ui`` module.) Here's an example plugin that adds a simple command: .. code-block:: python from beets.plugins import BeetsPlugin from beets.ui import Subcommand my_super_command = Subcommand("super", help="do something super") def say_hi(lib, opts, args): print("Hello everybody! I'm a plugin!") my_super_command.func = say_hi class SuperPlug(BeetsPlugin): def commands(self): return [my_super_command] To make a subcommand, invoke the constructor like so: ``Subcommand(name, parser, help, aliases)``. The ``name`` parameter is the only required one and should just be the name of your command. ``parser`` can be an `OptionParser instance`_, but it defaults to an empty parser (you can extend it later). ``help`` is a description of your command, and ``aliases`` is a list of shorthand versions of your command name. .. _optionparser instance: https://docs.python.org/3/library/optparse.html You'll need to add a function to your command by saying ``mycommand.func = myfunction``. This function should take the following parameters: ``lib`` (a beets ``Library`` object) and ``opts`` and ``args`` (command-line options and arguments as returned by OptionParser.parse_args_). .. _optionparser.parse_args: https://docs.python.org/3/library/optparse.html#parsing-arguments The function should use any of the utility functions defined in ``beets.ui``. Try running ``pydoc beets.ui`` to see what's available. You can add command-line options to your new command using the ``parser`` member of the ``Subcommand`` class, which is a ``CommonOptionsParser`` instance. Just use it like you would a normal ``OptionParser`` in an independent script. Note that it offers several methods to add common options: ``--album``, ``--path`` and ``--format``. This feature is versatile and extensively documented, try ``pydoc beets.ui.CommonOptionsParser`` for more information. beetbox-beets-00724b7/docs/dev/importer.rst0000664000175000017500000000176015253035401020160 0ustar pieterpieterMusic Importer ============== The importer component is responsible for the user-centric workflow that adds music to a library. This is one of the first aspects that a user experiences when using beets: it finds music in the filesystem, groups it into albums, finds corresponding metadata in MusicBrainz, asks the user for intervention, applies changes, and moves/copies files. A description of its user interface is given in :doc:`/guides/tagger`. The workflow is implemented in the ``beets.importer`` module and is distinct from the core logic for matching MusicBrainz metadata (in the ``beets.autotag`` module). The workflow is also decoupled from the command-line interface with the hope that, eventually, other (graphical) interfaces can be bolted onto the same importer implementation. The importer is multithreaded and follows the pipeline pattern. Each pipeline stage is a Python coroutine. The ``beets.util.pipeline`` module houses a generic, reusable implementation of a multithreaded pipeline. beetbox-beets-00724b7/docs/dev/library.rst0000664000175000017500000002406415253035401017765 0ustar pieterpieterLibrary Database API ==================== .. currentmodule:: beets.library This page describes the internal API of beets' core database features. It doesn't exhaustively document the API, but is aimed at giving an overview of the architecture to orient anyone who wants to dive into the code. The |Library| object is the central repository for data in beets. It represents a database containing songs, which are |Item| instances, and groups of items, which are |Album| instances. The Library Class ----------------- The |Library| is typically instantiated as a singleton. A single invocation of beets usually has only one |Library|. It's powered by :class:`dbcore.Database` under the hood, which handles the SQLite_ abstraction, something like a very minimal ORM_. The library is also responsible for handling queries to retrieve stored objects. Overview ~~~~~~~~ You can add new items or albums to the library via the :py:meth:`Library.add` and :py:meth:`Library.add_album` methods. You may also query the library for items and albums using the :py:meth:`Library.items`, :py:meth:`Library.albums`, :py:meth:`Library.get_item` and :py:meth:`Library.get_album` methods. Any modifications to the library must go through a :class:`Transaction` object, which you can get using the :py:meth:`Library.transaction` context manager. .. _orm: https://en.wikipedia.org/wiki/Object-relational_mapping .. _sqlite: https://sqlite.org/index.html Model Classes ------------- The two model entities in beets libraries, |Item| and |Album|, share a base class, :class:`LibModel`, that provides common functionality. That class itself specialises :class:`beets.dbcore.Model` which provides an ORM-like abstraction. To get or change the metadata of a model (an item or album), either access its attributes (e.g., ``print(album.year)`` or ``album.year = 2012``) or use the ``dict``-like interface (e.g. ``item['artist']``). Model base ~~~~~~~~~~ Models use dirty-flags to track when the object's metadata goes out of sync with the database. The dirty dictionary maps field names to booleans indicating whether the field has been written since the object was last synchronized (via load or store) with the database. This logic is implemented in the model base class :class:`LibModel` and is inherited by both |Item| and |Album|. We provide CRUD-like methods for interacting with the database: - :py:meth:`LibModel.store` - :py:meth:`LibModel.load` - :py:meth:`LibModel.remove` - :py:meth:`LibModel.add` The base class :class:`beets.dbcore.Model` has a ``dict``-like interface, so normal the normal mapping API is supported: - :py:meth:`LibModel.keys` - :py:meth:`LibModel.update` - :py:meth:`LibModel.items` - :py:meth:`LibModel.get` Item ~~~~ Each |Item| object represents a song or track. (We use the more generic term item because, one day, beets might support non-music media.) An item can either be purely abstract, in which case it's just a bag of metadata fields, or it can have an associated file (indicated by ``item.path``). In terms of the underlying SQLite database, items are backed by a single table called items with one column per metadata fields. The metadata fields currently in use are listed in ``library.py`` in ``Item._fields``. To read and write a file's tags, we use the MediaFile_ library. To make changes to either the database or the tags on a file, you update an item's fields (e.g., ``item.title = "Let It Be"``) and then call ``item.write()``. .. _mediafile: https://mediafile.readthedocs.io/en/latest/ Items also track their modification times (mtimes) to help detect when they become out of sync with on-disk metadata, mainly to speed up the :ref:`update-cmd` (which needs to check whether the database is in sync with the filesystem). This feature turns out to be sort of complicated. For any |Item|, there are two mtimes: the on-disk mtime (maintained by the OS) and the database mtime (maintained by beets). Correspondingly, there is on-disk metadata (ID3 tags, for example) and DB metadata. The goal with the mtime is to ensure that the on-disk and DB mtimes match when the on-disk and DB metadata are in sync; this lets beets do a quick mtime check and avoid rereading files in some circumstances. Specifically, beets attempts to maintain the following invariant: If the on-disk metadata differs from the DB metadata, then the on-disk mtime must be greater than the DB mtime. As a result, it is always valid for the DB mtime to be zero (assuming that real disk mtimes are always positive). However, whenever possible, beets tries to set ``db_mtime = disk_mtime`` at points where it knows the metadata is synchronized. When it is possible that the metadata is out of sync, beets can then just set ``db_mtime = 0`` to return to a consistent state. This leads to the following implementation policy: - On every write of disk metadata (``Item.write()``), the DB mtime is updated to match the post-write disk mtime. - Same for metadata reads (``Item.read()``). - On every modification to DB metadata (``item.field = ...``), the DB mtime is reset to zero. Album ~~~~~ An |Album| is a collection of Items in the database. Every item in the database has either zero or one associated albums (accessible via ``item.album_id``). An item that has no associated album is called a singleton. Changing fields on an album (e.g. ``album.year = 2012``) updates the album itself and also changes the same field in all associated items. An |Album| object keeps track of album-level metadata, which is (mostly) a subset of the track-level metadata. The album-level metadata fields are listed in ``Album._fields``. For those fields that are both item-level and album-level (e.g., ``year`` or ``albumartist``), every item in an album should share the same value. Albums use an SQLite table called ``albums``, in which each column is an album metadata field. .. note:: The :py:meth:`Album.items` method is not inherited from :py:meth:`LibModel.items` for historical reasons. Transactions ~~~~~~~~~~~~ The |Library| class provides the basic methods necessary to access and manipulate its contents. To perform more complicated operations atomically, or to interact directly with the underlying SQLite database, you must use a *transaction* (see this `blog post`_ for motivation). For example .. code-block:: python lib = Library() with lib.transaction() as tx: items = lib.items(query) lib.add_album(list(items)) .. currentmodule:: beets.dbcore.db The :class:`Transaction` class is a context manager that provides a transactional interface to the underlying SQLite database. It is responsible for managing the transaction's lifecycle, including beginning, committing, and rolling back the transaction if an error occurs. .. _blog post: https://beets.io/blog/sqlite-nightmare.html Migrations ~~~~~~~~~~ The database layer includes a first-class migration system for data changes that must happen alongside schema evolution. This keeps compatibility work explicit, testable, and isolated from normal query and model code. Each database subclass declares its migrations in ``_migrations`` as pairs of a migration class and the model classes it applies to. During startup, the database creates required tables and columns first, then executes configured migrations. Migration completion is tracked in a dedicated ``migrations`` table keyed by migration name and table name. This means each migration runs at most once per table, so large one-time data rewrites can be safely coordinated across restarts. The migration name is derived from the migration class name. Because that name is the persisted identity in the ``migrations`` table, renaming a released migration class changes its identity and can cause the migration to run again. Treat migration class names as stable once shipped. For example, ``MultiGenreFieldMigration`` becomes ``multi_genre_field``. After it runs for the ``items`` table, beets records a row equivalent to: .. code-block:: text name = "multi_genre_field", table_name = "items" Common use cases include: 1. Backfilling a newly introduced canonical field from older data. 2. Normalizing legacy free-form values into a structured representation. 3. Splitting mixed-content legacy fields into cleaned primary content plus auxiliary metadata stored as flexible attributes. To add a migration: 1. Create a :class:`beets.dbcore.db.Migration` subclass. 2. Implement the table-specific data rewrite logic in ``_migrate_data``. 3. Register the migration in the database subclass ``_migrations`` list for the target models. In practice, migrations should be idempotent and conservative: gate behavior on the current schema when needed, keep writes transactional, and batch large updates so startup remains predictable for real libraries. Queries ------- .. currentmodule:: beets.dbcore.query To access albums and items in a library, we use :doc:`/reference/query`. In beets, the :class:`Query` abstract base class represents a criterion that matches items or albums in the database. Every subclass of :class:`Query` must implement two methods, which implement two different ways of identifying matching items/albums. The ``clause()`` method should return an SQLite ``WHERE`` clause that matches appropriate albums/items. This allows for efficient batch queries. Correspondingly, the ``match(item)`` method should take an |Item| object and return a boolean, indicating whether or not a specific item matches the criterion. This alternate implementation allows clients to determine whether items that have already been fetched from the database match the query. There are many different types of queries. Just as an example, :class:`FieldQuery` determines whether a certain field matches a certain value (an equality query). :class:`AndQuery` (like its abstract superclass, :class:`CollectionQuery`) takes a set of other query objects and bundles them together, matching only albums/items that match all constituent queries. Beets has a human-writable plain-text query syntax that can be parsed into :class:`Query` objects. Calling ``AndQuery.from_strings`` parses a list of query parts into a query object that can then be used with |Library| objects. beetbox-beets-00724b7/docs/api/0000775000175000017500000000000015253035401015554 5ustar pieterpieterbeetbox-beets-00724b7/docs/api/index.rst0000664000175000017500000000017315253035401017416 0ustar pieterpieterAPI Reference ============= .. toctree:: :maxdepth: 2 :titlesonly: plugins plugin_utilities database beetbox-beets-00724b7/docs/api/plugins.rst0000664000175000017500000000042115253035401017764 0ustar pieterpieterPlugins ======= .. currentmodule:: beets.plugins .. autosummary:: :toctree: generated/ BeetsPlugin .. currentmodule:: beets.metadata_plugins .. autosummary:: :toctree: generated/ MetadataSourcePlugin SearchApiMetadataSourcePlugin SearchParams beetbox-beets-00724b7/docs/api/database.rst0000664000175000017500000000075315253035401020057 0ustar pieterpieterDatabase ======== .. currentmodule:: beets.library Library ------- .. autosummary:: :toctree: generated/ Library Models ------ .. autosummary:: :toctree: generated/ LibModel Album Item Transactions ------------ .. currentmodule:: beets.dbcore.db .. autosummary:: :toctree: generated/ Migration Transaction Queries ------- .. currentmodule:: beets.dbcore.query .. autosummary:: :toctree: generated/ Query FieldQuery AndQuery beetbox-beets-00724b7/docs/api/plugin_utilities.rst0000664000175000017500000000037715253035401021706 0ustar pieterpieterPlugin Utilities ================ .. currentmodule:: beetsplug._utils.requests .. autosummary:: :toctree: generated/ RequestHandler .. currentmodule:: beetsplug._utils.musicbrainz .. autosummary:: :toctree: generated/ MusicBrainzAPI beetbox-beets-00724b7/docs/guides/0000775000175000017500000000000015253035401016263 5ustar pieterpieterbeetbox-beets-00724b7/docs/guides/index.rst0000664000175000017500000000040515253035401020123 0ustar pieterpieterGuides ====== This section contains a couple of walkthroughs that will help you get familiar with beets. If you're new to beets, you'll want to begin with the :doc:`main` guide. .. toctree:: :maxdepth: 1 main installation tagger advanced beetbox-beets-00724b7/docs/guides/installation.rst0000664000175000017500000001442015253035401021517 0ustar pieterpieterInstallation ============ Beets requires `Python 3.10 or later`_. You can install it using uv_ or pip_. .. _python 3.10 or later: https://www.python.org/downloads/ Using ``uv tool`` or ``pip`` ---------------------------- We recommend installing with ``uv tool`` as it isolates beets and its dependencies from your system Python and other Python packages. This helps avoid dependency conflicts and keeps your system clean. .. .. tab-set:: .. tab-item:: uv tool .. code-block:: console uv tool install beets .. tab-item:: pipx .. code-block:: console pipx install beets .. tab-item:: pip .. code-block:: console pip install beets .. tab-item:: pip (user install) .. code-block:: console pip install --user beets .. If you don't have uv_ installed, you can follow the `uv installation instructions`_ to get it set up. .. _pip: https://pip.pypa.io/en/stable/ .. _uv: https://docs.astral.sh/uv/ .. _uv installation instructions: https://docs.astral.sh/uv/getting-started/installation/ Managing Plugins with ``uv tool`` --------------------------------- When using ``uv tool``, you can install beets with built-in plugin dependencies using extras, include third-party packages, and upgrade everything cleanly. Install beets with extras for built-in plugins: .. code-block:: console uv tool install "beets[lyrics,lastgenre]" If you already have beets installed, reinstall with a new set of extras: .. code-block:: console uv tool install --force "beets[lyrics,lastgenre]" Include additional packages in the beets environment (useful for third-party plugins): .. code-block:: console uv tool install --force --with beets To upgrade beets and included packages: .. code-block:: console uv tool upgrade beets Installation FAQ ---------------- Windows Installation ~~~~~~~~~~~~~~~~~~~~ **Q: What's the process for installing on Windows?** Installing beets on Windows can be tricky. Following these steps might help you get it right: 1. `Install Python`_ (check "Add Python to PATH" skip to 3) 2. Ensure Python is in your ``PATH`` (add if needed): - Settings → System → About → Advanced system settings → Environment Variables - Edit "PATH" and add: `;C:\Python39;C:\Python39\Scripts` - *Guide: [Adding Python to PATH](https://realpython.com/add-python-to-path/)* 3. Now install beets by running: ``pip install beets`` 4. You're all set! Type ``beet version`` in a new command prompt to verify the installation. .. note:: The classic Windows console (``cmd.exe``) does not display beets' output (special characters and colors) correctly. For a usable experience, run beets in a terminal emulator such as `Windows Terminal`_ or cmder_, or in a Unix-like shell such as Git Bash. .. _cmder: https://cmder.app/ .. _windows terminal: https://aka.ms/terminal **Bonus: Windows Context Menu Integration** Windows users may also want to install a context menu item for importing files into beets. Download the beets.reg_ file and open it in a text file to make sure the paths to Python match your system. Then double-click the file add the necessary keys to your registry. You can then right-click a directory and choose "Import with beets". .. _beets.reg: https://github.com/beetbox/beets/blob/master/extra/beets.reg .. _install pip: https://pip.pypa.io/en/stable/installing/ .. _install python: https://www.python.org/downloads/ ARM Installation ~~~~~~~~~~~~~~~~ **Q: Can I run beets on a Raspberry Pi or other ARM device?** Yes, but with some considerations: Beets on ARM devices is not recommended for Linux novices. If you are comfortable with troubleshooting tools like ``pip``, ``make``, and binary dependencies (e.g. ``ffmpeg`` and ``ImageMagick``), you will be fine. We have `notes for ARM`_ and an `older ARM reference`_. Beets is generally developed on x86-64 based devices, and most plugins target that platform as well. .. _notes for arm: https://github.com/beetbox/beets/discussions/4910 .. _older arm reference: https://discourse.beets.io/t/diary-of-beets-on-arm-odroid-hc4-armbian/1993 Package Manager Installation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Q: Can I install beets using my operating system's built-in package manager?** We generally don't recommend this route. OS package managers tend to ship outdated versions of beets, and installing third-party plugins into a system-managed environment ranges from awkward to impossible. You'll have a much better time with ``uv tool`` or pip_ as described above. That said, if you know what you're doing and prefer your system package manager, here are the options available: - **Debian/Ubuntu** (`Debian `_, `Ubuntu `_): ``apt-get install beets`` - **Arch Linux** (`extra `_, `AUR dev `_): ``pacman -S beets`` - **Alpine Linux** (`package `_): ``apk add beets`` - **Void Linux** (`package `_): ``xbps-install -S beets`` - **Gentoo Linux**: ``emerge beets`` (USE flags available for optional plugin deps) - **FreeBSD** (`port `_): ``audio/beets`` - **OpenBSD** (`port `_): ``pkg_add beets`` - **Fedora** (`package `_): ``dnf install beets beets-plugins beets-doc`` - **Solus**: ``eopkg install beets`` - **NixOS** (`package `_): ``nix-env -i beets`` - **Homebrew** (`formula `_): ``brew install beets`` - **MacPorts**: ``port install beets`` or ``port install beets-full`` (includes third-party plugins) .. _alpine package: https://pkgs.alpinelinux.org/package/edge/community/x86_64/beets .. _arch btw: https://archlinux.org/packages/extra/any/beets/ .. _aur: https://aur.archlinux.org/packages/beets-git/ .. _debian details: https://tracker.debian.org/pkg/beets .. _dnf package: https://packages.fedoraproject.org/pkgs/beets/ .. _freebsd: https://www.freshports.org/audio/beets/ .. _homebrew: https://formulae.brew.sh/formula/beets .. _nixos: https://github.com/NixOS/nixpkgs/tree/master/pkgs/development/python-modules/beets .. _openbsd: https://openports.pl/path/audio/beets .. _ubuntu details: https://launchpad.net/ubuntu/+source/beets .. _void package: https://github.com/void-linux/void-packages/tree/master/srcpkgs/beets beetbox-beets-00724b7/docs/guides/tagger.rst0000664000175000017500000003626315253035401020300 0ustar pieterpieter.. _using-the-auto-tagger: Using the Auto-Tagger ===================== Beets' automatic metadata correcter is sophisticated but complicated and cryptic. This is a guide to help you through its myriad inputs and options. An Apology and a Brief Interlude -------------------------------- I would like to sincerely apologize that the autotagger in beets is so fussy. It asks you a *lot* of complicated questions, insecurely asking that you verify nearly every assumption it makes. This means importing and correcting the tags for a large library can be an endless, tedious process. I'm sorry for this. Maybe it will help to think of it as a tradeoff. By carefully examining every album you own, you get to become more familiar with your library, its extent, its variation, and its quirks. People used to spend hours lovingly sorting and resorting their shelves of LPs. In the iTunes age, many of us toss our music into a heap and forget about it. This is great for some people. But there's value in intimate, complete familiarity with your collection. So instead of a chore, try thinking of correcting tags as quality time with your music collection. That's what I do. One practical piece of advice: because beets' importer runs in multiple threads, it queues up work in the background while it's waiting for you to respond. So if you find yourself waiting for beets for a few seconds between every question it asks you, try walking away from the computer for a while, making some tea, and coming back. Beets will have a chance to catch up with you and will ask you questions much more quickly. Back to the guide. Overview -------- Beets' tagger is invoked using the ``beet import`` command. Point it at a directory and it imports the files into your library, tagging them as it goes (unless you pass ``--noautotag``, of course). There are several assumptions beets currently makes about the music you import. In time, we'd like to remove all of these limitations. - Your music should be organized by album into directories. That is, the tagger assumes that each album is in a single directory. These directories can be arbitrarily deep (like ``music/2010/hiphop/seattle/freshespresso/glamour``), but any directory with music files in it is interpreted as a separate album. There are, however, a couple of exceptions to this rule: First, directories that look like separate parts of a *multi-disc album* are tagged together as a single release. If two adjacent albums have a common prefix, followed by "disc," "disk," "CD," "cassette," "digital media," or "vinyl" and then a number, they are tagged together. Second, if you have jumbled directories containing more than one album, you can ask beets to split them apart for you based on their metadata. Use either the ``--group-albums`` command-line flag or the *G* interactive option described below. - The music may have bad tags, but it's not completely untagged. This is because beets by default infers tags based on existing metadata. But this is not a hard and fast rule---there are a few ways to tag metadata-poor music: - You can use the *E* or *I* options described below to search in MusicBrainz for a specific album or song. - The :doc:`Acoustid plugin ` extends the autotagger to use acoustic fingerprinting to find information for arbitrary audio. Install that plugin if you're willing to spend a little more CPU power to get tags for unidentified albums. (But be aware that it does slow down the process.) - The :doc:`FromFilename plugin ` adds the ability to guess tags from the filenames. Use this plugin if your tracks have useful names (like "03 Call Me Maybe.mp3") but their tags don't reflect that. - Currently, MP3, AAC, FLAC, ALAC, Ogg Vorbis, Monkey's Audio, WavPack, Musepack, Windows Media, Opus, and AIFF files are supported. (Do you use some other format? Please `file a feature request`_!) .. _file a feature request: https://github.com/beetbox/beets/issues/new?template=feature-request.md Now that that's out of the way, let's tag some music. .. _import-options: Options ------- To import music, just say ``beet import MUSICDIR``. There are, of course, a few command-line options you should know: - ``beet import -A``: don't try to autotag anything; just import files (this goes much faster than with autotagging enabled) - ``beet import -W``: when autotagging, don't write new tags to the files themselves (just keep the new metadata in beets' database) - ``beet import -C``: don't copy imported files to your music directory; leave them where they are - ``beet import -m``: move imported files to your music directory (overrides the ``-c`` option) - ``beet import -M``: don't move imported files to your music directory (overrides the ``-m`` option) - ``beet import -l LOGFILE``: write a message to ``LOGFILE`` every time you skip an album or choose to take its tags "as-is" (see below) or the album is skipped as a duplicate; this lets you come back later and reexamine albums that weren't tagged successfully. Run ``beet import --from-logfile=LOGFILE`` rerun the importer on such paths from the logfile. - ``beet import -q``: quiet mode. Never prompt for input and, instead, conservatively skip any albums that need your opinion. The ``-ql`` combination is recommended. - ``beet import -t``: timid mode, which is sort of the opposite of "quiet." The importer will ask your permission for everything it does, confirming even very good matches with a prompt. - ``beet import -p``: automatically resume an interrupted import. The importer keeps track of imports that don't finish completely (either due to a crash or because you stop them halfway through) and, by default, prompts you to decide whether to resume them. The ``-p`` flag automatically says "yes" to this question. Relatedly, ``-P`` flag automatically says "no." - ``beet import -s``: run in *singleton* mode, tagging individual tracks instead of whole albums at a time. See the "as Tracks" choice below. This means you can use ``beet import -AC`` to quickly add a bunch of files to your library without doing anything to them. - ``beet import -g``: assume there are multiple albums contained in each directory. The tracks contained a directory are grouped by album artist and album name and you will be asked to import each of these groups separately. See the "Group albums" choice below. Similarity ---------- So you import an album into your beets library. It goes like this: :: $ beet imp witchinghour Tagging: Ladytron - Witching Hour (Similarity: 98.4%) * Last One Standing -> The Last One Standing * Beauty -> Beauty*2 * White Light Generation -> Whitelightgenerator * All the Way -> All the Way... Here, beets gives you a preview of the album match it has found. It shows you which track titles will be changed if the match is applied. In this case, beets has found a match and thinks it's a good enough match to proceed without asking your permission. It has reported the *similarity* for the match it's found. Similarity is a measure of how well-matched beets thinks a tagging option is. 100% similarity means a perfect match 0% indicates a truly horrible match. In this case, beets has proceeded automatically because it found an option with very high similarity (98.4%). But, as you'll notice, if the similarity isn't quite so high, beets will ask you to confirm changes. This is because beets can't be very confident about more dissimilar matches, and you (as a human) are better at making the call than a computer. So it occasionally asks for help. Choices ------- When beets needs your input about a match, it says something like this: :: Tagging: Beirut - Lon Gisland (Similarity: 94.4%) * Scenic World (Second Version) -> Scenic World [A]pply, More candidates, Skip, Use as-is, as Tracks, Group albums, Rescan directory, Enter search, enter Id, or aBort? When beets asks you this question, it wants you to enter one of the capital letters: A, M, S, U, T, G, R, E, I or B. That is, you can choose one of the following: - *A*: Apply the suggested changes shown and move on. - *M*: Show more options. (See the Candidates section, below.) - *S*: Skip this album entirely and move on to the next one. - *U*: Import the album without changing any tags. This is a good option for albums that aren't in the MusicBrainz database, like your friend's operatic faux-goth solo record that's only on two CD-Rs in the universe. - *T*: Import the directory as *singleton* tracks, not as an album. Choose this if the tracks don't form a real release---you just have one or more loner tracks that aren't a full album. This will temporarily flip the tagger into *singleton* mode, which attempts to match each track individually. - *G*: Group tracks in this directory by *album artist* and *album* and import groups as albums. If the album artist for a track is not set then the artist is used to group that track. For each group importing proceeds as for directories. This is helpful if a directory contains multiple albums. - *R*: Rescan the directory from disk and re-run the match. Use this if you want to clean up the files (remove duplicates or junk, add missing tracks, etc.) without restarting the whole ``beet import`` run---just make your changes on disk before choosing this option. - *E*: Enter an artist and album to use as a search in the database. Use this option if beets hasn't found any good options because the album is mistagged or untagged. - *I*: Enter a metadata backend ID to use as search in the database. Use this option to specify a backend entity (for example, a MusicBrainz release or recording) directly, by pasting its ID or the full URL. You can also specify several IDs by separating them by a space. - *B*: Cancel this import task altogether. No further albums will be tagged; beets shuts down immediately. The next time you attempt to import the same directory, though, beets will ask you if you want to resume tagging where you left off. Note that the option with ``[B]rackets`` is the default---so if you want to apply the changes, you can just hit return without entering anything. Candidates ---------- If you choose the M option, or if beets isn't very confident about any of the choices it found, it will present you with a list of choices (called candidates), like so: :: Finding tags for "Panther - Panther". Candidates: 1. Panther - Yourself (66.8%) 2. Tav Falco's Panther Burns - Return of the Blue Panther (30.4%) # selection (default 1), Skip, Use as-is, or Enter search, or aBort? Here, you have many of the same options as before, but you can also enter a number to choose one of the options that beets has found. Don't worry about guessing---beets will show you the proposed changes and ask you to confirm them, just like the earlier example. As the prompt suggests, you can just hit return to select the first candidate. .. _guide-duplicates: Duplicates ---------- If beets finds an album or item in your library that seems to be the same as the one you're importing, you may see a prompt like this: :: This album is already in the library! [S]kip new, Merge all, Remove old, Keep all, Upgrade? Beets wants to keep you safe from duplicates, which can be a real pain, so you have five choices in this situation. You can skip importing the new music, choosing to keep the stuff you already have in your library; you can keep both the old and the new music; you can remove the existing music and choose the new stuff; or you can merge all the new and old tracks into a single album. If you choose that "remove" option, any duplicates will be removed from your library database---and, if the corresponding files are located inside of your beets library directory, the files themselves will be deleted as well. If you choose "merge", beets will try re-importing the existing and new tracks as one bundle together. This is particularly helpful when you have an album that's missing some tracks and then want to import the remaining songs. The importer will ask you the same questions as it would if you were importing all tracks at once. If you choose "upgrade", beets compares each new track with its existing counterpart and replaces the old track only when the new one has a higher bitrate. New tracks without an existing counterpart are still added, while the rest of the existing album remains untouched. If you choose to keep two identically-named albums, beets can avoid storing both in the same directory. See :ref:`aunique` for details. Fingerprinting -------------- You may have noticed by now that beets' autotagger works pretty well for most files, but can get confused when files don't have any metadata (or have wildly incorrect metadata). In this case, you need *acoustic fingerprinting*, a technology that identifies songs from the audio itself. With fingerprinting, beets can autotag files that have very bad or missing tags. The :doc:`"chroma" plugin `, distributed with beets, uses the Chromaprint_ open-source fingerprinting technology, but it's disabled by default. That's because it's sort of tricky to install. See the :doc:`/plugins/chroma` page for a guide to getting it set up. Before you jump into acoustic fingerprinting with both feet, though, give beets a try without it. You may be surprised at how well metadata-based matching works. .. _chromaprint: https://acoustid.org/chromaprint Album Art, Lyrics, Genres and Such ---------------------------------- Aside from the basic stuff, beets can optionally fetch more specialized metadata. As a rule, plugins are responsible for getting information that doesn't come directly from the MusicBrainz database. This includes :doc:`album cover art `, :doc:`song lyrics `, and :doc:`musical genres `. Check out the :doc:`list of plugins ` to pick and choose the data you want. Missing Albums? --------------- If you're having trouble tagging a particular album with beets, check to make sure the album is present in `the MusicBrainz database`_. You can search on their site to make sure it's cataloged there. If not, anyone can edit MusicBrainz---so consider adding the data yourself. .. _the musicbrainz database: https://musicbrainz.org/ If you receive a "No matching release found" message from the Auto-Tagger for an album you know is present in MusicBrainz, check that musicbrainz is in the plugin list. Until version v2.4.0_ the default metadata source for the Auto-Tagger, the :doc:`musicbrainz plugin `, had to be manually disabled. At present, if the plugin list is changed, musicbrainz needs to be added to the plugin list in order to continue contributing results to Auto-Tagger. If you think beets is ignoring an album that's listed in MusicBrainz, please `file a bug report`_. .. _file a bug report: https://github.com/beetbox/beets/issues .. _v2.4.0: https://github.com/beetbox/beets/releases/tag/v2.4.0 I Hope That Makes Sense ----------------------- If we haven't made the process clear, please post on `the discussion board`_ and we'll try to improve this guide. .. _the discussion board: https://github.com/beetbox/beets/discussions/ beetbox-beets-00724b7/docs/guides/main.rst0000664000175000017500000003130415253035401017742 0ustar pieterpieterGetting Started =============== Welcome to beets_! This guide will help get started with improving and organizing your music collection. .. _beets: https://beets.io/ Quick Installation ------------------ Beets is distributed via PyPI_ and can be installed by most users with a single command: .. include:: installation.rst :start-after: :end-before: .. admonition:: Need more information? Having trouble with the commands above? Looking for information how to install plugins and keep Beets updated? See the :doc:`complete installation guide ` for: - Managing plugins with uv tool - OS-specific installation notes - Package manager options .. _pypi: https://pypi.org/project/beets/ Basic Configuration ------------------- Before using beets, you'll need a configuration file. This YAML file tells beets where to store your music and how to organize it. While beets is highly configurable, you only need a few basic settings to get started. 1. **Open the config file:** .. code-block:: console beet config -e This creates the file (if needed) and opens it in your default editor. You can also find its location with ``beet config -p``. 2. **Add required settings:** In the config file, set the ``directory`` option to the path where you want beets to store your music files. Set the ``library`` option to the path where you want beets to store its database file. .. code-block:: yaml directory: ~/music library: ~/data/musiclibrary.db 3. **Choose your import style** (pick one): Beets offers flexible import strategies to match your workflow. Choose one of the following approaches and put one of the following in your config file: .. tab-set:: .. tab-item:: Copy Files (Default) This is the default configuration and assumes you want to start a new organized music folder (inside ``directory`` above). During import we will *copy* cleaned-up music into that empty folder. .. code-block:: yaml import: copy: yes # Copy files to new location .. tab-item:: Move Files Start with a new empty directory, but *move* new music in instead of copying it (saving disk space). .. code-block:: yaml import: move: yes # Move files to new location .. tab-item:: Use Existing Structure Keep your current directory structure; importing should never move or copy files but instead just correct the tags on music. Make sure to point ``directory`` at the place where your music is currently stored. .. code-block:: yaml import: copy: no # Use files in place .. tab-item:: Read-Only Mode Keep everything exactly as-is; only track metadata in database. (Corrected tags will still be stored in beets' database, and you can use them to do renaming or tag changes later.) .. code-block:: yaml import: copy: no # Use files in place write: no # Don't modify tags 4. **Add customization via plugins (optional):** Beets comes with many plugins that extend its functionality. You can enable plugins by adding a ``plugins`` section to your config file. We recommend adding at least one :ref:`Autotagger Plugin ` to help with fetching metadata during import. For getting started, :doc:`MusicBrainz ` is a good choice. .. code-block:: yaml plugins: - musicbrainz # Example plugin for fetching metadata - ... other plugins you want ... You can find a list of available plugins in the :doc:`plugins index `. .. _yaml: https://yaml.org/ To validate that you've set up your configuration and it is valid YAML, you can type ``beet version`` to see a list of enabled plugins or ``beet config`` to get a complete listing of your current configuration. .. dropdown:: Minimal configuration Here's a sample configuration file that includes the settings mentioned above: .. code-block:: yaml directory: ~/music library: ~/data/musiclibrary.db import: move: yes # Move files to new location # copy: no # Use files in place # write: no # Don't modify tags plugins: - musicbrainz # Example plugin for fetching metadata # - ... other plugins you want ... You can copy and paste this into your config file and modify it as needed. .. admonition:: Ready for more? For a complete reference of all configuration options, see the :doc:`configuration reference `. Importing Your Music -------------------- Now you're ready to import your music into beets! .. important:: Importing can modify and move your music files. **Make sure you have a recent backup** before proceeding. Choose Your Import Method ~~~~~~~~~~~~~~~~~~~~~~~~~ There are two good ways to bring your *existing* library into beets database. .. tab-set:: .. tab-item:: Autotag (Recommended) This method uses beets' autotagger to find canonical metadata for every album you import. It may take a while, especially for large libraries, and it's an interactive process. But it ensures all your songs' tags are exactly right from the get-go. .. code-block:: console beet import /a/chunk/of/my/library .. warning:: The point about speed bears repeating: using the autotagger on a large library can take a very long time, and it's an interactive process. So set aside a good chunk of time if you're going to go that route. We also recommend importing smaller batches of music at a time (e.g., a few albums) to make the process more manageable. For more on the interactive tagging process, see :doc:`tagger`. .. tab-item:: Quick Import This method quickly brings all your files with all their current metadata into beets' database without any changes. It's really fast, but it doesn't clean up or correct any tags. To use this method, run: .. code-block:: console beet import --noautotag /my/huge/mp3/library The ``--noautotag`` / ``-A`` flag skips autotagging and uses your files' current metadata. .. admonition:: More Import Options The ``beet import`` command has many options to customize its behavior. For a full list, type ``beet help import`` or see the :ref:`import command reference `. Adding More Music Later ~~~~~~~~~~~~~~~~~~~~~~~ When you acquire new music, use the same ``beet import`` command to add it to your library: .. code-block:: console beet import ~/new_totally_not_ripped_album This will apply the same autotagging process to your new additions. For alternative import behaviors, consult the options mentioned above. Seeing Your Music ----------------- Once you've imported music into beets, you'll want to explore and query your library. Beets provides several commands for searching, browsing, and getting statistics about your collection. Basic Searching ~~~~~~~~~~~~~~~ The ``beet list`` command (shortened to ``beet ls``) lets you search your music library using :doc:`query string ` similar to web searches: .. code-block:: console $ beet ls the magnetic fields The Magnetic Fields - Distortion - Three-Way The Magnetic Fields - Dist The Magnetic Fields - Distortion - Old Fools .. code-block:: console $ beet ls hissing gronlandic of Montreal - Hissing Fauna, Are You the Destroyer? - Gronlandic Edit .. code-block:: console $ beet ls bird The Knife - The Knife - Bird The Mae Shi - Terrorbird - Revelation Six By default, search terms match against :ref:`common attributes ` of songs, and multiple terms are combined with AND logic (a track must match *all* criteria). Searching Specific Fields ~~~~~~~~~~~~~~~~~~~~~~~~~ To narrow a search term to a particular metadata field, prefix the term with the field name followed by a colon. For example, ``album:bird`` searches for "bird" only in the "album" field of your songs. For more details, see :doc:`/reference/query/`. .. code-block:: console $ beet ls album:bird The Mae Shi - Terrorbird - Revelation Six This searches only the ``album`` field for the term ``bird``. Searching for Albums ~~~~~~~~~~~~~~~~~~~~ The ``beet list`` command also has an ``-a`` option, which searches for albums instead of songs: .. code-block:: console $ beet ls -a forever Bon Iver - For Emma, Forever Ago Freezepop - Freezepop Forever Custom Output Formatting ~~~~~~~~~~~~~~~~~~~~~~~~ There's also an ``-f`` option (for *format*) that lets you specify what gets displayed in the results of a search: .. code-block:: console $ beet ls -a forever -f "[$format] $album ($year) - $artist - $title" [MP3] For Emma, Forever Ago (2009) - Bon Iver - Flume [AAC] Freezepop Forever (2011) - Freezepop - Harebrained Scheme In the format string, field references like ``$format``, ``$year``, ``$album``, etc., are replaced with data from each result. .. dropdown:: Available fields for formatting To see all available fields you can use in custom formats, run: .. code-block:: console beet fields This will display a comprehensive list of metadata fields available for your music. Library Statistics ~~~~~~~~~~~~~~~~~~ Beets can also show you statistics about your music collection: .. code-block:: console $ beet stats Tracks: 13019 Total time: 4.9 weeks Total size: 71.1 GB Artists: 548 Albums: 1094 .. admonition:: Ready for more advanced queries? The ``beet list`` command has many additional options for sorting, limiting results, and more complex queries. For a complete reference, run: .. code-block:: console beet help list Or see the :ref:`list command reference `. Keep Playing ------------ Congratulations! You've now mastered the basics of beets. But this is only the beginning, beets has many more powerful features to explore. Continue Your Learning Journey ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *I was there to push people beyond what's expected of them.* .. grid:: 2 :gutter: 3 .. grid-item-card:: :octicon:`zap` Advanced Techniques :link: advanced :link-type: doc Explore sophisticated beets workflows including: - Advanced tagging strategies - Complex import scenarios - Custom metadata management - Workflow automation .. grid-item-card:: :octicon:`terminal` Command Reference :link: /reference/cli :link-type: doc Comprehensive guide to all beets commands: - Complete command syntax - All available options - Usage examples - **Important operations like deleting music** .. grid-item-card:: :octicon:`plug` Plugin Ecosystem :link: /plugins/index :link-type: doc Discover beets' true power through plugins: - Metadata fetching from multiple sources - Audio analysis and processing - Streaming service integration - Custom export formats .. grid-item-card:: :octicon:`question` Illustrated Walkthrough :link: https://beets.io/blog/walkthrough.html :link-type: url Visual, step-by-step guide covering: - Real-world import examples - Screenshots of interactive tagging - Common workflow patterns - Troubleshooting tips .. admonition:: Need Help? Remember you can always use ``beet help`` to see all available commands, or ``beet help [command]`` for detailed help on specific commands. Join the Community ~~~~~~~~~~~~~~~~~~ We'd love to hear about your experience with beets! .. grid:: 2 :gutter: 2 .. grid-item-card:: :octicon:`comment-discussion` Discussion Board :link: https://github.com/beetbox/beets/discussions :link-type: url - Ask questions - Share tips and tricks - Discuss feature ideas - Get help from other users .. grid-item-card:: :octicon:`git-pull-request` Developer Resources :link: /dev/index :link-type: doc - Contribute code - Report issues - Review pull requests - Join development discussions .. admonition:: Found a Bug? If you encounter any issues, please report them on our `GitHub Issues page `_. beetbox-beets-00724b7/docs/guides/advanced.rst0000664000175000017500000001753315253035401020573 0ustar pieterpieterAdvanced Awesomeness ==================== So you have beets up and running and you've started :doc:`importing your music `. There's a lot more that beets can do now that it has cataloged your collection. Here's a few features to get you started. Most of these tips involve :doc:`plugins ` and fiddling with beets' :doc:`configuration `. So use your favorite text editor to create a config file before you continue. Fetch album art, genres, and lyrics ----------------------------------- Beets can help you fill in more than just the basic taxonomy metadata that comes from MusicBrainz. Plugins can provide :doc:`album art `, :doc:`lyrics `, and :doc:`genres ` from databases around the Web. If you want beets to get any of this data automatically during the import process, just enable any of the three relevant plugins (see :doc:`/plugins/index`). For example, put this line in your :doc:`config file ` to enable all three: :: plugins: fetchart lyrics lastgenre Each plugin also has a command you can run to fetch data manually. For example, if you want to get lyrics for all the Beatles tracks in your collection, just type ``beet lyrics beatles`` after enabling the plugin. Read more about using each of these plugins: - :doc:`/plugins/fetchart` (and its accompanying :doc:`/plugins/embedart`) - :doc:`/plugins/lyrics` - :doc:`/plugins/lastgenre` Customize your file and folder names ------------------------------------ Beets uses an extremely flexible template system to name the folders and files that organize your music in your filesystem. Take a look at :ref:`path-format-config` for the basics: use fields like ``$year`` and ``$title`` to build up a naming scheme. But if you need more flexibility, there are two features you need to know about: - :ref:`Template functions ` are simple expressions you can use in your path formats to add logic to your names. For example, you can get an artist's first initial using ``%upper{%left{$albumartist,1}}``. - If you need more flexibility, the :doc:`/plugins/inline` lets you write snippets of Python code that generate parts of your filenames. The equivalent code for getting an artist initial with the *inline* plugin looks like ``initial: albumartist[0].upper()``. If you already have music in your library and want to update their names according to a new scheme, just run the :ref:`move-cmd` command to rename everything. Stream your music to another computer ------------------------------------- Sometimes it can be really convenient to store your music on one machine and play it on another. For example, I like to keep my music on a server at home, but play it at work (without copying my whole library locally). The :doc:`/plugins/web` makes streaming your music easy---it's sort of like having your own personal Spotify. First, enable the ``web`` plugin (see :doc:`/plugins/index`). Run the server by typing ``beet web`` and head to http://localhost:8337 in a browser. You can browse your collection with queries and, if your browser supports it, play music using HTML5 audio. Transcode music files for media players --------------------------------------- Do you ever find yourself transcoding high-quality rips to a lower-bitrate, lossy format for your phone or music player? Beets can help with that. You'll first need to install ffmpeg_. Then, enable beets' :doc:`/plugins/convert`. Set a destination directory in your :doc:`config file ` like so: :: convert: dest: ~/converted_music Then, use the command ``beet convert QUERY`` to transcode everything matching the query and drop the resulting files in that directory, named according to your path formats. For example, ``beet convert long winters`` will move over everything by the Long Winters for listening on the go. The plugin has many more dials you can fiddle with to get your conversions how you like them. Check out :doc:`its documentation `. .. _ffmpeg: https://www.ffmpeg.org Store any data you like ----------------------- The beets database keeps track of a long list of :ref:`built-in fields `, but you're not limited to just that list. Say, for example, that you like to categorize your music by the setting where it should be played. You can invent a new ``context`` attribute to store this. Set the field using the :ref:`modify-cmd` command: :: beet modify context=party artist:'beastie boys' By default, beets will show you the changes that are about to be applied and ask if you really want to apply them to all, some or none of the items or albums. You can type y for "yes", n for "no", or s for "select". If you choose the latter, the command will prompt you for each individual matching item or album. Then :doc:`query ` your music just as you would with any other field: :: beet ls context:mope You can even use these fields in your filenames (see :ref:`path-format-config`). And, unlike :ref:`built-in fields `, such fields can be removed: :: beet modify context! artist:'beastie boys' Read more than you ever wanted to know about the *flexible attributes* feature `on the beets blog`_. .. _on the beets blog: https://beets.io/blog/flexattr.html Choose a path style manually for some music ------------------------------------------- Sometimes, you need to categorize some songs differently in your file system. For example, you might want to group together all the music you don't really like, but keep around to play for friends and family. This is, of course, impossible to determine automatically using metadata from MusicBrainz. Instead, use a flexible attribute (see above) to store a flag on the music you want to categorize, like so: :: beet modify bad=1 christmas Then, you can query on this field in your path formats to sort this music differently. Put something like this in your configuration file: :: paths: bad:1: Bad/$artist/$title Used together, flexible attributes and path format conditions let you sort your music by any criteria you can imagine. Automatically add new music to your library ------------------------------------------- As a command-line tool, beets is perfect for automated operation via a cron job or the like. To use it this way, you might want to use these options in your :doc:`config file `: .. code-block:: yaml import: incremental: yes quiet: yes log: /path/to/log.txt The :ref:`incremental` option will skip importing any directories that have been imported in the past. :ref:`quiet` avoids asking you any questions (since this will be run automatically, no input is possible). You might also want to use the :ref:`quiet_fallback` options to configure what should happen when no near-perfect match is found -- this option depends on your level of paranoia. Finally, :ref:`import_log` will make beets record its decisions so you can come back later and see what you need to handle manually. The last step is to set up cron or some other automation system to run ``beet import /path/to/incoming/music``. Useful reports -------------- Since beets has a quite powerful query tool, this list contains some useful and powerful queries to run on your library. - See a list of all albums which have files which are 128 bit rate: :: beet list bitrate:128000 - See a list of all albums with the tracks listed in order of bit rate: :: beet ls -f '$bitrate $artist - $title' bitrate+ - See a list of albums and their formats: :: beet ls -f '$albumartist $album $format' | sort | uniq Note that ``beet ls --album -f '... $format'`` doesn't do what you want, because ``format`` is an item-level field, not an album-level one. If an album's tracks exist in multiple formats, the album will appear in the list once for each format. beetbox-beets-00724b7/docs/changelog.rst0000664000175000017500000123072415253035401017475 0ustar pieterpieterChangelog ========= Changelog goes here! Please add your entry to the bottom of one of the lists below! .. Uncomment the relevant section when you add the first entry Unreleased ---------- .. New features ~~~~~~~~~~~~ .. Bug fixes ~~~~~~~~~ .. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ .. Other changes ~~~~~~~~~~~~~ 2.14.1 (September 17, 2026) --------------------------- .. New features ~~~~~~~~~~~~ Bug fixes ~~~~~~~~~ - :doc:`plugins/lyrics`: Support 3-decimal millisecond timestamps (e.g. ``[mm:ss.xxx]``) in LRC parsing, fixing an issue where synced lyrics with millisecond precision were erroneously rejected and fell back to plain lyrics. :bug:`7001` - Skip archive importer tests (``TestImport7z`` and ``TestImportRar``) when their optional dependencies (``py7zr`` or ``rarfile`` / ``unrar``) are not available. :bug:`7002` - :doc:`plugins/discogs`: Read the release month and day from the API's ``released`` field instead of only the year. Fix Discogs match overwriting month and day tags on import. - Empty leading path-format fields (e.g. from missing metadata) combined with a custom ``replace`` configuration no longer produce an absolute destination path that escapes the library or :doc:`plugins/convert` destination directory; leading path separators are now stripped from the rendered path. :bug:`4889` - Add a configurable ``tempfile_prefix`` for temporary files created during cross-filesystem moves, avoiding hidden-file behavior on Windows and Samba shares caused by a hard-coded leading dot ('.'). :bug:`7033` - :ref:`import-cmd` Fix interactive importer ignoring candidates from manual search (``e``) and manual ID (``i``) entry. :bug:`7000` .. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ Other changes ~~~~~~~~~~~~~ - :doc:`plugins/duplicates`: Improve the documentation of the ``checksum`` option: explain how the external command is run, remove the broken ``md5sum {file}`` example and show how to use such commands through a wrapper script. :bug:`3979` - Use ``bytes`` instead of ``memoryview`` for SQLite path storage and query parameters. 2.14.0 (September 07, 2026) --------------------------- New features ~~~~~~~~~~~~ - :doc:`plugins/plexupdate`: Add ``beet plexupdate --auth``, an interactive plex.tv login following Plex' traditional PIN authentication flow: the access token for the local server is stored in a token file. The manual ``token`` configuration option is now deprecated. - :ref:`duplicate_action`: Add an ``upgrade`` option that replaces individual duplicate tracks only if the new copy has a higher bitrate, adds any genuinely new tracks, and keeps the album together rather than splitting it. The option is available both through configuration and from the interactive duplicate prompt. :bug:`4471` - The interactive import prompt now offers a "Rescan directory" choice for album tasks. It re-reads the album's directory from disk and re-runs the match, so files can be cleaned up (duplicates, junk) while the import is paused at the prompt, without restarting the whole ``beet import`` run. - :ref:`list-cmd` Add ``-l / --limit LIMIT`` flag to the ``list`` command to limit query results. :bug:`5076` Bug fixes ~~~~~~~~~ - Add ``editor`` config option to allow users to permanently set their preferred editor, overriding ``$VISUAL`` and ``$EDITOR`` environment variables. :bug:`6641` - ``beet update`` no longer crashes when a plugin-added media field is stored as a flexible attribute. :bug:`5580` - A date range query written back to front (for example ``added:2024..2020``) no longer crashes with an uncaught ``ValueError``. The endpoints are now swapped, so such a range means the same as ``added:2020..2024``. - Deduplicating a file whose name already ends in a counter of two or more digits no longer restarts the numbering: ``track.10.mp3`` now yields ``track.11.mp3`` instead of ``track.1.mp3``. The counter was matched with ``\.(\d)+$``, which captures only the final digit. - Autotagging distance calculations no longer treat ordinary words containing "ft" (such as "draft", "left", "gift", "craft") as a "featuring artist" suffix, which was silently making genuinely different titles/artists score as near-identical matches. - :doc:`plugins/lyrics`: ``beet lyrics`` no longer crashes with an ``AttributeError`` on tracks that have no stored lyrics when ``force`` is enabled; a missing lyrics body is now treated as empty text. :bug:`6860` - :doc:`plugins/deezer`: Detect compilations that Deezer credits to a single "main" artist instead of "Various Artists", so they are tagged as such rather than getting every track artist in the album artist field. :bug:`4057` - Flexible attributes whose names contain uppercase characters (for example ``beet import --set Tag_With_Uppercase=true``) can now be found by queries. Field names are lowercased when a query is parsed, so such attributes could never be matched; flexible attribute lookups now fall back to a case-insensitive key match. :bug:`4565` - :doc:`plugins/deezer`: Singleton searches now use plain free text rather than `` artist:"<artist>"``. Deezer discards unquoted free text as soon as a query contains any ``field:"value"`` filter, so the old query was evaluated as ``artist:"<artist>"`` alone -- every track by the artist, in Deezer's own relevance order and truncated to ``search_limit``. For artists with more releases than that window, the track being imported was never among the candidates offered. - :doc:`plugins/tidal`: The ``label`` field no longer stores Tidal's raw copyright/rights-statement text verbatim. It's now normalized to a concise label name, stripping copyright markers, years, and corporate, licensing, and territorial boilerplate. Affects both album and track metadata. :bug:`6796` - :doc:`plugins/deezer`: Track conversion no longer assumes the API sends both ``contributors`` and ``artist``. The fallback to ``artist`` was evaluated even when ``contributors`` was present, so a track payload without ``artist`` raised ``KeyError``. Albums were already guarded; this fixes the remaining call site. :bug:`4339` - :doc:`plugins/discogs`: Retry a search once when Discogs returns an invalid JSON response instead of immediately discarding all Discogs candidates. - Plugins built on ``SearchApiMetadataSourcePlugin`` (:doc:`plugins/musicbrainz`, :doc:`plugins/spotify`, :doc:`plugins/deezer` and :doc:`plugins/discogs`) no longer send a search request when both the query text and the filters are empty. :bug:`6862` - :doc:`plugins/ipfs`: Fix ``beet ipfs --play`` option to invoke the Play plugin through its command interface. - :doc:`plugins/lyrics`: LRCLib entries that carry no lyrics text at all, with both ``plainLyrics`` and ``syncedLyrics`` null while ``instrumental`` is ``False``, are no longer considered matches. Previously such an entry was accepted and its null text propagated, raising ``AttributeError: 'NoneType' object has no attribute 'splitlines'``. During an import this aborted the whole run rather than a single track. A null ``plainLyrics`` now also falls back to the synced lyrics instead of discarding them. - :ref:`modify-cmd`: Fix applying changes when choosing objects in interactive select mode. :bug:`4880` - :ref:`move-cmd`: Fix moving albums in interactive select/timid mode. :bug:`2802` - :doc:`plugins/bpd`: Fix ``search`` command when ``any`` field is used. - :doc:`plugins/aura`: Prevent multi-valued field filters from crashing with an ``sqlite3.InterfaceError``. - :doc:`plugins/aura`: When sorting by ``field``, do not exclude resources that have no value for ``field``. - :doc:`plugins/scrub`: The scrub plugin now respects the ``--nowrite`` (``-W``) flag during import. Previously, ``beet import -W`` with the scrub plugin enabled would still remove tags from imported files; the plugin now skips scrubbing when ``should_write()`` returns ``False``. :bug:`6958` - :doc:`plugins/convert`: Fixed convert plugin not taking into account the new format when determining the target path. :bug:`1360` - :doc:`plugins/edit`: Item-only fields rejected from the album header remain available in per-track documents during interactive import when they are also configured in ``itemfields``. :bug:`6953` - :doc:`plugins/tidal`: Pass the converted track duration as ``length`` so it contributes to the autotagging track-length distance instead of being silently stored as a ``duration`` flexible attribute. - :doc:`plugins/tidal`: Restore catalog searches after TIDAL moved search queries from the request path to the required ``filter[query]`` parameter. :bug:`6989` - :ref:`import-cmd`: Restore the ability to import from tar and 7z archives. Both failed with an ``'... object has no attribute 'infolist'`` error because ``tarfile.TarFile`` lost its ``ZipFileCompat`` interface in Python 3 and ``py7zr.SevenZipFile`` exposes ``list()`` rather than ``infolist()``. :bug:`5664` - :doc:`plugins/listenbrainz` and :doc:`plugins/lastimport`: Play counts are now matched more accurately. An exact MusicBrainz recording ID match is preferred when one exists, and titles are matched exactly (confirmed by the artist or album) before falling back to the previous substring-based matching. Previously all queries were combined, so a listen for "Song" also updated "Song (inst.)" or any other item whose title only contained the listened title. - :doc:`plugins/limit` Deprecate the ``limit`` plugin in favor of the new ``-l`` / ``--limit`` flag for the :ref:`list-cmd` command. .. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ Other changes ~~~~~~~~~~~~~ - :doc:`plugins/bpd`: Replace the bundled Bluelet scheduler with Python's standard ``asyncio`` event loop. - Docs: fix broken link to ``test/dbcore/test_query.py`` in ``CONTRIBUTING.rst``; add crawler-blocking and unreachable sites to ``linkcheck_ignore`` in ``docs/conf.py``. 2.13.1 (July 29, 2026) ---------------------- Bug fixes ~~~~~~~~~ - Fixed source distributions not including the bundled man pages. :bug:`6882` 2.13.0 (July 27, 2026) ---------------------- New features ~~~~~~~~~~~~ - :doc:`plugins/spotify`: Recognize native Spotify URIs (e.g. ``spotify:album:<id>`` and ``spotify:track:<id>``) when extracting release/track IDs, in addition to full ``open.spotify.com`` URLs and bare IDs - :doc:`/plugins/convert`: Add new configuration option ``convert.refresh`` and command-line option ``--refresh``, allowing to force ``convert`` operation when original file is newer than existing converted file. - :doc:`plugins/lyrics`: Added a ``rest_directory`` configuration option for specifying a reStructuredText output directory, semantically equivalent to ``-r, --write-rest``. :bug:`2806` - A database backup is now automatically created before running schema migrations. Control with the ``create_backup_before_migrations`` option (default: yes). - :doc:`plugins/tidal`: Add cover art support. Album metadata now includes ``cover_art_url`` from Tidal's ``coverArt`` relationship, which the :doc:`plugins/fetchart` plugin can retrieve. - :ref:`modify-cmd`: Support ``+=`` and ``-=`` operators to add or remove individual values from multi-valued fields without replacing the whole field. :bug:`6587` - :doc:`plugins/edit`: The interactive import editor now shows album-level fields (as configured by ``albumfields``) as a YAML header section when editing an album import. Fields that appear in both ``itemfields`` and ``albumfields`` are shown only in the header, not per-track. - :doc:`plugins/ftintitle`: Apply featured-artist rewriting to fetched metadata before commands such as :doc:`plugins/mbsync` use it. :bug:`1153` - :doc:`plugins/fetchart`: Add ``fetch_for_asis`` setting that enables fetching album art from online sources even when imported files are not modified by the auto-tagger. Default is ``no`` which means ``fetchart`` looks for art only in the local filesystem when the user (or ``quiet_fallback``) chooses ``asis``. - :doc:`plugins/lyrics`: Added a ``--no-keep-synced`` command option to override ``keep_synced: yes`` for a single manual lyrics fetch. - :doc:`plugins/lastgenre`: Add support for normalizing genre spellings and naming variants with a new configuration option ``aliases``. The feature is enabled by default and ships with a built-in list of regex patterns. These patterns can be replaced via the user's configuration. The default whitelist and genre tree were audited against the top 1,000 Last.fm tags: canonical names are now consistent across both files, long-standing mismatches between them have been resolved, and entries align with the built-in alias patterns. :bug:`6466` - :doc:`plugins/lyrics`: Add ``lrcmux`` backend, which aggregates lyrics from various other sources. - :doc:`plugins/replaygain`: Add a ``metaflac`` backend that computes ReplayGain for FLAC files using the ``metaflac`` command-line tool. :bug:`1203` Bug fixes ~~~~~~~~~ - :doc:`plugins/edit`: Preserve missing album art paths when editing album metadata, instead of turning ``artpath: null`` into a path ending in ``None``. :bug:`2438` - :doc:`plugins/subsonicupdate`: Log a clearer error when the Subsonic server returns a non-JSON response. :bug:`5635` - :doc:`plugins/missing`: Honor the ``-f``/``--format`` option (and the ``format_album`` configuration) when listing missing albums in album mode. :bug:`3804` - :doc:`plugins/importfeeds`: ``beet import`` no longer aborts the whole run when a symlink cannot be created (e.g. on Windows or a read-only directory); the failure is logged and the import continues. :bug:`840` - Album ``store`` no longer copies ``artpath`` onto its items as an absolute path, which broke relative-path portability. A database migration removes any such stale ``artpath`` attributes left on items by earlier versions. :bug:`6756` - :doc:`plugins/convert`: ``convert -a`` with ``copy_album_art`` enabled no longer crashes when the stored album art path points to a missing file (for example a multi-disc album whose cover lives in the album root rather than a per-disc directory); the missing art is skipped instead. :bug:`4692` - :doc:`plugins/tidal`: Normalize Tidal album types to lowercase. - :doc:`plugins/lyrics`: Leave lyrics empty when a source reports an instrumental track, and store that state in ``lyrics_instrumental`` flexible attribute. Existing ``[Instrumental]`` lyrics are migrated automatically. :bug:`6719` - Sorting by a nullable field (for example a flexible attribute with a declared type whose null value is ``None``) that is present on only some items no longer crashes with a ``TypeError``. Missing values are now grouped together, ordered before present ones when sorting ascending and after them when descending. :bug:`3461` - :doc:`plugins/smartplaylist`: ``splupdate`` no longer crashes with ``TypeError: unhashable type: 'list'`` when a playlist configuration includes a ``playlist:`` query. :bug:`5354` - A date query containing a stray ``|`` (for example ``added:2000|2001``, as might be typed by a user expecting ``|`` to mean "or") now raises a clean "a valid date/time string" error instead of crashing with an uncaught ``KeyError``. A ``|`` was being accepted as a relative-date unit due to a regular expression character-class typo. .. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ Other changes ~~~~~~~~~~~~~ - :doc:`/guides/installation` Add Homebrew to the list of supported package managers in the installation guide. - :doc:`/guides/installation`: Note that Windows users should run beets in a terminal emulator (such as Windows Terminal or cmder) for output to display correctly. :bug:`2848` - :doc:`contributing`: The project now uses ``uv`` for packaging, virtual environment, and dependency management, replacing ``poetry``. The build backend has changed from ``poetry-core`` to ``hatchling``. Please see updates in :ref:`development-tools` and :ref:`getting-the-source` for more information. :bug:`5783` - :doc:`guides/installation`: Switch isolated tool installation guidance and GitHub workflow setup to ``uv tool`` commands. - :doc:`plugins/lastgenre`: Add a new "Choosing the Right Tool" documentation section to guide users in picking the right approach across genre fetching, filtering, and normalization. - :doc:`plugins/spotify`: Retry on ``503 Service Unavailable`` responses from the Spotify API instead of immediately aborting, matching the existing ``429`` rate-limit retry behavior. 2.12.0 (June 22, 2026) ---------------------- New features ~~~~~~~~~~~~ - :doc:`plugins/convert`: The ``--force`` and ``--keep-new`` CLI flags are now also available as config options via ``force`` and ``keep_new``. - :ref:`import-cmd`: The ``--nomove`` / ``-M`` CLI flag can now be used to override the ``move: yes`` config option during import. - :doc:`plugins/lyrics`: Write synced (LRC) lyrics to the ``SYLT`` (synchronized lyrics) ID3 frame and plain text to ``USLT`` for ID3-tagged files, instead of storing raw LRC timestamps in ``USLT``. Players that only support ``USLT`` continue to see readable plain lyrics. :bug:`6541` - :doc:`plugins/listenbrainz`: Add support for importing ListenBrainz listening history from an export file. Use the ``-f`` / ``--export-file`` flag to specify the path to the ListenBrainz export file. - :doc:`plugins/musicbrainz`: Introduce :conf:`plugins.musicbrainz:aliases_as_credits` to make aliases-as-artist-credit optional. - :doc:`plugins/badfiles`: Added settings for auto error and warning actions. - :doc:`plugins/tidal`: New flexible attributes are now populated during imports, including ``tidal_track_id``, ``tidal_album_id``, ``tidal_artist_id``, ``tidal_track_popularity``, ``tidal_album_popularity``, and ``tidal_updated``. Added a new ``beet tidalsync`` command to refresh popularity data for imported items by default, or albums with ``--album``, with ``--force`` to re-fetch and ``--write`` to update file tags. **Migration**: Existing Tidal imports can copy the previously stored IDs into the new flexible attributes with ``beet modify``: run ``beet modify data_source:tidal tidal_album_id='$mb_albumid' -a`` for albums and ``beet modify data_source:tidal tidal_track_id='$mb_trackid'`` for items. Bug fixes ~~~~~~~~~ - :doc:`plugins/lyrics`: Add rate limiting and exponential backoff to HTTP requests to prevent ``429 Too Many Requests`` errors from lyrics sources during bulk imports. :bug:`6728` - :doc:`plugins/replace`: Fix ``TypeError`` when invoking the ``replace`` command. :bug:`6260` - :doc:`plugins/mpdstats`: Fix crashes and invalid configuration when passing ``--host``, ``--port``, or ``--password`` on the command line. :bug:`5404` - :ref:`import-cmd`: Fix duplicate album merge during import when running in threaded mode. The merge action no longer creates a duplicate folder or reports ``could not get filesize`` errors. :bug:`6601` - :doc:`plugins/mbpseudo`: Fix crashes when applying a pseudo-release. One in ``PseudoAlbumInfo.raw_data`` and a ``sqlite3.ProgrammingError``. - :doc:`plugins/duplicates`: Fix plugin output: information about duplicate items was not displayed by default. --count option was ignored :bug:`6476` - :doc:`plugins/mbsync` / :doc:`plugins/bpsync`: Do not clear items metadata when ``import.from_scratch`` is enabled. :bug:`6613` - :doc:`plugins/tidal`: add ``tidal`` dependency extra to make sure ``requests-oauthlib`` is installed. :bug:`6633` - Path format queries now correctly match multi-value fields such as ``genres`` when using exact string matches like ``genres:=Classical`` or ``genres:=~Classical``. :bug:`6598` - Fix a CLI help formatting regression that moved command descriptions to separate lines; descriptions are inline again, with regression test coverage. - :ref:`modify-cmd`: Fix ``beet modify -a`` splitting multi-value field strings (like ``artists``, ``genres``) into individual characters when modifying albums. Album field types now fall back to the corresponding item field type definitions. :bug:`5690` - ``AttrDict.__getattribute__`` now unmasks ``AttributeError`` raised inside a ``cached_property`` body. Previously such errors were swallowed by the ``__getattr__`` fallback, producing a misleading message about the property name itself. The wrapped ``RuntimeError`` keeps the original traceback so it still points at the real failing line. :bug:`6558` - ``ReadError`` and ``WriteError`` now include the file path and the underlying reason in their message instead of a ``<super: ...>`` object representation. :bug:`6560` - :doc:`plugins/mbcollection`: Handle MusicBrainz ``401 Unauthorized`` errors during ``mbupdate`` without crashing, and log a clearer message that points users to ``musicbrainz.user`` and ``musicbrainz.pass`` configuration. :bug:`6651` - :doc:`plugins/musicbrainz`: Fix ``KeyError: 'aliases'`` crash when looking up releases with more than 500 tracks. - :doc:`plugins/fetchart`: Catch ``OSError`` in ``_set_art`` so that permission errors (e.g. a file locked by another process) are logged as warnings instead of crashing beets. :bug:`6193` - :doc:`plugins/lyrics`: Improve Musica.com lyric scraping so fetched lyrics no longer omit the opening verse or include non-lyric page content. - :doc:`plugins/convert`: Tidy the ``--playlist`` help text so it no longer has awkward indentation in CLI output. - :doc:`plugins/spotify`: Improved Spotify API parsing to handle missing label data :bug:`6679` - :ref:`move-cmd`: ``beet move`` no longer crashes when an item referenced in the database has been deleted from disk. Missing items are now skipped with a warning and the command continues. :bug:`6720` - :doc:`plugins/fish`: Fix error on plugin initialization. - :doc:`plugins/spotify`: Use single instead of double quotes in spotify queries. - :doc:`plugins/tidal`: Fix auth URL not printed in environments without a configured browser :bug:`6710` For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - Plugin authors can import all autotagger helpers directly from ``beets.autotag``, including match classes, distance helpers, and ``assign_items``, without relying on lower-level autotag modules. - Introduced ``beets.importer.DuplicateAction`` to simplify handling of duplicates. Other changes ~~~~~~~~~~~~~ - :doc:`plugins/lyrics`: Fold rate limiting and 429 retry from the lyrics-specific ``LyricsSession`` into the shared :class:`~beetsplug._utils.requests.TimeoutAndRetrySession` so all plugins benefit. The standalone ``LyricsSession`` class has been removed. - :doc:`plugins/spotify`: ``spotifysync`` now batches its SQLite commit for a sync run, follows the standard beets write-before-store pattern, and logs audio-features API unavailability only once per run. - :doc:`plugins/titlecase`: Correct the path format example and document the ``%titlecase{text}`` template function. :bug:`6697` - Log message prefix formatting (``musicbrainz: msg``) moved from a filter to ``LegacyFormatter``, making future customization easier. 2.11.0 (May 06, 2026) --------------------- New features ~~~~~~~~~~~~ - :doc:`plugins/smartplaylist`: The ``splupdate`` command output is restructured. The per-playlist summary now includes a track count. Per-track details are shown only when ``-v`` flag is provided (``beet -v splupdate``). The ``--pretend`` flag produces the same output but reports *"N playlists would be updated"* instead of *"N playlists updated"*. The ``--format`` option allows customizing the track line format. The ``--pretend-paths`` option was removed (use ``--format='$path'`` instead). :bug:`6183` - :ref:`import-cmd`: When importing an archive (zip, tar, rar, or 7z) with ``move: yes``, the source archive is now removed after a successful import. Archives are preserved if any file in the archive was not imported (e.g. skipped as a duplicate, or the import was aborted), and in non-move import modes. - :doc:`plugins/fromfilename`: Support ``track`` prefix when parsing the track number from the filename (e.g., ``track01.m4a``). - **Tidal plugin**: Introduces a new plugin for fetching metadata from Tidal. It supports album and track lookups by ID, including batch operations via ``albums_for_ids`` and ``tracks_for_ids``. It also enables search by query as well as identifier-based retrieval, with support for ISRC codes (tracks) and barcode/EANs (albums). This is an initial, relatively minimal implementation, but already fully usable for common metadata workflows. We welcome feedback, improvement ideas, and community contributions to further extend its capabilities. See :doc:`plugins/tidal` for more information. - Add support for adding or modifying a subtitle (ID3 tag ``TIT3``) field Bug fixes ~~~~~~~~~ - :ref:`import-cmd`: Multi-disc album detection now recognizes ``cassette``, ``digital media``, and ``vinyl`` as disc markers (e.g. ``vinyl 1``, ``12 vinyl 2``), in addition to the existing ``disc``, ``disk``, and ``cd`` markers. - :ref:`import-cmd`: Tags with a zero distance penalty are no longer shown as differences in the match display. Previously, custom ``distance_weights`` could cause fields with no actual mismatch to appear in the ``≠`` line. - Library path migration now also handles manually edited database rows where item or album-art paths were stored as SQLite ``TEXT`` values instead of bytes, so upgrading to the portable-path storage format no longer fails for those libraries. :bug:`6561` - :ref:`import-cmd`: Fix duplicate album art files (e.g. ``cover.2.jpg``) being created when re-importing albums with the :doc:`plugins/fetchart` plugin enabled. Old album art is now properly removed when replacing duplicate albums during import. :bug:`1264` :bug:`6205` - :doc:`plugins/discogs`: Prevent duplicate featured artists in track artist fields when the same artist is credited both in ``artists`` (for example with ``Feat.`` join text) and ``extraartists`` as ``Featuring``. :bug:`6166` - :ref:`import-cmd`: Metadata source plugin ID lookups now correctly call each plugin's own lookup method when running in parallel. :bug:`6583` - Improve ``DBAccessError`` messages to help users diagnose database permission issues more easily. The error message now mentions directory missing and file permissions as potential causes. :bug:`1676` - :doc:`plugins/lyrics`: Fix apostrophe handling in the ``musixmatch`` backend slug. :bug:`4759` - :ref:`import-cmd`: With ``original_date: yes``, album-level ``year``, ``month``, and ``day`` now use the original release date. :bug:`6577` - :doc:`plugins/musicbrainz`: Correctly handle release dates where leading or intermediate components are missing, e.g. 2008-??-02 - :doc:`plugins/badfiles`: Respect quiet mode (the ``--quiet`` flag or ``import.quiet: yes`` config) during import so the corrupt-file prompt is suppressed in non-interactive imports. :bug:`4736` Other changes ~~~~~~~~~~~~~ - :doc:`plugins/spotify`: Batch ``spotifysync`` track and audio-features API requests and deduplicate repeated Spotify track IDs within a run. 2.10.0 (April 19, 2026) ----------------------- New features ~~~~~~~~~~~~ - **Beets library is now made portable**: item and album-art paths are now stored relative to the library root in the database while remaining absolute in the rest of beets. Path queries continue matching both library-relative paths and absolute paths under the currently configured music directory under the new storage model. The existing paths in the database are migrated automatically the first time you run any ``beet`` command after the update. :bug:`133` .. warning:: make sure you run ``beet version`` (or any other command) at least once after upgrading to trigger the migration. Only then you can safely move the library to a new location. - :doc:`plugins/inline`: Add access to the ``album`` or ``item`` object as ``db_obj`` in inline fields. - :doc:`plugins/discogs`: Import Discogs remixer, lyricist, composer, and arranger credits into the multi-value ``remixers``, ``lyricists``, ``composers``, and ``arrangers`` fields. :bug:`6380` - :doc:`plugins/lyrics`: Add ``keep_synced`` config option and ``--keep-synced`` CLI flag to skip re-fetching lyrics for tracks that already have synced lyrics, even when ``force`` is enabled. :bug:`5249` - :doc:`plugins/musicbrainz`: Use aliases for artist credit. - Metadata source plugin searches and lookups are now executed concurrently, speeding up lookups when multiple plugins (e.g. MusicBrainz and Spotify) are enabled. Bug fixes ~~~~~~~~~ - :ref:`import-cmd` Automatically remux WAV files containing MP3 streams (``WAVE_FORMAT_MPEGLAYER3``) to proper MP3 files during import, instead of silently importing them with incorrect metadata. :bug:`6455` - :doc:`plugins/listenbrainz`: Retry listenbrainz requests for temporary failures. - :doc:`plugins/chroma`: Do not produce MusicBrainz-sourced autotagger candidates when the :doc:`plugins/musicbrainz` plugin is not enabled. The chroma plugin now looks up the musicbrainz plugin through the metadata-source registry instead of unconditionally instantiating its own private instance, which also restores compatibility with :doc:`plugins/mbpseudo` for chroma-triggered lookups. :bug:`6212` :bug:`6441` - :ref:`import-cmd` Remove clutter from imported album folders. :bug:`5016` - :doc:`plugins/web`: Fix a stored XSS vulnerability where unescaped metadata fields (artist, album, title, comments, lyrics) could execute arbitrary JavaScript in the browser. Template tags now use ``<%-`` (escaped interpolation) instead of ``<%=`` (raw interpolation). For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - Consumers of :py:class:`beetsplug._utils.musicbrainz.MusicBrainzAPI` now receive normalized MusicBrainz payloads with underscore-separated field names (for example ``artist_credit`` and ``release_group``) and grouped relation lists such as ``work_relations``, ``release_relations``, and ``url_relations``. The API responses are also now fully typed with concrete ``TypedDict`` models for releases, recordings, works, and relations. Update direct access to raw MusicBrainz response keys if needed. 2.9.0 (April 11, 2026) ---------------------- Beets now officially supports Python 3.14. New features ~~~~~~~~~~~~ - :ref:`import-cmd` Use ffprobe to recognize format of any import music file that has no extension. If the file cannot be recognized as a music file, leave it alone. :bug:`4881` - Query: Add ``has_cover_art`` computed field to query items by embedded cover art presence. Users can now search for tracks with or without embedded artwork using ``beet list has_cover_art:true`` or ``beet list has_cover_art:false``. - :doc:`plugins/autobpm`: Add ``force`` configuration and CLI option and deprecate ``overwrite``. - :doc:`plugins/autobpm`: The "BPM already exists for item" log message can now be hidden with the ``--quiet`` flag. - :doc:`plugins/smartplaylist`: The list of available playlists shown when an unknown playlist name is passed as an argument is now sorted alphabetically and printed space-delimited and POSIX shell-quoted when required. This makes it easier to copy and paste multiple playlists for further use in the shell. - :doc:`plugins/chroma`: Add new command ``chromasearch`` to search the local library by chromaprint fingerprint. - Store track remixers, lyricists, composers, and arrangers in the multi-valued ``remixers``, ``lyricists``, ``composers``, and ``arrangers`` fields instead of the legacy single-value ``remixer``, ``lyricist``, ``composer``, and ``arranger`` fields. Existing libraries are migrated automatically, and :doc:`plugins/musicbrainz` now preserves each MusicBrainz ``remixer``, ``lyricist``, ``composer``, and ``arranger`` relation as a separate value. - :doc:`plugins/musicbrainz`: Store MBIDs for remixers, lyricists, composers, and arrangers in the new multi-valued fields ``remixers_mbid``, ``lyricists_mbid``, ``composers_mbid``, and ``arrangers_mbid``. :bug:`5698` - :doc:`plugins/replaygain`: Conflicting replay gain tags are now removed on write. RG_* tags are removed when setting R128_* and vice versa. - :doc:`plugins/fetchart`: Add support for WebP images. - :doc:`plugins/lastgenre`: Add support for a user-configurable ignorelist to exclude unwanted or incorrect Last.fm (or existing) genres, either per artist or globally :bug:`6449` Bug fixes ~~~~~~~~~ - :doc:`plugins/deezer`: Fix Various Artists albums being tagged with a localized string instead of the configured ``va_name``. Detection now uses Deezer's artist ID rather than the artist name string. :bug:`4956` - :doc:`plugins/listenbrainz`: Paginate through all ListenBrainz listens instead of fetching only 25, aggregate individual listen events into correct play counts, use ``recording_mbid`` from the ListenBrainz mapping when available, and avoid per-listen MusicBrainz API lookups that caused imports to hang on large listen histories. :bug:`6469` - Correctly handle semicolon-delimited genre values from externally-tagged files. :bug:`6450` - :doc:`plugins/listenbrainz`: Fix ``lbimport`` crashing when ListenBrainz tracks are processed through Last.fm-specific play-count import logic. Play-count imports now use source-specific fields so :doc:`plugins/listenbrainz`, :doc:`plugins/lastimport`, and :doc:`plugins/mpdstats` do not clash. :bug:`6469` - :ref:`import-cmd` Fix ``albumartists_sort`` (and related fields) incorrectly prepending the full combined artist credit as the first element for multi-artist releases. :bug:`6470` - :doc:`plugins/discogs`: Store specific Discogs styles in beets ``genres`` and broader Discogs genres in the ``style`` field. When :conf:`plugins.discogs:append_style_genre` is enabled, the broader Discogs genres are also appended to the ``genres`` list. :bug:`6390` - :doc:`plugins/deezer`: Fix a regression in 2.8.0 where selecting a Deezer match during import could crash with ``AttributeError: 'AlbumInfo' object has no attribute 'raw_data'`` when Deezer returned numeric artist IDs. :bug:`6503` - :ref:`modify-cmd` accepts legacy singular field names such as ``genre``, ``composer``, ``lyricist``, ``remixer``, and ``arranger`` in assignments, rewrites them to the corresponding multi-valued fields, and warns users to switch to the plural field names. :ref:`list-cmd`, and query expressions, accept the same legacy singular field names and warn users to switch to the plural field names. :bug:`6483` - :doc:`plugins/fetchart`: Error when a configured source does not exist or sources configuration is empty. :bug:`6336` - :doc:`plugins/rewrite` :doc:`plugins/advancedrewrite`: Fix rewriting multi-valued fields such as ``genres`` by applying rules to each matching list entry. Additionally, apply rewrite rules in config order, so that multiple rules can be applied to the same field. :bug:`6515` For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - If you maintain a metadata source plugin that populates any of ``arranger``, ``composer``, ``lyricist``, ``remixer`` fields, update it to populate the respective multi-valued fields instead (``arrangers``, ``composers``, ``lyricists``, ``remixers``). 2.8.0 (March 28, 2026) ---------------------- New features ~~~~~~~~~~~~ - :doc:`plugins/discogs`: Add :conf:`plugins.discogs:extra_tags` option to use additional tags (such as ``barcode``, ``catalognum``, ``country``, ``label``, ``media``, and ``year``) in Discogs search queries. - :doc:`plugins/smartplaylist`: Add new configuration option ``dest_regen`` to regenerate items' path in the generated playlist instead of using those in the library. This is useful when items have been imported in don't copy-move (``-C -M``) mode in the library but are later passed through the ``convert`` plugin which will regenerate new paths according to the Beets path format. - :doc:`plugins/missing`: When running in missing album mode, allows users to specify MusicBrainz release types to show using the ``--release-type`` flag. The default behavior is also changed to just show releases of type ``album``. :bug:`2661` - :doc:`plugins/play`: Added ``-R``/``--randomize`` flag to shuffle the playlist order before passing it to the player. - :doc:`plugins/lyrics`: Add ``auto_ignore`` configuration option to skip fetching lyrics for items matching a beets query during auto import. - :doc:`plugins/musicbrainz`: Use title aliases for releases, release groups, and recordings. Bug fixes ~~~~~~~~~ - :doc:`plugins/missing`: Fix ``--album`` mode incorrectly reporting albums already in the library as missing. The comparison now correctly uses ``mb_releasegroupid``. - :ref:`replace`: Made ``drive_sep_replace`` regex logic more precise to prevent edge-case mismatches (e.g., a song titled "1:00 AM" would incorrectly be considered a Windows drive path). - :doc:`plugins/fish`: Fix AttributeError. :bug:`6340` - :ref:`import-cmd` Autotagging by explicit release or recording IDs now keeps candidates from all enabled metadata sources instead of dropping matches when different providers share the same ID. :bug:`6178` :bug:`6181` - :doc:`plugins/mbsync` and :doc:`plugins/missing` now use each item's stored ``data_source`` for ID lookups, with a fallback to ``MusicBrainz``. - :doc:`plugins/musicbrainz`: Use ``va_name`` config for ``albumartist_sort``, ``albumartists_sort``, ``albumartist_credit``, ``albumartists_credit``, and ``albumartists`` on VA releases instead of hardcoded "Various Artists". :bug:`6316` - :doc:`plugins/beatport`: Use ``va_name`` config for the album artist on VA releases instead of hardcoded "Various Artists". :bug:`6316` - :ref:`config-cmd` on Windows now uses ``cmd /c start ""`` for the default editor fallback so ``beet config -e`` works when ``VISUAL`` and ``EDITOR`` are unset. :bug:`6436` - :doc:`plugins/lastimport`: Rename flexible field ``play_count`` to ``lastfm_play_count`` to avoid conflicts with :doc:`plugins/mpdstats`. **Migration**: This cannot be migrated automatically because of the field clash. If you use ``lastimport`` without ``mpdstats``, migrate manually with ``beet modify lastfm_play_count='$play_count'``. - :ref:`import-cmd` Simplify autotag metadata application for albums and singletons, fixing null-overwrite handling and keeping singular/plural artist metadata fields in sync during tagging. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - :py:func:`beets.metadata_plugins.album_for_id` and :py:func:`beets.metadata_plugins.track_for_id` now require a ``data_source`` argument and query only that provider. - Colorisation, diff and layout utility helpers previously imported from :mod:`beets.ui` now live in :mod:`beets.util.color`, :mod:`beets.util.diff`, and :mod:`beets.util.layout`. Update external imports accordingly. - The lastgenre ``tunelog`` helper was generalized into :py:meth:`beets.logging.BeetsLogger.extra_debug`, which emits ``DEBUG`` messages only at verbosity level 3 or higher (for example ``-vvv``). Plugin authors can use it via ``self._log.extra_debug(...)``. Other changes ~~~~~~~~~~~~~ - Deprecate the :doc:`plugins/beatport` and :doc:`plugins/bpsync` plugins. Beatport has retired the API these plugins rely on, making them non-functional. :bug:`3862` - API-backed metadata source plugins can now use :py:class:`~beets.metadata_plugins.SearchApiMetadataSourcePlugin` for shared search orchestration. Implement provider behavior in :py:meth:`~beets.metadata_plugins.SearchApiMetadataSourcePlugin.get_search_query_with_filters` and :py:meth:`~beets.metadata_plugins.SearchApiMetadataSourcePlugin.get_search_response`. - :doc:`guides/installation`: Remove redundant macOS section from the installation guide. :bug:`5993` - :doc:`guides/installation`: Update installation guide to document plugin management with pipx and move package manager instructions to the FAQ. - :doc:`guides/main`: Update quick installation section to reflect current installation guide structure. - :doc:`guides/installation`: Update pipx installation guide link - :doc:`contributing`: Update pipx installation guide link 2.7.1 (March 08, 2026) ---------------------- Bug fixes ~~~~~~~~~ - Tests that depend on the optional ``langdetect`` package are now skipped when the package is not installed. :bug:`6421` 2.7.0 (March 07, 2026) ---------------------- New features ~~~~~~~~~~~~ - :doc:`plugins/lastgenre`: Added ``cleanup_existing`` configuration flag to allow whitelist canonicalization of existing genres. - Add native support for multiple genres per album/track. The ``genres`` field now stores genres as a list and is written to files as multiple individual genre tags (e.g., separate GENRE tags for FLAC/MP3) while the singular ``genre`` field has been removed. The :doc:`plugins/musicbrainz`, :doc:`plugins/beatport`, :doc:`plugins/discogs` and :doc:`plugins/lastgenre` plugins have been updated to populate the ``genres`` field as a list. **Migration**: Existing libraries with comma-separated, semicolon-separated, or slash-separated genre strings (e.g., ``"Rock, Alternative, Indie"``) are automatically migrated to the ``genres`` list when you first run beets after upgrading. The migration runs once when the database schema is updated, splitting genre strings and writing the changes to the database. The updated ``genres`` values will be written to media files the next time you run a command that writes tags (such as ``beet write`` or during import). No manual action or ``mbsync`` is required. The existing values in the legacy ``genre`` field are split by the first separator found in the string, in the following order of precedence: 1. :doc:`plugins/lastgenre` ``separator`` configuration 2. Semicolon followed by a space 3. Comma followed by a space 4. Slash wrapped by spaces - :doc:`plugins/lyrics`: With ``synced`` enabled, existing synced lyrics are no longer replaced by newly fetched plain lyrics, even when ``force`` is enabled. - :doc:`plugins/lyrics`: Remove ``Source: <lyrics-url>`` suffix from lyrics. Store the backend name in ``lyrics_backend``, URL in ``lyrics_url``, language in ``lyrics_language`` and translation language (if translations present) in ``lyrics_translation_language`` flexible attributes. Lyrics are automatically migrated on the first beets run. :bug:`6370` Bug fixes ~~~~~~~~~ - :doc:`plugins/ftintitle`: Fix handling of multiple featured artists with ampersand. - :doc:`plugins/zero`: When the ``omit_single_disc`` option is set, ``disctotal`` is zeroed alongside ``disc``. - :doc:`plugins/fetchart`: Prevent deletion of configured fallback cover art - :ref:`import-cmd` When autotagging, initialise empty multi-valued fields with ``None`` instead of empty list, which caused beets to overwrite existing metadata with empty list values instead of leaving them unchanged. :bug:`6403` - :doc:`plugins/fuzzy`: Improve fuzzy matching when the query is shorter than the field value so substring-style searches produce more useful results. :bug:`2043` - :doc:`plugins/fuzzy`: Force slow query evaluation whenever the fuzzy prefix is used (for example ``~foo`` or ``%%foo``), so fuzzy matching is applied consistently. :bug:`5638` - :ref:`import-cmd` Duplicate detection now works for as-is imports (when ``autotag`` is disabled). Previously, ``duplicate_keys`` and ``duplicate_action`` config options were silently ignored for as-is imports. - :doc:`/plugins/convert`: Fix extension substitution inside path of the exported playlist. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - If you maintain a metadata source plugin that populates the ``genre`` field, please update it to populate a list of ``genres`` instead. You will see a deprecation warning for now, but support for populating the single ``genre`` field will be removed in version ``3.0.0``. Other changes ~~~~~~~~~~~~~ - :ref:`modify-cmd`: Use the following separator to delimit multiple field values: |semicolon_space|. For example ``beet modify albumtypes="album; ep"``. Previously, ``\â�€`` was used as a separator. This applies to fields such as ``artists``, ``albumtypes`` etc. - Improve highlighting of multi-valued fields changes. - :doc:`plugins/edit`: Editing multi-valued fields now behaves more naturally, with list values handled directly to make metadata edits smoother and more predictable. - :doc:`plugins/lastgenre`: The ``separator`` configuration option is removed. Since genres are now stored as a list in the ``genres`` field and written to files as individual genre tags, this option has no effect and has been removed. - :doc:`plugins/lyrics`: To cut down noise from the ``lrclib`` lyrics source, synced lyrics are now checked to ensure the final verse falls within the track's duration. - Updated URLs in the documentation to use HTTPS where possible and updated outdated links. 2.6.2 (February 22, 2026) ------------------------- Bug fixes ~~~~~~~~~ - :doc:`plugins/musicbrainz`: Fix crash when release mediums lack the ``tracks`` key. :bug:`6302` - :doc:`plugins/musicbrainz`: Fix search terms escaping. :bug:`6347` - :doc:`plugins/musicbrainz`: Fix support for ``alias`` and ``tracks`` :conf:`plugins.musicbrainz:extra_tags`. - :doc:`plugins/musicbrainz`: Fix fetching very large releases that have more than 500 tracks. :bug:`6355` - :doc:`plugins/badfiles`: Fix number of found errors in log message - :doc:`plugins/replaygain`: Avoid magic Windows prefix in calls to command backends, such as ``mp3gain``. :bug:`2946` - :doc:`plugins/mbpseudo`: Fix crash due to missing ``artist_credit`` field in the MusicBrainz API response. :bug:`6339` - :ref:`config-cmd`: Improved error message when user-configured editor does not exist. :bug:`6176` Other changes ~~~~~~~~~~~~~ - :doc:`plugins/lyrics`: Disable ``tekstowo`` by default because it blocks the beets User-Agent. 2.6.1 (February 02, 2026) ------------------------- Bug fixes ~~~~~~~~~ - Make ``packaging`` a required dependency. :bug:`6332` 2.6.0 (February 01, 2026) ------------------------- Beets now requires Python 3.10 or later since support for EOL Python 3.9 has been dropped. New features ~~~~~~~~~~~~ - :doc:`plugins/fetchart`: Added config setting for a fallback cover art image. - :doc:`plugins/ftintitle`: Added argument for custom feat. words in ftintitle. - :doc:`plugins/ftintitle`: Added album template value ``album_artist_no_feat``. - :doc:`plugins/musicbrainz`: Allow selecting tags or genres to populate the genres tag. - :doc:`plugins/ftintitle`: Added argument to skip the processing of artist and album artist are the same in ftintitle. - :doc:`plugins/play`: Added ``$playlist`` marker to precisely edit the playlist filepath into the command calling the player program. - :doc:`plugins/lastgenre`: For tuning plugin settings ``-vvv`` can be passed to receive extra verbose logging around last.fm results and how they are resolved. The ``extended_debug`` config setting and ``--debug`` option have been removed. - :doc:`plugins/importsource`: Added new plugin that tracks original import paths and optionally suggests removing source files when items are removed from the library. - :doc:`plugins/mbpseudo`: Add a new ``mbpseudo`` plugin to proactively receive MusicBrainz pseudo-releases as recommendations during import. - Added support for Python 3.13. - :doc:`/plugins/convert`: ``force`` can be passed to override checks like no_convert, never_convert_lossy_files, same format, and max_bitrate - :doc:`plugins/titlecase`: Add the ``titlecase`` plugin to allow users to resolve differences in metadata source styles. - :doc:`plugins/spotify`: Added support for multi-artist albums and tracks, saving all contributing artists to the respective fields. - :doc:`plugins/fetchart`: Fix colorized output text. - :doc:`plugins/ftintitle`: Featured artists are now inserted before brackets containing remix/edit-related keywords (e.g., "Remix", "Live", "Edit") instead of being appended at the end. This improves formatting for titles like "Song 1 (Carol Remix) ft. Bob" which becomes "Song 1 ft. Bob (Carol Remix)". A variety of brackets are supported and a new ``bracket_keywords`` configuration option allows customizing the keywords. Setting ``bracket_keywords`` to an empty list matches any bracket content regardless of keywords. - :doc:`plugins/discogs`: Added support for multi value fields. :bug:`6068` - :doc:`plugins/embedart`: Embedded arts can now be cleared during import with the ``clearart_on_import`` config option. Also, ``beet clearart`` is only going to update the files matching the query and with an embedded art, leaving untouched the files without. - :doc:`plugins/fish`: Filenames are now completed in more places, like after ``beet import``. - :doc:`plugins/random`: Added ``--field`` option to specify which field to use for equal-chance sampling (default: ``albumartist``). Bug fixes ~~~~~~~~~ - :doc:`/plugins/lastgenre`: Canonicalize genres when ``force`` and ``keep_existing`` are ``on``, yet no genre info on lastfm could be found. :bug:`6303` - Handle potential OSError when unlinking temporary files in ArtResizer. :bug:`5615` - :doc:`/plugins/spotify`: Updated Spotify API credentials. :bug:`6270` - :doc:`/plugins/smartplaylist`: Fixed an issue where multiple queries in a playlist configuration were not preserving their order, causing items to appear in database order rather than the order specified in the config. :bug:`6183` - :doc:`plugins/inline`: Fix recursion error when an inline field definition shadows a built-in item field (e.g., redefining ``track_no``). Inline expressions now skip self-references during evaluation to avoid infinite recursion. :bug:`6115` - When hardlinking from a symlink (e.g. importing a symlink with hardlinking enabled), dereference the symlink then hardlink, rather than creating a new (potentially broken) symlink :bug:`5676` - :doc:`/plugins/spotify`: The plugin now gracefully handles audio-features API deprecation (HTTP 403 errors). When a 403 error is encountered from the audio-features endpoint, the plugin logs a warning once and skips audio features for all remaining tracks in the session, avoiding unnecessary API calls and rate limit exhaustion. - Running ``beet --config <mypath> config -e`` now edits ``<mypath>`` rather than the default config path. :bug:`5652` - :doc:`plugins/lyrics`: Accepts strings for lyrics sources (previously only accepted a list of strings). :bug:`5962` - Fix a bug introduced in release 2.4.0 where import from any valid import-log-file always threw a "none of the paths are importable" error. - :doc:`/plugins/web`: repair broken ``/item/values/…`` and `/albums/values/…` endpoints. Previously, due to single-quotes (ie. string literal) in the SQL query, the query eg. ``GET /item/values/albumartist`` would return the literal "albumartist" instead of a list of unique album artists. - Sanitize log messages by removing control characters preventing terminal rendering issues. - When using :doc:`plugins/fromfilename` together with :doc:`plugins/edit`, temporary tags extracted from filenames are no longer lost when discarding or cancelling an edit session during import. :bug:`6104` - :ref:`update-cmd` :doc:`plugins/edit` fix display formatting of field changes to clearly show added and removed flexible fields. - :doc:`plugins/lastgenre`: Fix the issue where last.fm doesn't return any result in the artist genre stage because "concatenation" words in the artist name (like "feat.", "+", or "&") prevent it. Using the albumartists list field and fetching a genre for each artist separately improves the chance of receiving valid results in that stage. - :doc:`/plugins/ftintitle`: Fixed artist name splitting to prioritize explicit featuring tokens (feat, ft, featuring) over generic separators (&, and), preventing incorrect splits when both are present. - :doc:`reference/cli`: Fix 'from_scratch' option for singleton imports: delete all (old) metadata when new metadata is applied. :bug:`3706` - :doc:`/plugins/convert`: ``auto_keep`` now respects ``no_convert`` and ``never_convert_lossy_files`` when deciding whether to copy/transcode items, avoiding extra lossy duplicates. - :doc:`plugins/discogs`: Fixed unexpected flex attr from the Discogs plugin. :bug:`6177` - Errors in metadata plugins during autotage process will now be logged but won't crash beets anymore. If you want to raise exceptions instead, set the new configuration option ``raise_on_error`` to ``yes`` :bug:`5903`, :bug:`4789`. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - A new plugin event, ``album_matched``, is sent when an album that is being imported has been matched to its metadata and the corresponding distance has been calculated. - Added a reusable requests handler which can be used by plugins to make HTTP requests with built-in retry and backoff logic. It uses beets user-agent and configures timeouts. See :class:`~beetsplug._utils.requests.RequestHandler` for documentation. - Replaced dependency on ``python-musicbrainzngs`` with a lightweight custom MusicBrainz client implementation and updated relevant plugins accordingly: - :doc:`plugins/listenbrainz` - :doc:`plugins/mbcollection` - :doc:`plugins/mbpseudo` - :doc:`plugins/missing` - :doc:`plugins/musicbrainz` - :doc:`plugins/parentwork` See :class:`~beetsplug._utils.musicbrainz.MusicBrainzAPI` for documentation. For packagers ~~~~~~~~~~~~~ - The minimum supported Python version is now 3.10. - An unused dependency on ``mock`` has been removed. Other changes ~~~~~~~~~~~~~ - The documentation chapter :doc:`dev/paths` has been moved to the "For Developers" section and revised to reflect current best practices (pathlib usage). - Refactored the ``beets/ui/commands.py`` monolithic file (2000+ lines) into multiple modules within the ``beets/ui/commands`` directory for better maintainability. - :doc:`plugins/bpd`: Raise ImportError instead of ValueError when GStreamer is unavailable, enabling ``importorskip`` usage in pytest setup. - Finally removed gmusic plugin and all related code/docs as the Google Play Music service was shut down in 2020. - Updated color documentation with ``bright_*`` and ``bg_bright_*`` entries. - Moved ``beets/random.py`` into ``beetsplug/random.py`` to cleanup core module. - dbcore: Allow models to declare SQL indices; add an ``items.album_id`` index to speed up ``album.items()`` queries. :bug:`5809` 2.5.1 (October 14, 2025) ------------------------ New features ~~~~~~~~~~~~ - :doc:`plugins/zero`: Add new configuration option, ``omit_single_disc``, to allow zeroing the disc number on write for single-disc albums. Defaults to False. Bug fixes ~~~~~~~~~ - |BeetsPlugin|: load the last plugin class defined in the plugin namespace. :bug:`6093` For packagers ~~~~~~~~~~~~~ - Fixed issue with legacy metadata plugins not copying properties from the base class. - Reverted the following: When installing ``beets`` via git or locally the version string now reflects the current git branch and commit hash. :bug:`6089` Other changes ~~~~~~~~~~~~~ - Removed outdated mailing list contact information from the documentation :bug:`5462`. - :doc:`guides/main`: Modernized the *Getting Started* guide with tabbed sections and dropdown menus. Installation instructions have been streamlined, and a new subpage now provides additional setup details. - Documentation: introduced a new role ``conf`` for documenting configuration options. This role provides consistent formatting and creates references automatically. Applied it to :doc:`plugins/deezer`, :doc:`plugins/discogs`, :doc:`plugins/musicbrainz` and :doc:`plugins/spotify` plugins documentation. 2.5.0 (October 11, 2025) ------------------------ New features ~~~~~~~~~~~~ - :doc:`plugins/lastgenre`: Add a ``--pretend`` option to preview genre changes without storing or writing them. - :doc:`plugins/convert`: Add a config option to disable writing metadata to converted files. - :doc:`plugins/discogs`: New config option :conf:`plugins.discogs:strip_disambiguation` to toggle stripping discogs numeric disambiguation on artist and label fields. - :doc:`plugins/discogs` Added support for featured artists. :bug:`6038` - :doc:`plugins/discogs` New configuration option :conf:`plugins.discogs:featured_string` to change the default string used to join featured artists. The default string is ``Feat.``. - :doc:`plugins/discogs` Support for ``artist_credit`` in Discogs tags. :bug:`3354` - :doc:`plugins/discogs` Support for name variations and config options to specify where the variations are written. :bug:`3354` - :doc:`plugins/web` Support for ``nexttrack`` keyboard press Bug fixes ~~~~~~~~~ - :doc:`plugins/musicbrainz` Refresh flexible MusicBrainz metadata on reimport so format changes are applied. :bug:`6036` - :doc:`plugins/spotify` Ensure ``spotifysync`` keeps popularity, ISRC, and related fields current even when audio features requests fail. :bug:`6061` - :doc:`plugins/spotify` Fixed an issue where track matching and lookups could return incorrect or misleading results when using the Spotify plugin. The problem occurred primarily when no album was provided or when the album field was an empty string. :bug:`5189` - :doc:`plugins/spotify` Removed old and undocumented config options ``artist_field``, ``album_field`` and ``track`` that were causing issues with track matching. :bug:`5189` - :doc:`plugins/spotify` Fixed an issue where candidate lookup would not find matches due to query escaping (single vs double quotes). - :doc:`plugins/discogs` Fixed inconsistency in stripping disambiguation from artists but not labels. :bug:`5366` - :doc:`plugins/chroma` :doc:`plugins/bpsync` Fix plugin loading issue caused by an import of another |BeetsPlugin| class. :bug:`6033` - :doc:`/plugins/fromfilename`: Fix :bug:`5218`, improve the code (refactor regexps, allow for more cases, add some logging), add tests. - Metadata source plugins: Fixed data source penalty calculation that was incorrectly applied during import matching. The :conf:`plugins.index:source_weight` configuration option has been renamed to :conf:`plugins.index:data_source_mismatch_penalty` to better reflect its purpose. :bug:`6066` Other changes ~~~~~~~~~~~~~ - :doc:`plugins/index`: Clarify that musicbrainz must be mentioned if plugin list modified :bug:`6020` - :doc:`/faq`: Add check for musicbrainz plugin if auto-tagger can't find a match :bug:`6020` - :doc:`guides/tagger`: Section on no matching release found, related to possibly disabled musicbrainz plugin :bug:`6020` - Moved ``art.py`` utility module from ``beets`` into ``beetsplug`` namespace as it is not used in the core beets codebase. It can now be found in ``beetsplug._utils``. - Moved ``vfs.py`` utility module from ``beets`` into ``beetsplug`` namespace as it is not used in the core beets codebase. It can now be found in ``beetsplug._utils``. - :class:`beets.metadata_plugins.MetadataSourcePlugin`: Remove discogs specific disambiguation stripping. - When installing ``beets`` via git or locally the version string now reflects the current git branch and commit hash. :bug:`4448` - :ref:`match-config`: ``match.distance_weights.source`` configuration has been renamed to ``match.distance_weights.data_source`` for consistency with the name of the field it refers to. For developers and plugin authors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Typing improvements in ``beets/logging.py``: ``getLogger`` now returns ``BeetsLogger`` when called with a name, or ``RootLogger`` when called without a name. - The ``track_distance()`` and ``album_distance()`` methods have been removed from ``MetadataSourcePlugin``. Distance calculation for data source mismatches is now handled automatically by the core matching logic. This change simplifies the plugin architecture and fixes incorrect penalty calculations. :bug:`6066` - Metadata source plugins are now registered globally when instantiated, which makes their handling slightly more efficient. 2.4.0 (September 13, 2025) -------------------------- New features ~~~~~~~~~~~~ - :doc:`plugins/musicbrainz`: The MusicBrainz autotagger has been moved to a separate plugin. The default :ref:`plugins-config` includes ``musicbrainz``, but if you've customized your ``plugins`` list in your configuration, you'll need to explicitly add ``musicbrainz`` to continue using this functionality. Configuration option :conf:`plugins.musicbrainz:enabled` has thus been deprecated. :bug:`2686` :bug:`4605` - :doc:`plugins/web`: Show notifications when a track plays. This uses the Media Session API to customize media notifications. - :doc:`plugins/discogs`: Add configurable :conf:`plugins.discogs:search_limit` option to limit the number of results returned by the Discogs metadata search queries. - :doc:`plugins/discogs`: Implement ``track_for_id`` method to allow retrieving singletons by their Discogs ID. :bug:`4661` - :doc:`plugins/replace`: Add new plugin. - :doc:`plugins/duplicates`: Add ``--remove`` option, allowing to remove from the library without deleting media files. :bug:`5832` - :doc:`plugins/playlist`: Support files with the ``.m3u8`` extension. :bug:`5829` - :doc:`plugins/mbcollection`: When getting the user collections, only consider collections of releases, and ignore collections of other entity types. - :doc:`plugins/mpdstats`: Add new configuration option, ``played_ratio_threshold``, to allow configuring the percentage the song must be played for it to be counted as played instead of skipped. - :doc:`plugins/web`: Display artist and album as part of the search results. - :doc:`plugins/spotify` :doc:`plugins/deezer`: Add new configuration option :conf:`plugins.index:search_limit` to limit the number of results returned by search queries. Bug fixes ~~~~~~~~~ - :doc:`plugins/musicbrainz`: fix regression where user configured :conf:`plugins.musicbrainz:extra_tags` have been read incorrectly. :bug:`5788` - tests: Fix library tests failing on Windows when run from outside ``D:/``. :bug:`5802` - Fix an issue where calling ``Library.add`` would cause the ``database_change`` event to be sent twice, not once. :bug:`5560` - Fix ``HiddenFileTest`` by using ``bytestring_path()``. - tests: Fix tests failing without ``langdetect`` (by making it required). :bug:`5797` - :doc:`plugins/musicbrainz`: Fix the MusicBrainz search not taking into account the album/recording aliases - :doc:`/plugins/spotify`: Fix the issue with that every query to spotify was ascii encoded. This resulted in bad matches for queries that contained special e.g. non latin characters as 盗作. If you want to keep the legacy behavior set the config option ``spotify.search_query_ascii: yes``. :bug:`5699` - :doc:`plugins/discogs`: Beets will no longer crash if a release has been deleted, and returns a 404. - :doc:`plugins/lastgenre`: Fix the issue introduced in Beets 2.3.0 where non-whitelisted last.fm genres were not canonicalized to parent genres. :bug:`5930` - :doc:`plugins/chroma`: AcoustID lookup HTTP requests will now time out after 10 seconds, rather than hanging the entire import process. - :doc:`/plugins/deezer`: Fix the issue with that every query to deezer was ascii encoded. This resulted in bad matches for queries that contained special e.g. non latin characters as 盗作. If you want to keep the legacy behavior set the config option ``deezer.search_query_ascii: yes``. :bug:`5860` - Fixed regression with :doc:`/plugins/listenbrainz` where the plugin could not be loaded :bug:`5975` - :doc:`/plugins/fromfilename`: Beets will no longer crash if a track's title field is missing. For packagers ~~~~~~~~~~~~~ - Optional :conf:`plugins.musicbrainz:extra_tags` parameter has been removed from ``BeetsPlugin.candidates`` method signature since it is never passed in. If you override this method in your plugin, feel free to remove this parameter. - Loosened ``typing_extensions`` dependency in pyproject.toml to apply to every python version. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - The ``fetchart`` plugins has seen a few changes to function signatures and source registration in the process of introducing typings to the code. Custom art sources might need to be adapted. - We split the responsibilities of plugins into two base classes 1. |BeetsPlugin| is the base class for all plugins, any plugin needs to inherit from this class. 2. :class:`beets.metadata_plugins.MetadataSourcePlugin` allows plugins to act like metadata sources. E.g. used by the MusicBrainz plugin. All plugins in the beets repo are opted into this class where applicable. If you are maintaining a plugin that acts like a metadata source, i.e. you expose any of ``track_for_id``, ``album_for_id``, ``candidates``, ``item_candidates``, ``album_distance``, ``track_distance`` methods, please update your plugin to inherit from the new baseclass, as otherwise your plugin will stop working with the next major release. - Several definitions have been moved: - ``BLOB_TYPE`` constant, ``PathQuery`` and ``SingletonQuery`` queries have moved from ``beets.library`` to ``beets.dbcore.query`` module - ``DateType``, ``DurationType``, ``PathType`` types and ``MusicalKey`` class have moved from ``beets.library`` to ``beets.dbcore.types`` module. - ``Distance`` has moved from ``beets.autotag`` to ``beets.autotag.distance`` module. - ``beets.autotag.current_metadata`` has been renamed to ``beets.util.get_most_common_tags``. Old imports are now deprecated and will be removed in version ``3.0.0``. - ``beets.ui.decargs`` is deprecated and will be removed in version ``3.0.0``. - Beets is now PEP 561 compliant, which means that it provides type hints for all public APIs. This allows IDEs to provide better autocompletion and type checking for downstream users of the beets API. - ``plugins.find_plugins`` function does not anymore load plugins. You need to explicitly call ``plugins.load_plugins()`` to load them. - ``plugins.load_plugins`` function does not anymore accept the list of plugins to load. Instead, it loads all plugins that are configured by :ref:`plugins-config` configuration. - Flexible fields, which can be used by plugins to store additional metadata, now also support list values. Previously, beets would throw an error while storing the data in the SQL database due to missing type conversion. :bug:`5698` Other changes ~~~~~~~~~~~~~ - Refactor: Split responsibilities of Plugins into MetaDataPlugins and general Plugins. - Documentation structure for auto generated API references changed slightly. Autogenerated API references are now located in the ``docs/api`` subdirectory. - :doc:`/plugins/substitute`: Fix rST formatting for example cases so that each case is shown on separate lines. - :doc:`/plugins/ftintitle`: Process items whose albumartist is not contained in the artist field, including compilations using Various Artists as an albumartist and album tracks by guest artists featuring a third artist. - Refactored library.py file by splitting it into multiple modules within the beets/library directory. - Added a test to check that all plugins can be imported without errors. - :doc:`/guides/main`: Add instructions to install beets on Void Linux. - :doc:`plugins/lastgenre`: Refactor loading whitelist and canonicalization file. :bug:`5979` - :doc:`plugins/lastgenre`: Updated and streamlined the genre whitelist and canonicalization tree :bug:`5977` - UI: Update default ``text_diff_added`` color from **bold red** to **bold green.** - UI: Use ``text_diff_added`` and ``text_diff_removed`` colors in **all** diff comparisons, including case differences. 2.3.1 (May 14, 2025) -------------------- Bug fixes ~~~~~~~~~ - :doc:`/reference/pathformat`: Fixed a regression where path legalization incorrectly removed parts of user-configured path formats that followed a dot (**.**). :bug:`5771` For packagers ~~~~~~~~~~~~~ - Force ``poetry`` version below 2 to avoid it mangling file modification times in ``sdist`` package. :bug:`5770` 2.3.0 (May 07, 2025) -------------------- Beets now requires Python 3.9 or later since support for EOL Python 3.8 has been dropped. New features ~~~~~~~~~~~~ - :doc:`plugins/lastgenre`: The new configuration option, ``keep_existing``, provides more fine-grained control over how pre-populated genre tags are handled. The ``force`` option now behaves in a more conventional manner. :bug:`4982` - :doc:`plugins/lyrics`: Add new configuration option ``dist_thresh`` to control the maximum allowed distance between the lyrics search result and the tagged item's artist and title. This is useful for preventing false positives when fetching lyrics. - :doc:`plugins/lyrics`: Rewrite lyrics translation functionality to use Azure AI Translator API and add relevant instructions to the documentation. - :doc:`plugins/missing`: Add support for all metadata sources. - :doc:`plugins/mbsync`: Add support for all metadata sorces. Bug fixes ~~~~~~~~~ - :doc:`plugins/thumbnails`: Fix API call to GIO on big endian architectures (like s390x) in thumbnails plugin. :bug:`5708` - :doc:`plugins/listenbrainz`: Fix rST formatting for URLs of Listenbrainz API Key documentation and config.yaml. - :doc:`plugins/listenbrainz`: Fix ``UnboundLocalError`` in cases where 'mbid' is not defined. - :doc:`plugins/fetchart`: Fix fetchart bug where a tempfile could not be deleted due to never being properly closed. :bug:`5521` - :doc:`plugins/lyrics`: LRCLib will fallback to plain lyrics if synced lyrics are not found and ``synced`` flag is set to ``yes``. - Synchronise files included in the source distribution with what we used to have before the introduction of Poetry. :bug:`5531` :bug:`5526` - :ref:`write-cmd`: Fix the issue where for certain files differences in ``mb_artistid``, ``mb_albumartistid`` and ``albumtype`` fields are shown on every attempt to write tags. Note: your music needs to be reimported with ``beet import -LI`` or synchronised with ``beet mbsync`` in order to fix this! :bug:`5265` :bug:`5371` :bug:`4715` - :ref:`import-cmd`: Fix ``MemoryError`` and improve performance tagging large albums by replacing ``munkres`` library with ``lap.lapjv``. :bug:`5207` - :ref:`query-sort`: Fix a bug that would raise an exception when sorting on a non-string field that is not populated in all items. :bug:`5512` - :doc:`plugins/lastgenre`: Fix track-level genre handling. Now when an album-level genre is set already, single tracks don't fall back to the album's genre and request their own last.fm genre. Also log messages regarding what's been tagged are now more polished. :bug:`5582` - Fix ambiguous column name ``sqlite3.OperationalError`` that occured in album queries that filtered album track titles, for example ``beet list -a keyword title:foo``. - :doc:`plugins/lyrics`: Rewrite lyrics tests using pytest to provide isolated configuration for each test case. This fixes the issue where some tests failed because they read developers' local lyrics configuration. :bug:`5133` - :doc:`plugins/lyrics`: Do not attempt to search for lyrics if either the artist or title is missing and ignore ``artist_sort`` value if it is empty. :bug:`2635` - :doc:`plugins/lyrics`: Fix fetching lyrics from ``lrclib`` source. If we cannot find lyrics for a specific album, artist, title combination, the plugin now tries to search for the artist and title and picks the most relevant result. Update the default ``sources`` configuration to prioritize ``lrclib`` over other sources since it returns reliable results quicker than others. :bug:`5102` - :doc:`plugins/lyrics`: Fix the issue with ``genius`` backend not being able to match lyrics when there is a slight variation in the artist name. :bug:`4791` - :doc:`plugins/lyrics`: Fix plugin crash when ``genius`` backend returns empty lyrics. :bug:`5583` - ImageMagick 7.1.1-44 is now supported. - :doc:`plugins/parentwork`: Only output parentwork changes when running in verbose mode. For packagers ~~~~~~~~~~~~~ - The minimum supported Python version is now 3.9. - External plugin developers: ``beetsplug/__init__.py`` file can be removed from your plugin as beets now uses native/implicit namespace package setup. Other changes ~~~~~~~~~~~~~ - Release workflow: fix the issue where the new release tag is created for the wrong (outdated) commit. Now the tag is created in the same workflow step right after committing the version update. :bug:`5539` - :doc:`/plugins/smartplaylist`: URL-encode additional item ``fields`` within generated EXTM3U playlists instead of JSON-encoding them. - typehints: ``./beets/importer.py`` file now has improved typehints. - typehints: ``./beets/plugins.py`` file now includes typehints. - :doc:`plugins/ftintitle`: Optimize the plugin by avoiding unnecessary writes to the database. - Database models are now serializable with pickle. 2.2.0 (December 02, 2024) ------------------------- New features ~~~~~~~~~~~~ - :doc:`/plugins/substitute`: Allow the replacement string to use capture groups from the match. It is thus possible to create more general rules, applying to many different artists at once. Bug fixes ~~~~~~~~~ - Check if running python from the Microsoft Store and provide feedback to install from python.org. :bug:`5467` - Fix bug where matcher doesn't consider medium number when importing. This makes it difficult to import hybrid SACDs and other releases with duplicate tracks. :bug:`5148` - Bring back test files and the manual to the source distribution tarball. :bug:`5513` Other changes ~~~~~~~~~~~~~ - Changed ``bitesize`` label to ``good first issue``. Our contribute_ page is now automatically populated with these issues. :bug:`4855` .. _contribute: https://github.com/beetbox/beets/contribute 2.1.0 (November 22, 2024) ------------------------- New features ~~~~~~~~~~~~ - New template function added: ``%capitalize``. Converts the first letter of the text to uppercase and the rest to lowercase. - Ability to query albums with track db fields and vice-versa, for example ``beet list -a title:something`` or ``beet list artpath:cover``. Consequently album queries involving ``path`` field have been sped up, like ``beet list -a path:/path/``. - :doc:`plugins/ftintitle`: New ``keep_in_artist`` option for the plugin, which allows keeping the "feat." part in the artist metadata while still changing the title. - :doc:`plugins/autobpm`: Add new configuration option ``beat_track_kwargs`` which enables adjusting keyword arguments supplied to librosa's ``beat_track`` function call. - Beets now uses ``platformdirs`` to determine the default music directory. This location varies between systems -- for example, users can configure it on Unix systems via ``user-dirs.dirs(5)``. Bug fixes ~~~~~~~~~ - :doc:`plugins/ftintitle`: The detection of a "feat. X" part in a song title does not produce any false positives caused by words like "and" or "with" anymore. :bug:`5441` - :doc:`plugins/ftintitle`: The detection of a "feat. X" part now also matches such parts if they are in parentheses or brackets. :bug:`5436` - Improve naming of temporary files by separating the random part with the file extension. - Fix the ``auto`` value for the :ref:`reflink` config option. - Fix lyrics plugin only getting part of the lyrics from ``Genius.com`` :bug:`4815` - Album flexible fields are now correctly saved. For instance MusicBrainz external links such as ``bandcamp_album_id`` will be available on albums in addition to tracks. For albums already in your library, a re-import is required for the fields to be added. Such a re-import can be done with, in this case, ``beet import -L data_source:=MusicBrainz``. - :doc:`plugins/autobpm`: Fix the ``TypeError`` where tempo was being returned as a numpy array. Update ``librosa`` dependency constraint to prevent similar issues in the future. :bug:`5289` - :doc:`plugins/discogs`: Fix the ``TypeError`` when there is no description. - Use single quotes in all SQL queries :bug:`4709` - :doc:`plugins/lyrics`: Update ``tekstowo`` backend to fetch lyrics directly since recent updates to their website made it unsearchable. :bug:`5456` - :doc:`plugins/convert`: Fixed the convert plugin ``no_convert`` option so that it no longer treats "and" and "or" queries the same. To maintain previous behaviour add commas between your query keywords. For help see :ref:`combiningqueries`. - Fix the ``TypeError`` when :ref:`set_fields` is provided non-string values. :bug:`4840` For packagers ~~~~~~~~~~~~~ - The minimum supported Python version is now 3.8. - The ``beet`` script has been removed from the repository. - The ``typing_extensions`` is required for Python 3.10 and below. Other changes ~~~~~~~~~~~~~ - :doc:`contributing`: The project now uses ``poetry`` for packaging and dependency management. This change affects project management and mostly affects beets developers. Please see updates in :ref:`getting-the-source` and :ref:`testing` for more information. - :doc:`contributing`: Since ``poetry`` now manages local virtual environments, ``tox`` has been replaced by a task runner ``poethepoet``. This change affects beets developers and contributors. Please see updates in the :ref:`development-tools` section for more details. Type ``poe`` while in the project directory to see the available commands. - Installation instructions have been made consistent across plugins documentation. Users should simply install ``beets`` with an ``extra`` of the corresponding plugin name in order to install extra dependencies for that plugin. - GitHub workflows have been reorganised for clarity: style, linting, type and docs checks now live in separate jobs and are named accordingly. - Added caching for dependency installation in all CI jobs which speeds them up a bit, especially the tests. - The linting workflow has been made to run only when Python files or documentation is changed, and they only check the changed files. When dependencies are updated (``poetry.lock``), then the entire code base is checked. - The long-deprecated ``beets.util.confit`` module has been removed. This may cause extremely outdated external plugins to fail to load. - :doc:`plugins/autobpm`: Add plugin dependencies to ``pyproject.toml`` under the ``autobpm`` extra and update the plugin installation instructions in the docs. Since importing the bpm calculation functionality from ``librosa`` takes around 4 seconds, update the plugin to only do so when it actually needs to calculate the bpm. Previously this import was being done immediately, so every ``beet`` invocation was being delayed by a couple of seconds. :bug:`5185` 2.0.0 (May 30, 2024) -------------------- With this release, beets now requires Python 3.7 or later (it removes support for Python 3.6). Major new features ~~~~~~~~~~~~~~~~~~ - The beets importer UI received a major overhaul. Several new configuration options are available for customizing layout and colors: :ref:`ui_options`. :bug:`3721` :bug:`5028` New features ~~~~~~~~~~~~ - :doc:`/plugins/edit`: Prefer editor from ``VISUAL`` environment variable over ``EDITOR``. - :ref:`config-cmd`: Prefer editor from ``VISUAL`` environment variable over ``EDITOR``. - :doc:`/plugins/listenbrainz`: Add initial support for importing history and playlists from ``ListenBrainz`` :bug:`1719` - :doc:`plugins/mbsubmit`: add new prompt choices helping further to submit unmatched tracks to MusicBrainz faster. - :doc:`plugins/spotify`: We now fetch track's ISRC, EAN, and UPC identifiers from Spotify when using the ``spotifysync`` command. :bug:`4992` - :doc:`plugins/discogs`: supply a value for the ``cover_art_url`` attribute, for use by ``fetchart``. :bug:`429` - :ref:`update-cmd`: added ``-e`` flag for excluding fields from being updated. - :doc:`/plugins/deezer`: Import rank and other attributes from Deezer during import and add a function to update the rank of existing items. :bug:`4841` - resolve transl-tracklisting relations for pseudo releases and merge data with the actual release :bug:`654` - Fetchart: Use the right field (``spotify_album_id``) to obtain the Spotify album id :bug:`4803` - Prevent reimporting album if it is permanently removed from Spotify :bug:`4800` - Added option to use ``cover_art_url`` as an album art source in the ``fetchart`` plugin. :bug:`4707` - :doc:`/plugins/fetchart`: The plugin can now get album art from ``spotify``. - Added option to specify a URL in the ``embedart`` plugin. :bug:`83` - :ref:`list-cmd` ``singleton:true`` queries have been made faster - :ref:`list-cmd` ``singleton:1`` and ``singleton:0`` can now alternatively be used in queries, same as ``comp`` - --from-logfile now parses log files using a UTF-8 encoding in ``beets/beets/ui/commands.py``. :bug:`4693` - :doc:`/plugins/bareasc` lookups have been made faster - :ref:`list-cmd` lookups using the pattern operator ``::`` have been made faster - Added additional error handling for ``spotify`` plugin. :bug:`4686` - We now import the remixer field from Musicbrainz into the library. :bug:`4428` - :doc:`/plugins/mbsubmit`: Added a new ``mbsubmit`` command to print track information to be submitted to MusicBrainz after initial import. :bug:`4455` - Added ``spotify_updated`` field to track when the information was last updated. - We now import and tag the ``album`` information when importing singletons using Spotify source. :bug:`4398` - :doc:`/plugins/spotify`: The plugin now provides an additional command ``spotifysync`` that allows getting track popularity and audio features information from Spotify. :bug:`4094` - :doc:`/plugins/spotify`: The plugin now records Spotify-specific IDs in the ``spotify_album_id``, ``spotify_artist_id``, and ``spotify_track_id`` fields. :bug:`4348` - Create the parental directories for database if they do not exist. :bug:`3808` :bug:`4327` - :ref:`musicbrainz-config`: a new :conf:`plugins.musicbrainz:enabled` option allows disabling the MusicBrainz metadata source during the autotagging process - :doc:`/plugins/kodiupdate`: Now supports multiple kodi instances :bug:`4101` - Add the item fields ``bitrate_mode``, ``encoder_info`` and ``encoder_settings``. - Add query prefixes ``=`` and ``~``. - A new configuration option, :ref:`duplicate_keys`, lets you change which fields the beets importer uses to identify duplicates. :bug:`1133` :bug:`4199` - Add :ref:`exact match <exact-match>` queries, using the prefixes ``=`` and ``=~``. :bug:`4251` - :doc:`/plugins/discogs`: Permit appending style to genre. - :doc:`plugins/discogs`: Implement item_candidates for matching singletons. - :doc:`plugins/discogs`: Check for compliant discogs_client module. - :doc:`/plugins/convert`: Add a new ``auto_keep`` option that automatically converts files but keeps the *originals* in the library. :bug:`1840` :bug:`4302` - Added a ``-P`` (or ``--disable-plugins``) flag to specify one/multiple plugin(s) to be disabled at startup. - :ref:`import-options`: Add support for re-running the importer on paths in log files that were created with the ``-l`` (or ``--logfile``) argument. :bug:`4379` :bug:`4387` - Preserve mtimes from archives :bug:`4392` - Add :ref:`%sunique{} <sunique>` template to disambiguate between singletons. :bug:`4438` - Add a new ``import.ignored_alias_types`` config option to allow for specific alias types to be skipped over when importing items/albums. - :doc:`/plugins/smartplaylist`: A new ``--pretend`` option lets the user see what a new or changed smart playlist saved in the config is actually returning. :bug:`4573` - :doc:`/plugins/fromfilename`: Add debug log messages that inform when the plugin replaced bad (missing) artist, title or tracknumber metadata. :bug:`4561` :bug:`4600` - :ref:`musicbrainz-config`: MusicBrainz release pages often link to related metadata sources like Discogs, Bandcamp, Spotify, Deezer and Beatport. When enabled via the :conf:`plugins.musicbrainz:external_ids` options, release ID's will be extracted from those URL's and imported to the library. :bug:`4220` - :doc:`/plugins/convert`: Add support for generating m3u8 playlists together with converted media files. :bug:`4373` - Fetch the ``release_group_title`` field from MusicBrainz. :bug:`4809` - :doc:`plugins/discogs`: Add support for applying album information on singleton imports. :bug:`4716` - :doc:`/plugins/smartplaylist`: During explicit runs of the ``splupdate`` command, the log message "Creating playlist ..."" is now displayed instead of hidden in the debug log, which states some form of progress through the UI. :bug:`4861` - :doc:`plugins/subsonicupdate`: Updates are now triggered whenever either the beets database is changed or a smart playlist is created/updated. :bug:`4862` - :doc:`plugins/importfeeds`: Add a new output format allowing to save a playlist once per import session. :bug:`4863` - Make ArtResizer work with :pypi:`PIL`/:pypi:`pillow` 10.0.0 removals. :bug:`4869` - A new configuration option, :ref:`duplicate_verbose_prompt`, allows changing how duplicates are presented during import. :bug:`4866` - :doc:`/plugins/embyupdate`: Add handling for private users by adding ``userid`` config option. :bug:`4402` - :doc:`/plugins/substitute`: Add the new plugin ``substitute`` as an alternative to the ``rewrite`` plugin. The main difference between them being that ``rewrite`` modifies files' metadata and ``substitute`` does not. :bug:`2786` - Add support for ``artists`` and ``albumartists`` multi-valued tags. :bug:`505` - :doc:`/plugins/autobpm`: Add the ``autobpm`` plugin which uses Librosa to calculate the BPM of the audio. :bug:`3856` - :doc:`/plugins/fetchart`: Fix the error with CoverArtArchive where the ``maxwidth`` option would not be used to download a pre-sized thumbnail for release groups, as is already done with releases. - :doc:`/plugins/fetchart`: Fix the error with CoverArtArchive where no cover would be found when the ``maxwidth`` option matches a pre-sized thumbnail size, but no thumbnail is provided by CAA. We now fallback to the raw image. - :doc:`/plugins/advancedrewrite`: Add an advanced version of the ``rewrite`` plugin which allows to replace fields based on a given library query. - :doc:`/plugins/lyrics`: Add LRCLIB as a new lyrics provider and a new ``synced`` option to prefer synced lyrics over plain lyrics. - :ref:`import-cmd`: Expose import.quiet_fallback as CLI option. - :ref:`import-cmd`: Expose ``import.incremental_skip_later`` as CLI option. - :doc:`/plugins/smartplaylist`: Expose config options as CLI options. - :doc:`/plugins/smartplaylist`: Add new option ``smartplaylist.output``. - :doc:`/plugins/smartplaylist`: Add new option ``smartplaylist.uri_format``. - Sorted the default configuration file into categories. :bug:`4987` - :doc:`/plugins/convert`: Don't treat WAVE (``.wav``) files as lossy anymore when using the ``never_convert_lossy_files`` option. They will get transcoded like the other lossless formats. - Add support for ``barcode`` field. :bug:`3172` - :doc:`/plugins/smartplaylist`: Add new config option ``smartplaylist.fields``. - :doc:`/plugins/fetchart`: Defer source removal config option evaluation to the point where they are used really, supporting temporary config changes. Bug fixes ~~~~~~~~~ - Improve ListenBrainz error handling. :bug:`5459` - :doc:`/plugins/deezer`: Improve requests error handling. - :doc:`/plugins/lastimport`: Improve error handling in the ``process_tracks`` function and enable it to be used with other plugins. - :doc:`/plugins/spotify`: Improve handling of ConnectionError. - :doc:`/plugins/deezer`: Improve Deezer plugin error handling and set requests timeout to 10 seconds. :bug:`4983` - :doc:`/plugins/spotify`: Add bad gateway (502) error handling. - :doc:`/plugins/spotify`: Add a limit of 3 retries, instead of retrying endlessly when the API is not available. - Fix a crash when the Spotify API timeouts or does not return a ``Retry-After`` interval. :bug:`4942` - :doc:`/plugins/scrub`: Fixed the import behavior where scrubbed database tags were restored to newly imported tracks with config settings ``scrub.auto: yes`` and ``import.write: no``. :bug:`4326` - :doc:`/plugins/deezer`: Fixed the error where Deezer plugin would crash if non-Deezer id is passed during import. - :doc:`/plugins/fetchart`: Fix fetching from Cover Art Archive when the ``maxwidth`` option is set to one of the supported Cover Art Archive widths. - :doc:`/plugins/discogs`: Fix "Discogs plugin replacing Feat. or Ft. with a comma" by fixing an oversight that removed a functionality from the code base when the MetadataSourcePlugin abstract class was introduced in PR's #3335 and #3371. :bug:`4401` - :doc:`/plugins/convert`: Set default ``max_bitrate`` value to ``None`` to avoid transcoding when this parameter is not set. :bug:`4472` - :doc:`/plugins/replaygain`: Avoid a crash when errors occur in the analysis backend. :bug:`4506` - We now use Python's defaults for command-line argument encoding, which should reduce the chance for errors and "file not found" failures when invoking other command-line tools, especially on Windows. :bug:`4507` - We now respect the Spotify API's rate limiting, which avoids crashing when the API reports code 429 (too many requests). :bug:`4370` - Fix implicit paths OR queries (e.g. ``beet list /path/ , /other-path/``) which have previously been returning the entire library. :bug:`1865` - The Discogs release ID is now populated correctly to the discogs_albumid field again (it was no longer working after Discogs changed their release URL format). :bug:`4225` - The autotagger no longer considers all matches without a MusicBrainz ID as duplicates of each other. :bug:`4299` - :doc:`/plugins/convert`: Resize album art when embedding :bug:`2116` - :doc:`/plugins/deezer`: Fix auto tagger pagination issues (fetch beyond the first 25 tracks of a release). - :doc:`/plugins/spotify`: Fix auto tagger pagination issues (fetch beyond the first 50 tracks of a release). - :doc:`/plugins/lyrics`: Fix Genius search by using query params instead of body. - :doc:`/plugins/unimported`: The new ``ignore_subdirectories`` configuration option added in 1.6.0 now has a default value if it hasn't been set. - :doc:`/plugins/deezer`: Tolerate missing fields when searching for singleton tracks. :bug:`4116` - :doc:`/plugins/replaygain`: The type of the internal ``r128_track_gain`` and ``r128_album_gain`` fields was changed from integer to float to fix loss of precision due to truncation. :bug:`4169` - Fix a regression in the previous release that caused a ``TypeError`` when moving files across filesystems. :bug:`4168` - :doc:`/plugins/convert`: Deleting the original files during conversion no longer logs output when the ``quiet`` flag is enabled. - :doc:`plugins/web`: Fix handling of "query" requests. Previously queries consisting of more than one token (separated by a slash) always returned an empty result. - :doc:`/plugins/discogs`: Skip Discogs query on insufficiently tagged files (artist and album tags missing) to prevent arbitrary candidate results. :bug:`4227` - :doc:`plugins/lyrics`: Fixed issues with the Tekstowo.pl and Genius backends where some non-lyrics content got included in the lyrics - :doc:`plugins/limit`: Better header formatting to improve index - :doc:`plugins/replaygain`: Correctly handle the ``overwrite`` config option, which forces recomputing ReplayGain values on import even for tracks that already have the tags. - :doc:`plugins/embedart`: Fix a crash when using recent versions of ImageMagick and the ``compare_threshold`` option. :bug:`4272` - :doc:`plugins/lyrics`: Fixed issue with Genius header being included in lyrics, added test case of up-to-date Genius html - :doc:`plugins/importadded`: Fix a bug with recently added reflink import option that causes a crash when ImportAdded plugin enabled. :bug:`4389` - :doc:`plugins/convert`: Fix a bug with the ``wma`` format alias. - :doc:`/plugins/web`: Fix get file from item. - :doc:`/plugins/lastgenre`: Fix a duplicated entry for trip hop in the default genre list. :bug:`4510` - :doc:`plugins/lyrics`: Fixed issue with Tekstowo backend not actually checking if the found song matches. :bug:`4406` - :doc:`plugins/embedart`: Add support for ImageMagick 7.1.1-12 :bug:`4836` - :doc:`/plugins/fromfilename`: Fix failed detection of <track> <title> filename patterns. :bug:`4561` :bug:`4600` - Fix issue where deletion of flexible fields on an album doesn't cascade to items :bug:`4662` - Fix issue where ``beet write`` continuously retags the ``albumtypes`` metadata field in files. Additionally broken data could have been added to the library when the tag was read from file back into the library using ``beet update``. It is required for all users to **check if such broken data is present in the library**. Following the instructions `described here <https://github.com/beetbox/beets/pull/4582#issuecomment-1445023493>`_, a sanity check and potential fix is easily possible. :bug:`4528` - Fix updating "data_source" on re-imports and improve logging when flexible attributes are being re-imported. :bug:`4726` - :doc:`/plugins/fetchart`: Correctly select the cover art from fanart.tv with the highest number of likes - :doc:`/plugins/lyrics`: Fix a crash with the Google backend when processing some web pages. :bug:`4875` - Modifying flexible attributes of albums now cascade to the individual album tracks, similar to how fixed album attributes have been cascading to tracks already. A new option ``--noinherit/-I`` to :ref:`modify <modify-cmd>` allows changing this behaviour. :bug:`4822` - Fix bug where an interrupted import process poisons the database, causing a null path that can't be removed. :bug:`4906` - :doc:`/plugins/discogs`: Fix bug where empty artist and title fields would return None instead of an empty list. :bug:`4973` - Fix bug regarding displaying tracks that have been changed not being displayed unless the detail configuration is enabled. - :doc:`/plugins/web`: Fix range request support, allowing to play large audio/ opus files using e.g. a browser/firefox or gstreamer/mopidy directly. - Fix bug where ``zsh`` completion script made assumptions about the specific variant of ``awk`` installed and required specific settings for ``sqlite3`` and caching in ``zsh``. :bug:`3546` - Remove unused functions :bug:`5103` - Fix bug where all media types are reported as the first media type when importing with MusicBrainz as the data source :bug:`4947` - Fix bug where unimported plugin would not ignore children directories of ignored directories. :bug:`5130` - Fix bug where some plugin commands hang indefinitely due to a missing ``requests`` timeout. - Fix cover art resizing logic to support multiple steps of resizing :bug:`5151` - :doc:`/plugins/convert`: Fix attempt to convert and perform side-effects if library file is not readable. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - beets now explicitly prevents multiple plugins to define replacement functions for the same field. When previously defining ``template_fields`` for the same field in two plugins, the last loaded plugin would silently overwrite the function defined by the other plugin. Now, beets will raise an exception when this happens. :bug:`5002` - Allow reuse of some parts of beets' testing components. This may ease the work for externally developed plugins or related software (e.g. the beets plugin for Mopidy), if they need to create an in-memory instance of a beets music library for their tests. For packagers ~~~~~~~~~~~~~ - As noted above, the minimum Python version is now 3.7. - We fixed a version for the dependency on the Confuse_ library. :bug:`4167` - The minimum required version of :pypi:`mediafile` is now 0.9.0. Other changes ~~~~~~~~~~~~~ - Add ``sphinx`` and ``sphinx_rtd_theme`` as dependencies for a new ``docs`` extra :bug:`4643` - :doc:`/plugins/absubmit`: Deprecate the ``absubmit`` plugin since AcousticBrainz has stopped accepting new submissions. :bug:`4627` - :doc:`/plugins/acousticbrainz`: Deprecate the ``acousticbrainz`` plugin since the AcousticBrainz project has shut down. :bug:`4627` - :doc:`/plugins/limit`: Limit query results to head or tail (``lslimit`` command only) - :doc:`/plugins/fish`: Add ``--output`` option. - :doc:`/plugins/lyrics`: Remove Musixmatch from default enabled sources as they are currently blocking requests from the beets user agent. :bug:`4585` - :doc:`/faq`: :ref:`multidisc`: Elaborated the multi-disc FAQ :bug:`4806` - :doc:`/faq`: :ref:`src`: Removed some long lines. - Refactor the test cases to avoid test smells. 1.6.0 (November 27, 2021) ------------------------- This release is our first experiment with time-based releases! We are aiming to publish a new release of beets every 3 months. We therefore have a healthy but not dizzyingly long list of new features and fixes. With this release, beets now requires Python 3.6 or later (it removes support for Python 2.7, 3.4, and 3.5). There are also a few other dependency changes---if you're a maintainer of a beets package for a package manager, thank you for your ongoing efforts, and please see the list of notes below. Major new features ~~~~~~~~~~~~~~~~~~ - When fetching genres from MusicBrainz, we now include genres from the release group (in addition to the release). We also prioritize genres based on the number of votes. Thanks to :user:`aereaux`. - Primary and secondary release types from MusicBrainz are now stored in a new ``albumtypes`` field. Thanks to :user:`edgars-supe`. :bug:`2200` - An accompanying new :doc:`/plugins/albumtypes` includes some options for formatting this new ``albumtypes`` field. Thanks to :user:`edgars-supe`. - The :ref:`modify-cmd` and :ref:`import-cmd` can now use :doc:`/reference/pathformat` formats when setting fields. For example, you can now do ``beet modify title='$track $title'`` to put track numbers into songs' titles. :bug:`488` Other new things ~~~~~~~~~~~~~~~~ - :doc:`/plugins/permissions`: The plugin now sets cover art permissions to match the audio file permissions. - :doc:`/plugins/unimported`: A new configuration option supports excluding specific subdirectories in library. - :doc:`/plugins/info`: Add support for an ``--album`` flag. - :doc:`/plugins/export`: Similarly add support for an ``--album`` flag. - ``beet move`` now highlights path differences in color (when enabled). - When moving files and a direct rename of a file is not possible (for example, when crossing filesystems), beets now copies to a temporary file in the target folder first and then moves to the destination instead of directly copying the target path. This gets us closer to always updating files atomically. Thanks to :user:`catap`. :bug:`4060` - :doc:`/plugins/fetchart`: Add a new option to store cover art as non-progressive image. This is useful for DAPs that do not support progressive images. Set ``deinterlace: yes`` in your configuration to enable this conversion. - :doc:`/plugins/fetchart`: Add a new option to change the file format of cover art images. This may also be useful for DAPs that only support some image formats. - Support flexible attributes in ``%aunique``. :bug:`2678` :bug:`3553` - Make ``%aunique`` faster, especially when using inline fields. :bug:`4145` Bug fixes ~~~~~~~~~ - :doc:`/plugins/lyrics`: Fix a crash when Beautiful Soup is not installed. :bug:`4027` - :doc:`/plugins/discogs`: Support a new Discogs URL format for IDs. :bug:`4080` - :doc:`/plugins/discogs`: Remove built-in rate-limiting because the Discogs Python library we use now has its own rate-limiting. :bug:`4108` - :doc:`/plugins/export`: Fix some duplicated output. - :doc:`/plugins/aura`: Fix a potential security hole when serving image files. :bug:`4160` For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - :py:meth:`beets.library.Item.destination` now accepts a ``replacements`` argument to be used in favor of the default. - The ``pluginload`` event is now sent after plugin types and queries are available, not before. - A new plugin event, ``album_removed``, is called when an album is removed from the library (even when its file is not deleted from disk). Here are some notes for packagers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - As noted above, the minimum Python version is now 3.6. - We fixed a flaky test, named ``test_album_art`` in the ``test_zero.py`` file, that some distributions had disabled. Disabling this test should no longer be necessary. :bug:`4037` :bug:`4038` - This version of beets no longer depends on the six_ library. :bug:`4030` - The ``gmusic`` plugin was removed since Google Play Music has been shut down. Thus, the optional dependency on ``gmusicapi`` does not exist anymore. :bug:`4089` 1.5.0 (August 19, 2021) ----------------------- This long overdue release of beets includes far too many exciting and useful features than could ever be satisfactorily enumerated. As a technical detail, it also introduces two new external libraries: MediaFile_ and Confuse_ used to be part of beets but are now reusable dependencies---packagers, please take note. Finally, this is the last version of beets where we intend to support Python 2.x and 3.5; future releases will soon require Python 3.6. One non-technical change is that we moved our official ``#beets`` home on IRC from freenode to Libera.Chat_. .. _libera.chat: https://libera.chat/ Major new features ~~~~~~~~~~~~~~~~~~ - Fields in queries now fall back to an item's album and check its fields too. Notably, this allows querying items by an album's attribute: in other words, ``beet list foo:bar`` will not only find tracks with the ``foo`` attribute; it will also find tracks *on albums* that have the ``foo`` attribute. This may be particularly useful in the :ref:`path-format-config`, which matches individual items to decide which path to use. Thanks to :user:`FichteFoll`. :bug:`2797` :bug:`2988` - A new :ref:`reflink` config option instructs the importer to create fast, copy-on-write file clones on filesystems that support them. Thanks to :user:`rubdos`. - A new :doc:`/plugins/unimported` lets you find untracked files in your library directory. - The :doc:`/plugins/aura` has arrived! Try out the future of remote music library access today. - We now fetch information about works_ from MusicBrainz. MusicBrainz matches provide the fields ``work`` (the title), ``mb_workid`` (the MBID), and ``work_disambig`` (the disambiguation string). Thanks to :user:`dosoe`. :bug:`2580` :bug:`3272` - A new :doc:`/plugins/parentwork` gets information about the original work, which is useful for classical music. Thanks to :user:`dosoe`. :bug:`2580` :bug:`3279` - :doc:`/plugins/bpd`: BPD now supports most of the features of version 0.16 of the MPD protocol. This is enough to get it talking to more complicated clients like ncmpcpp, but there are still some incompatibilities, largely due to MPD commands we don't support yet. (Let us know if you find an MPD client that doesn't get along with BPD!) :bug:`3214` :bug:`800` - A new :doc:`/plugins/deezer` can autotag tracks and albums using the Deezer_ database. Thanks to :user:`rhlahuja`. :bug:`3355` - A new :doc:`/plugins/bareasc` provides a new query type: "bare ASCII" queries that ignore accented characters, treating them as though they were plain ASCII characters. Use the ``#`` prefix with :ref:`list-cmd` or other commands. :bug:`3882` - :doc:`/plugins/fetchart`: The plugin can now get album art from last.fm_. :bug:`3530` - :doc:`/plugins/web`: The API now supports the HTTP ``DELETE`` and ``PATCH`` methods for modifying items. They are disabled by default; set ``readonly: no`` in your configuration file to enable modification via the API. :bug:`3870` Other new things ~~~~~~~~~~~~~~~~ - ``beet remove`` now also allows interactive selection of items from the query, similar to ``beet modify``. - Enable HTTPS for MusicBrainz by default and add configuration option :conf:`plugins.musicbrainz:https` for custom servers. See :ref:`musicbrainz-config` for more details. - :doc:`/plugins/mpdstats`: Add a new ``strip_path`` option to help build the right local path from MPD information. - :doc:`/plugins/convert`: Conversion can now parallelize conversion jobs on Python 3. - :doc:`/plugins/lastgenre`: Add a new ``title_case`` config option to make title-case formatting optional. - There's a new message when running ``beet config`` when there's no available configuration file. :bug:`3779` - When importing a duplicate album, the prompt now says "keep all" instead of "keep both" to reflect that there may be more than two albums involved. :bug:`3569` - :doc:`/plugins/chroma`: The plugin now updates file metadata after generating fingerprints through the ``submit`` command. - :doc:`/plugins/lastgenre`: Added more heavy metal genres to the built-in genre filter lists. - A new :doc:`/plugins/subsonicplaylist` can import playlists from a Subsonic server. - :doc:`/plugins/subsonicupdate`: The plugin now automatically chooses between token- and password-based authentication based on the server version. - A new :conf:`plugins.musicbrainz:extra_tags` configuration option lets you use more metadata in MusicBrainz queries to further narrow the search. - A new :doc:`/plugins/fish` adds `Fish shell`_ tab autocompletion to beets. - :doc:`plugins/fetchart` and :doc:`plugins/embedart`: Added a new ``quality`` option that controls the quality of the image output when the image is resized. - :doc:`plugins/keyfinder`: Added support for keyfinder-cli_. Thanks to :user:`BrainDamage`. - :doc:`plugins/fetchart`: Added a new ``high_resolution`` config option to allow downloading of higher resolution iTunes artwork (at the expense of file size). :bug:`3391` - :doc:`plugins/discogs`: The plugin applies two new fields: ``discogs_labelid`` and ``discogs_artistid``. :bug:`3413` - :doc:`/plugins/export`: Added a new ``-f`` (``--format``) flag, which can export your data as JSON, JSON lines, CSV, or XML. Thanks to :user:`austinmm`. :bug:`3402` - :doc:`/plugins/convert`: Added a new ``-l`` (``--link``) flag and ``link`` option as well as the ``-H`` (``--hardlink``) flag and ``hardlink`` option, which symlink or hardlink files that do not need to be converted (instead of copying them). :bug:`2324` - :doc:`/plugins/replaygain`: The plugin now supports a ``per_disc`` option that enables calculation of album ReplayGain on disc level instead of album level. Thanks to :user:`samuelnilsson`. :bug:`293` - :doc:`/plugins/replaygain`: The new ``ffmpeg`` ReplayGain backend supports ``R128_`` tags. :bug:`3056` - :doc:`plugins/replaygain`: A new ``r128_targetlevel`` configuration option defines the reference volume for files using ``R128_`` tags. ``targetlevel`` only configures the reference volume for ``REPLAYGAIN_`` files. :bug:`3065` - :doc:`/plugins/discogs`: The plugin now collects the "style" field. Thanks to :user:`thedevilisinthedetails`. :bug:`2579` :bug:`3251` - :doc:`/plugins/absubmit`: By default, the plugin now avoids re-analyzing files that already have AcousticBrainz data. There are new ``force`` and ``pretend`` options to help control this new behavior. Thanks to :user:`SusannaMaria`. :bug:`3318` - :doc:`/plugins/discogs`: The plugin now also gets genre information and a new ``discogs_albumid`` field from the Discogs API. Thanks to :user:`thedevilisinthedetails`. :bug:`465` :bug:`3322` - :doc:`/plugins/acousticbrainz`: The plugin now fetches two more additional fields: ``moods_mirex`` and ``timbre``. Thanks to :user:`malcops`. :bug:`2860` - :doc:`/plugins/playlist` and :doc:`/plugins/smartplaylist`: A new ``forward_slash`` config option facilitates compatibility with MPD on Windows. Thanks to :user:`MartyLake`. :bug:`3331` :bug:`3334` - The ``data_source`` field, which indicates which metadata source was used during an autotagging import, is now also applied as an album-level flexible attribute. :bug:`3350` :bug:`1693` - :doc:`/plugins/beatport`: The plugin now gets the musical key, BPM, and genre for each track. :bug:`2080` - A new :doc:`/plugins/bpsync` can synchronize metadata changes from the Beatport database (like the existing :doc:`/plugins/mbsync` for MusicBrainz). - :doc:`/plugins/hook`: The plugin now treats non-zero exit codes as errors. :bug:`3409` - :doc:`/plugins/subsonicupdate`: A new ``url`` configuration replaces the older (and now deprecated) separate ``host``, ``port``, and ``contextpath`` config options. As a consequence, the plugin can now talk to Subsonic over HTTPS. Thanks to :user:`jef`. :bug:`3449` - :doc:`/plugins/discogs`: The new :conf:`plugins.discogs:index_tracks` option enables incorporation of work names and intra-work divisions into imported track titles. Thanks to :user:`cole-miller`. :bug:`3459` - :doc:`/plugins/web`: The query API now interprets backslashes as path separators to support path queries. Thanks to :user:`nmeum`. :bug:`3567` - ``beet import`` now handles tar archives with bzip2 or gzip compression. :bug:`3606` - ``beet import`` *also* now handles 7z archives, via the py7zr_ library. Thanks to :user:`arogl`. :bug:`3906` - :doc:`/plugins/plexupdate`: Added an option to use a secure connection to Plex server, and to ignore certificate validation errors if necessary. :bug:`2871` - :doc:`/plugins/convert`: A new ``delete_originals`` configuration option can delete the source files after conversion during import. Thanks to :user:`logan-arens`. :bug:`2947` - There is a new ``--plugins`` (or ``-p``) CLI flag to specify a list of plugins to load. - A new :conf:`plugins.musicbrainz:genres` option fetches genre information from MusicBrainz. This functionality depends on functionality that is currently unreleased in the python-musicbrainzngs_ library: see PR `#266 <https://github.com/alastair/python-musicbrainzngs/pull/266>`_. Thanks to :user:`aereaux`. - :doc:`/plugins/replaygain`: Analysis now happens in parallel using the ``command`` and ``ffmpeg`` backends. :bug:`3478` - :doc:`plugins/replaygain`: The bs1770gain backend is removed. Thanks to :user:`SamuelCook`. - Added ``trackdisambig`` which stores the recording disambiguation from MusicBrainz for each track. :bug:`1904` - :doc:`plugins/fetchart`: The new ``max_filesize`` configuration sets a maximum target image file size. - :doc:`/plugins/badfiles`: Checkers can now run during import with the ``check_on_import`` config option. - :doc:`/plugins/export`: The plugin is now much faster when using the ``--include-keys`` option is used. Thanks to :user:`ssssam`. - The importer's :ref:`set_fields` option now saves all updated fields to on-disk metadata. :bug:`3925` :bug:`3927` - We now fetch ISRC identifiers from MusicBrainz. Thanks to :user:`aereaux`. - :doc:`/plugins/metasync`: The plugin now also fetches the "Date Added" field from iTunes databases and stores it in the ``itunes_dateadded`` field. Thanks to :user:`sandersantema`. - :doc:`/plugins/lyrics`: Added a new Tekstowo.pl lyrics provider. Thanks to various people for the implementation and for reporting issues with the initial version. :bug:`3344` :bug:`3904` :bug:`3905` :bug:`3994` - ``beet update`` will now confirm that the user still wants to update if their library folder cannot be found, preventing the user from accidentally wiping out their beets database. Thanks to user: ``logan-arens``. :bug:`1934` Fixes ~~~~~ - Adapt to breaking changes in Python's ``ast`` module in Python 3.8. - :doc:`/plugins/beatport`: Fix the assignment of the ``genre`` field, and rename ``musical_key`` to ``initial_key``. :bug:`3387` - :doc:`/plugins/lyrics`: Fixed the Musixmatch backend for lyrics pages when lyrics are divided into multiple elements on the webpage, and when the lyrics are missing. - :doc:`/plugins/web`: Allow use of the backslash character in regex queries. :bug:`3867` - :doc:`/plugins/web`: Fixed a small bug that caused the album art path to be redacted even when ``include_paths`` option is set. :bug:`3866` - :doc:`/plugins/discogs`: Fixed a bug with the :conf:`plugins.discogs:index_tracks` option that sometimes caused the index to be discarded. Also, remove the extra semicolon that was added when there is no index track. - :doc:`/plugins/subsonicupdate`: The API client was using the ``POST`` method rather the ``GET`` method. Also includes better exception handling, response parsing, and tests. - :doc:`/plugins/the`: Fixed incorrect regex for "the" that matched any 3-letter combination of the letters t, h, e. :bug:`3701` - :doc:`/plugins/fetchart`: Fixed a bug that caused the plugin to not take environment variables, such as proxy servers, into account when making requests. :bug:`3450` - :doc:`/plugins/fetchart`: Temporary files for fetched album art that fail validation are now removed. - :doc:`/plugins/inline`: In function-style field definitions that refer to flexible attributes, values could stick around from one function invocation to the next. This meant that, when displaying a list of objects, later objects could seem to reuse values from earlier objects when they were missing a value for a given field. These values are now properly undefined. :bug:`2406` - :doc:`/plugins/bpd`: Seeking by fractions of a second now works as intended, fixing crashes in MPD clients like mpDris2 on seek. The ``playlistid`` command now works properly in its zero-argument form. :bug:`3214` - :doc:`/plugins/replaygain`: Fix a Python 3 incompatibility in the Python Audio Tools backend. :bug:`3305` - :doc:`/plugins/importadded`: Fixed a crash that occurred when the ``after_write`` signal was emitted. :bug:`3301` - :doc:`plugins/replaygain`: Fix the storage format for R128 gain tags. :bug:`3311` :bug:`3314` - :doc:`/plugins/discogs`: Fixed a crash that occurred when the master URI isn't set in the API response. :bug:`2965` :bug:`3239` - :doc:`/plugins/spotify`: Fix handling of year-only release dates returned by the Spotify albums API. Thanks to :user:`rhlahuja`. :bug:`3343` - Fixed a bug that caused the UI to display incorrect track numbers for tracks with index 0 when the ``per_disc_numbering`` option was set. :bug:`3346` - ``none_rec_action`` does not import automatically when ``timid`` is enabled. Thanks to :user:`RollingStar`. :bug:`3242` - Fix a bug that caused a crash when tagging items with the beatport plugin. :bug:`3374` - ``beet import`` now logs which files are ignored when in debug mode. :bug:`3764` - :doc:`/plugins/bpd`: Fix the transition to next track when in consume mode. Thanks to :user:`aereaux`. :bug:`3437` - :doc:`/plugins/lyrics`: Fix a corner-case with Genius lowercase artist names :bug:`3446` - :doc:`/plugins/parentwork`: Don't save tracks when nothing has changed. :bug:`3492` - Added a warning when configuration files defined in the ``include`` directive of the configuration file fail to be imported. :bug:`3498` - Added normalization to integer values in the database, which should avoid problems where fields like ``bpm`` would sometimes store non-integer values. :bug:`762` :bug:`3507` :bug:`3508` - Fix a crash when querying for null values. :bug:`3516` :bug:`3517` - :doc:`/plugins/lyrics`: Tolerate a missing lyrics div in the Genius scraper. Thanks to :user:`thejli21`. :bug:`3535` :bug:`3554` - :doc:`/plugins/lyrics`: Use the artist sort name to search for lyrics, which can help find matches when the artist name has special characters. Thanks to :user:`hashhar`. :bug:`3340` :bug:`3558` - :doc:`/plugins/replaygain`: Trying to calculate volume gain for an album consisting of some formats using ``ReplayGain`` and some using ``R128`` will no longer crash; instead it is skipped and and a message is logged. The log message has also been rewritten for to improve clarity. Thanks to :user:`autrimpo`. :bug:`3533` - :doc:`/plugins/lyrics`: Adapt the Genius backend to changes in markup to reduce the scraping failure rate. :bug:`3535` :bug:`3594` - :doc:`/plugins/lyrics`: Fix a crash when writing ReST files for a query without results or fetched lyrics. :bug:`2805` - :doc:`/plugins/fetchart`: Attempt to fetch pre-resized thumbnails from Cover Art Archive if the ``maxwidth`` option matches one of the sizes supported by the Cover Art Archive API. Thanks to :user:`trolley`. :bug:`3637` - :doc:`/plugins/ipfs`: Fix Python 3 compatibility. Thanks to :user:`musoke`. :bug:`2554` - Fix a bug that caused metadata starting with something resembling a drive letter to be incorrectly split into an extra directory after the colon. :bug:`3685` - :doc:`/plugins/mpdstats`: Don't record a skip when stopping MPD, as MPD keeps the current track in the queue. Thanks to :user:`aereaux`. :bug:`3722` - String-typed fields are now normalized to string values, avoiding an occasional crash when using both the :doc:`/plugins/fetchart` and the :doc:`/plugins/discogs` together. :bug:`3773` :bug:`3774` - Fix a bug causing PIL to generate poor quality JPEGs when resizing artwork. :bug:`3743` - :doc:`plugins/keyfinder`: Catch output from ``keyfinder-cli`` that is missing key. :bug:`2242` - :doc:`plugins/replaygain`: Disable parallel analysis on import by default. :bug:`3819` - :doc:`/plugins/mpdstats`: Fix Python 2/3 compatibility :bug:`3798` - :doc:`/plugins/discogs`: Replace the deprecated official ``discogs-client`` library with the community supported python3-discogs-client_ library. :bug:`3608` - :doc:`/plugins/chroma`: Fixed submitting AcoustID information for tracks that already have a fingerprint. :bug:`3834` - Allow equals within the value part of the ``--set`` option to the ``beet import`` command. :bug:`2984` - Duplicates can now generate checksums. Thanks :user:`wisp3rwind` for the pointer to how to solve. Thanks to :user:`arogl`. :bug:`2873` - Templates that use ``%ifdef`` now produce the expected behavior when used in conjunction with non-string fields from the :doc:`/plugins/types`. :bug:`3852` - :doc:`/plugins/lyrics`: Fix crashes when a website could not be retrieved, affecting at least the Genius source. :bug:`3970` - :doc:`/plugins/duplicates`: Fix a crash when running the ``dup`` command with a query that returns no results. :bug:`3943` - :doc:`/plugins/beatport`: Fix the default assignment of the musical key. :bug:`3377` - :doc:`/plugins/lyrics`: Improved searching on the Genius backend when the artist contains special characters. :bug:`3634` - :doc:`/plugins/parentwork`: Also get the composition date of the parent work, instead of just the child work. Thanks to :user:`aereaux`. :bug:`3650` - :doc:`/plugins/lyrics`: Fix a bug in the heuristic for detecting valid lyrics in the Google source. :bug:`2969` - :doc:`/plugins/thumbnails`: Fix a crash due to an incorrect string type on Python 3. :bug:`3360` - :doc:`/plugins/fetchart`: The Cover Art Archive source now iterates over all front images instead of blindly selecting the first one. - :doc:`/plugins/lyrics`: Removed the LyricWiki source (the site shut down on 21/09/2020). - :doc:`/plugins/subsonicupdate`: The plugin is now functional again. A new ``auth`` configuration option is required in the configuration to specify the flavor of authentication to use. :bug:`4002` For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - MediaFile_ has been split into a standalone project. Where you used to do ``from beets import mediafile``, now just do ``import mediafile``. Beets re-exports MediaFile at the old location for backwards-compatibility, but a deprecation warning is raised if you do this since we might drop this wrapper in a future release. - Similarly, we've replaced beets' configuration library (previously called Confit) with a standalone version called Confuse_. Where you used to do ``from beets.util import confit``, now just do ``import confuse``. The code is almost identical apart from the name change. Again, we'll re-export at the old location (with a deprecation warning) for backwards compatibility, but we might stop doing this in a future release. - ``beets.util.command_output`` now returns a named tuple containing both the standard output and the standard error data instead of just stdout alone. Client code will need to access the ``stdout`` attribute on the return value. Thanks to :user:`zsinskri`. :bug:`3329` - There were sporadic failures in ``test.test_player``. Hopefully these are fixed. If they resurface, please reopen the relevant issue. :bug:`3309` :bug:`3330` - The ``beets.plugins.MetadataSourcePlugin`` base class has been added to simplify development of plugins which query album, track, and search APIs to provide metadata matches for the importer. Refer to the :doc:`/plugins/spotify` and the :doc:`/plugins/deezer` for examples of using this template class. :bug:`3355` - Accessing fields on an ``Item`` now falls back to the album's attributes. So, for example, ``item.foo`` will first look for a field ``foo`` on ``item`` and, if it doesn't exist, next tries looking for a field named ``foo`` on the album that contains ``item``. If you specifically want to access an item's attributes, use ``Item.get(key, with_album=False)``. :bug:`2988` - ``Item.keys`` also has a ``with_album`` argument now, defaulting to ``True``. - A ``revision`` attribute has been added to ``Database``. It is increased on every transaction that mutates it. :bug:`2988` - The classes ``AlbumInfo`` and ``TrackInfo`` now convey arbitrary attributes instead of a fixed, built-in set of field names (which was important to address :bug:`1547`). Thanks to :user:`dosoe`. - Two new events, ``mb_album_extract`` and ``mb_track_extract``, let plugins add new fields based on MusicBrainz data. Thanks to :user:`dosoe`. For packagers ~~~~~~~~~~~~~ - Beets' library for manipulating media file metadata has now been split to a standalone project called MediaFile_, released as :pypi:`mediafile`. Beets now depends on this new package. Beets now depends on Mutagen transitively through MediaFile rather than directly, except in the case of one of beets' plugins (in particular, the :doc:`/plugins/scrub`). - Beets' library for configuration has been split into a standalone project called Confuse_, released as :pypi:`confuse`. Beets now depends on this package. Confuse has existed separately for some time and is used by unrelated projects, but until now we've been bundling a copy within beets. - We attempted to fix an unreliable test, so a patch to skip-broken-test_ or repairing_ may no longer be necessary. - This version drops support for Python 3.4. - We have removed an optional dependency on bs1770gain. .. _confuse: https://github.com/beetbox/confuse .. _deezer: https://www.deezer.com/en/ .. _fish shell: https://fishshell.com/ .. _keyfinder-cli: https://github.com/EvanPurkhiser/keyfinder-cli .. _last.fm: https://www.last.fm/ .. _mediafile: https://github.com/beetbox/mediafile .. _py7zr: https://pypi.org/project/py7zr/ .. _python3-discogs-client: https://github.com/joalla/discogs_client .. _repairing: https://build.opensuse.org/package/view_file/openSUSE:Factory/beets/fix_test_command_line_option_relative_to_working_dir.diff?expand=1 .. _skip-broken-test: https://sources.debian.org/src/beets/1.4.7-2/debian/patches/skip-broken-test/ .. _works: https://musicbrainz.org/doc/Work 1.4.9 (May 30, 2019) -------------------- This small update is part of our attempt to release new versions more often! There are a few important fixes, and we're clearing the deck for a change to beets' dependencies in the next version. The new feature is ~~~~~~~~~~~~~~~~~~ - You can use the NO_COLOR_ environment variable to disable terminal colors. :bug:`3273` There are some fixes in this release ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Fix a regression in the last release that made the image resizer fail to detect older versions of ImageMagick. :bug:`3269` - ``/plugins/gmusic``: The ``oauth_file`` config option now supports more flexible path values, including ``~`` for the home directory. :bug:`3270` - ``/plugins/gmusic``: Fix a crash when using version 12.0.0 or later of the ``gmusicapi`` module. :bug:`3270` - Fix an incompatibility with Python 3.8's AST changes. :bug:`3278` Here's a note for packagers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ``pathlib`` is now an optional test dependency on Python 3.4+, removing the need for `Debian pathlib patch`_ :bug:`3275` .. _debian pathlib patch: https://sources.debian.org/src/beets/1.4.7-2/debian/patches/pathlib-is-stdlib/ .. _no_color: https://no-color.org 1.4.8 (May 16, 2019) -------------------- This release is far too long in coming, but it's a good one. There is the usual torrent of new features and a ridiculously long line of fixes, but there are also some crucial maintenance changes. We officially support Python 3.7 and 3.8, and some performance optimizations can (anecdotally) make listing your library more than three times faster than in the previous version. The new core features are ~~~~~~~~~~~~~~~~~~~~~~~~~ - A new :ref:`config-aunique` configuration option allows setting default options for the :ref:`aunique` template function. - The ``albumdisambig`` field no longer includes the MusicBrainz release group disambiguation comment. A new ``releasegroupdisambig`` field has been added. :bug:`3024` - The :ref:`modify-cmd` command now allows resetting fixed attributes. For example, ``beet modify -a artist:beatles artpath!`` resets ``artpath`` attribute from matching albums back to the default value. :bug:`2497` - A new importer option, :ref:`ignore_data_tracks`, lets you skip audio tracks contained in data files. :bug:`3021` There are some new plugins ~~~~~~~~~~~~~~~~~~~~~~~~~~ - The :doc:`/plugins/playlist` can query the beets library using M3U playlists. Thanks to :user:`Holzhaus` and :user:`Xenopathic`. :bug:`123` :bug:`3145` - The :doc:`/plugins/loadext` allows loading of SQLite extensions, primarily for use with the ICU SQLite extension for internationalization. :bug:`3160` :bug:`3226` - The :doc:`/plugins/subsonicupdate` can automatically update your Subsonic library. Thanks to :user:`maffo999`. :bug:`3001` And many improvements to existing plugins ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/lastgenre`: Added option ``-A`` to match individual tracks and singletons. :bug:`3220` :bug:`3219` - :doc:`/plugins/play`: The plugin can now emit a UTF-8 BOM, fixing some issues with foobar2000 and Winamp. Thanks to :user:`mz2212`. :bug:`2944` - ``/plugins/gmusic``: - Add a new option to automatically upload to Google Play Music library on track import. Thanks to :user:`shuaiscott`. - Add new options for Google Play Music authentication. Thanks to :user:`thetarkus`. :bug:`3002` - :doc:`/plugins/replaygain`: ``albumpeak`` on large collections is calculated as the average, not the maximum. :bug:`3008` :bug:`3009` - :doc:`/plugins/chroma`: - Now optionally has a bias toward looking up more relevant releases according to the :ref:`preferred` configuration options. Thanks to :user:`archer4499`. :bug:`3017` - Fingerprint values are now properly stored as strings, which prevents strange repeated output when running ``beet write``. Thanks to :user:`Holzhaus`. :bug:`3097` :bug:`2942` - :doc:`/plugins/convert`: The plugin now has an ``id3v23`` option that allows you to override the global ``id3v23`` option. Thanks to :user:`Holzhaus`. :bug:`3104` - :doc:`/plugins/spotify`: - The plugin now uses OAuth for authentication to the Spotify API. Thanks to :user:`rhlahuja`. :bug:`2694` :bug:`3123` - The plugin now works as an import metadata provider: you can match tracks and albums using the Spotify database. Thanks to :user:`rhlahuja`. :bug:`3123` - :doc:`/plugins/ipfs`: The plugin now supports a ``nocopy`` option which passes that flag to ipfs. Thanks to :user:`wildthyme`. - :doc:`/plugins/discogs`: The plugin now has rate limiting for the Discogs API. :bug:`3081` - :doc:`/plugins/mpdstats`, :doc:`/plugins/mpdupdate`: These plugins now use the ``MPD_PORT`` environment variable if no port is specified in the configuration file. :bug:`3223` - :doc:`/plugins/bpd`: - MPD protocol commands ``consume`` and ``single`` are now supported along with updated semantics for ``repeat`` and ``previous`` and new fields for ``status``. The bpd server now understands and ignores some additional commands. :bug:`3200` :bug:`800` - MPD protocol command ``idle`` is now supported, allowing the MPD version to be bumped to 0.14. :bug:`3205` :bug:`800` - MPD protocol command ``decoders`` is now supported. :bug:`3222` - The plugin now uses the main beets logging system. The special-purpose ``--debug`` flag has been removed. Thanks to :user:`arcresu`. :bug:`3196` - :doc:`/plugins/mbsync`: The plugin no longer queries MusicBrainz when either the ``mb_albumid`` or ``mb_trackid`` field is invalid. See also the discussion on `Google Groups`_ Thanks to :user:`arogl`. - :doc:`/plugins/export`: The plugin now also exports ``path`` field if the user explicitly specifies it with ``-i`` parameter. This only works when exporting library fields. :bug:`3084` - :doc:`/plugins/acousticbrainz`: The plugin now declares types for all its fields, which enables easier querying and avoids a problem where very small numbers would be stored as strings. Thanks to :user:`rain0r`. :bug:`2790` :bug:`3238` .. _google groups: https://groups.google.com/forum/#!searchin/beets-users/mbsync|sort:date/beets-users/iwCF6bNdh9A/i1xl4Gx8BQAJ Some improvements have been focused on improving beets' performance ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Querying the library is now faster: - We only convert fields that need to be displayed. Thanks to :user:`pprkut`. :bug:`3089` - We now compile templates once and reuse them instead of recompiling them to print out each matching object. Thanks to :user:`SimonPersson`. :bug:`3258` - Querying the library for items is now faster, for all queries that do not need to access album level properties. This was implemented by lazily fetching the album only when needed. Thanks to :user:`SimonPersson`. :bug:`3260` - :doc:`/plugins/absubmit`, :doc:`/plugins/badfiles`: Analysis now works in parallel (on Python 3 only). Thanks to :user:`bemeurer`. :bug:`2442` :bug:`3003` - :doc:`/plugins/mpdstats`: Use the ``currentsong`` MPD command instead of ``playlist`` to get the current song, improving performance when the playlist is long. Thanks to :user:`ray66`. :bug:`3207` :bug:`2752` Several improvements are related to usability ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The disambiguation string for identifying albums in the importer now shows the catalog number. Thanks to :user:`8h2a`. :bug:`2951` - Added whitespace padding to missing tracks dialog to improve readability. Thanks to :user:`jams2`. :bug:`2962` - The :ref:`move-cmd` command now lists the number of items already in-place. Thanks to :user:`RollingStar`. :bug:`3117` - Modify selection can now be applied early without selecting every item. :bug:`3083` - Beets now emits more useful messages during startup if SQLite returns an error. The SQLite error message is now attached to the beets message. :bug:`3005` - Fixed a confusing typo when the :doc:`/plugins/convert` plugin copies the art covers. :bug:`3063` Many fixes have been focused on issues where beets would previously crash ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Avoid a crash when archive extraction fails during import. :bug:`3041` - Missing album art file during an update no longer causes a fatal exception (instead, an error is logged and the missing file path is removed from the library). :bug:`3030` - When updating the database, beets no longer tries to move album art twice. :bug:`3189` - Fix an unhandled exception when pruning empty directories. :bug:`1996` :bug:`3209` - :doc:`/plugins/fetchart`: Added network connection error handling to backends so that beets won't crash if a request fails. Thanks to :user:`Holzhaus`. :bug:`1579` - :doc:`/plugins/badfiles`: Avoid a crash when the underlying tool emits undecodable output. :bug:`3165` - :doc:`/plugins/beatport`: Avoid a crash when the server produces an error. :bug:`3184` - :doc:`/plugins/bpd`: Fix crashes in the bpd server during exception handling. :bug:`3200` - :doc:`/plugins/bpd`: Fix a crash triggered when certain clients tried to list the albums belonging to a particular artist. :bug:`3007` :bug:`3215` - :doc:`/plugins/replaygain`: Avoid a crash when the ``bs1770gain`` tool emits malformed XML. :bug:`2983` :bug:`3247` There are many fixes related to compatibility with our dependencies including addressing changes interfaces: - On Python 2, pin the :pypi:`jellyfish` requirement to version 0.6.0 for compatibility. - Fix compatibility with Python 3.7 and its change to a name in the :stdlib:`re` module. :bug:`2978` - Fix several uses of deprecated standard-library features on Python 3.7. Thanks to :user:`arcresu`. :bug:`3197` - Fix compatibility with pre-release versions of Python 3.8. :bug:`3201` :bug:`3202` - :doc:`/plugins/web`: Fix an error when using more recent versions of Flask with CORS enabled. Thanks to :user:`rveachkc`. :bug:`2979`: :bug:`2980` - Avoid some deprecation warnings with certain versions of the MusicBrainz library. Thanks to :user:`zhelezov`. :bug:`2826` :bug:`3092` - Restore iTunes Store album art source, and remove the dependency on :pypi:`python-itunes`, which had gone unmaintained and was not Python-3-compatible. Thanks to :user:`ocelma` for creating :pypi:`python-itunes` in the first place. Thanks to :user:`nathdwek`. :bug:`2371` :bug:`2551` :bug:`2718` - :doc:`/plugins/lastgenre`, :doc:`/plugins/edit`: Avoid a deprecation warnings from the :pypi:`PyYAML` library by switching to the safe loader. Thanks to :user:`translit` and :user:`sbraz`. :bug:`3192` :bug:`3225` - Fix a problem when resizing images with :pypi:`PIL`/:pypi:`pillow` on Python 3. Thanks to :user:`architek`. :bug:`2504` :bug:`3029` And there are many other fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - R128 normalization tags are now properly deleted from files when the values are missing. Thanks to :user:`autrimpo`. :bug:`2757` - Display the artist credit when matching albums if the :ref:`artist_credit` configuration option is set. :bug:`2953` - With the :ref:`from_scratch` configuration option set, only writable fields are cleared. Beets now no longer ignores the format your music is saved in. :bug:`2972` - The ``%aunique`` template function now works correctly with the ``-f/--format`` option. :bug:`3043` - Fixed the ordering of items when manually selecting changes while updating tags Thanks to :user:`TaizoSimpson`. :bug:`3501` - The ``%title`` template function now works correctly with apostrophes. Thanks to :user:`GuilhermeHideki`. :bug:`3033` - :doc:`/plugins/lastgenre`: It's now possible to set the ``prefer_specific`` option without also setting ``canonical``. :bug:`2973` - :doc:`/plugins/fetchart`: The plugin now respects the ``ignore`` and ``ignore_hidden`` settings. :bug:`1632` - :doc:`/plugins/hook`: Fix byte string interpolation in hook commands. :bug:`2967` :bug:`3167` - :doc:`/plugins/the`: Log a message when something has changed, not when it hasn't. Thanks to :user:`arcresu`. :bug:`3195` - :doc:`/plugins/lastgenre`: The ``force`` config option now actually works. :bug:`2704` :bug:`3054` - Resizing image files with ImageMagick now avoids problems on systems where there is a ``convert`` command that is *not* ImageMagick's by using the ``magick`` executable when it is available. Thanks to :user:`ababyduck`. :bug:`2093` :bug:`3236` There is one new thing for plugin developers to know about ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - In addition to prefix-based field queries, plugins can now define *named queries* that are not associated with any specific field. For example, the new :doc:`/plugins/playlist` supports queries like ``playlist:name`` although there is no field named ``playlist``. See :ref:`extend-query` for details. And some messages for packagers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Note the changes to the dependencies on :pypi:`jellyfish` and :pypi:`munkres`. - The optional :pypi:`python-itunes` dependency has been removed. - Python versions 3.7 and 3.8 are now supported. 1.4.7 (May 29, 2018) -------------------- This new release includes lots of new features in the importer and the metadata source backends that it uses. We've changed how the beets importer handles non-audio tracks listed in metadata sources like MusicBrainz: - The importer now ignores non-audio tracks (namely, data and video tracks) listed in MusicBrainz. Also, a new option, :ref:`ignore_video_tracks`, lets you return to the old behavior and include these video tracks. :bug:`1210` - A new importer option, :ref:`ignored_media`, can let you skip certain media formats. :bug:`2688` There are other subtle improvements to metadata handling in the importer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - In the MusicBrainz backend, beets now imports the ``musicbrainz_releasetrackid`` field. This is a first step toward :bug:`406`. Thanks to :user:`Rawrmonkeys`. - A new importer configuration option, :ref:`artist_credit`, will tell beets to prefer the artist credit over the artist when autotagging. :bug:`1249` And there are even more new features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/replaygain`: The ``beet replaygain`` command now has ``--force``, ``--write`` and ``--nowrite`` options. :bug:`2778` - A new importer configuration option, :ref:`incremental_skip_later`, lets you avoid recording skipped directories to the list of "processed" directories in :ref:`incremental` mode. This way, you can revisit them later with another import. Thanks to :user:`sekjun9878`. :bug:`2773` - :doc:`/plugins/fetchart`: The configuration options now support finer-grained control via the ``sources`` option. You can now specify the search order for different *matching strategies* within different backends. - :doc:`/plugins/web`: A new ``cors_supports_credentials`` configuration option lets in-browser clients communicate with the server even when it is protected by an authorization mechanism (a proxy with HTTP authentication enabled, for example). - A new :doc:`/plugins/sonosupdate` plugin automatically notifies Sonos controllers to update the music library when the beets library changes. Thanks to :user:`cgtobi`. - :doc:`/plugins/discogs`: The plugin now stores master release IDs into ``mb_releasegroupid``. It also "simulates" track IDs using the release ID and the track list position. Thanks to :user:`dbogdanov`. :bug:`2336` - :doc:`/plugins/discogs`: Fetch the original year from master releases. :bug:`1122` There are lots and lots of fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/replaygain`: Fix a corner-case with the ``bs1770gain`` backend where ReplayGain values were assigned to the wrong files. The plugin now requires version 0.4.6 or later of the ``bs1770gain`` tool. :bug:`2777` - :doc:`/plugins/lyrics`: The plugin no longer crashes in the Genius source when BeautifulSoup is not found. Instead, it just logs a message and disables the source. :bug:`2911` - :doc:`/plugins/lyrics`: Handle network and API errors when communicating with Genius. :bug:`2771` - :doc:`/plugins/lyrics`: The ``lyrics`` command previously wrote ReST files by default, even when you didn't ask for them. This default has been fixed. - :doc:`/plugins/lyrics`: When writing ReST files, the ``lyrics`` command now groups lyrics by the ``albumartist`` field, rather than ``artist``. :bug:`2924` - Plugins can now see updated import task state, such as when rejecting the initial candidates and finding new ones via a manual search. Notably, this means that the importer prompt options that the :doc:`/plugins/edit` provides show up more reliably after doing a secondary import search. :bug:`2441` :bug:`2731` - :doc:`/plugins/importadded`: Fix a crash on non-autotagged imports. Thanks to :user:`m42i`. :bug:`2601` :bug:`1918` - :doc:`/plugins/plexupdate`: The Plex token is now redacted in configuration output. Thanks to :user:`Kovrinic`. :bug:`2804` - Avoid a crash when importing a non-ASCII filename when using an ASCII locale on Unix under Python 3. :bug:`2793` :bug:`2803` - Fix a problem caused by time zone misalignment that could make date queries fail to match certain dates that are near the edges of a range. For example, querying for dates within a certain month would fail to match dates within hours of the end of that month. :bug:`2652` - :doc:`/plugins/convert`: The plugin now runs before other plugin-provided import stages, which addresses an issue with generating ReplayGain data incompatible between the source and target file formats. Thanks to :user:`autrimpo`. :bug:`2814` - :doc:`/plugins/ftintitle`: The ``drop`` config option had no effect; it now does what it says it should do. :bug:`2817` - Importing a release with multiple release events now selects the event based on the order of your :ref:`preferred` countries rather than the order of release events in MusicBrainz. :bug:`2816` - :doc:`/plugins/web`: The time display in the web interface would incorrectly jump at the 30-second mark of every minute. Now, it correctly changes over at zero seconds. :bug:`2822` - :doc:`/plugins/web`: Fetching album art now works (instead of throwing an exception) under Python 3. Additionally, the server will now return a 404 response when the album ID is unknown (instead of throwing an exception and producing a 500 response). :bug:`2823` - :doc:`/plugins/web`: Fix an exception on Python 3 for filenames with non-Latin1 characters. (These characters are now converted to their ASCII equivalents.) :bug:`2815` - Partially fix bash completion for subcommand names that contain hyphens. Thanks to :user:`jhermann`. :bug:`2836` :bug:`2837` - :doc:`/plugins/replaygain`: Really fix album gain calculation using the GStreamer backend. :bug:`2846` - Avoid an error when doing a "no-op" move on non-existent files (i.e., moving a file onto itself). :bug:`2863` - :doc:`/plugins/discogs`: Fix the ``medium`` and ``medium_index`` values, which were occasionally incorrect for releases with two-sided mediums such as vinyl. Also fix the ``medium_total`` value, which now contains total number of tracks on the medium to which a track belongs, not the total number of different mediums present on the release. Thanks to :user:`dbogdanov`. :bug:`2887` - The importer now supports audio files contained in data tracks when they are listed in MusicBrainz: the corresponding audio tracks are now merged into the main track list. Thanks to :user:`jdetrey`. :bug:`1638` - :doc:`/plugins/keyfinder`: Avoid a crash when trying to process unmatched tracks. :bug:`2537` - :doc:`/plugins/mbsync`: Support MusicBrainz recording ID changes, relying on release track IDs instead. Thanks to :user:`jdetrey`. :bug:`1234` - :doc:`/plugins/mbsync`: We can now successfully update albums even when the first track has a missing MusicBrainz recording ID. :bug:`2920` There are a couple of changes for developers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Plugins can now run their import stages *early*, before other plugins. Use the ``early_import_stages`` list instead of plain ``import_stages`` to request this behavior. :bug:`2814` - We again properly send ``albuminfo_received`` and ``trackinfo_received`` in all cases, most notably when using the ``mbsync`` plugin. This was a regression since version 1.4.1. :bug:`2921` 1.4.6 (December 21, 2017) ------------------------- The highlight of this release is "album merging," an oft-requested option in the importer to add new tracks to an existing album you already have in your library. This way, you no longer need to resort to removing the partial album from your library, combining the files manually, and importing again. Here are the larger new features in this release ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - When the importer finds duplicate albums, you can now merge all the tracks---old and new---together and try importing them as a single, combined album. Thanks to :user:`udiboy1209`. :bug:`112` :bug:`2725` - :doc:`/plugins/lyrics`: The plugin can now produce reStructuredText files for beautiful, readable books of lyrics. Thanks to :user:`anarcat`. :bug:`2628` - A new :ref:`from_scratch` configuration option makes the importer remove old metadata before applying new metadata. This new feature complements the :doc:`zero </plugins/zero>` and :doc:`scrub </plugins/scrub>` plugins but is slightly different: beets clears out all the old tags it knows about and only keeps the new data it gets from the remote metadata source. Thanks to :user:`tummychow`. :bug:`934` :bug:`2755` There are also somewhat littler, but still great, new features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/convert`: A new ``no_convert`` option lets you skip transcoding items matching a query. Instead, the files are just copied as-is. Thanks to :user:`Stunner`. :bug:`2732` :bug:`2751` - :doc:`/plugins/fetchart`: A new quiet switch that only prints out messages when album art is missing. Thanks to :user:`euri10`. :bug:`2683` - :doc:`/plugins/mbcollection`: You can configure a custom MusicBrainz collection via the new ``collection`` configuration option. :bug:`2685` - :doc:`/plugins/mbcollection`: The collection update command can now remove albums from collections that are longer in the beets library. - :doc:`/plugins/fetchart`: The ``clearart`` command now asks for confirmation before touching your files. Thanks to :user:`konman2`. :bug:`2708` :bug:`2427` - :doc:`/plugins/mpdstats`: The plugin now correctly updates song statistics when MPD switches from a song to a stream and when it plays the same song multiple times consecutively. :bug:`2707` - :doc:`/plugins/acousticbrainz`: The plugin can now be configured to write only a specific list of tags. Thanks to :user:`woparry`. There are lots and lots of bug fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/hook`: Fixed a problem where accessing non-string properties of ``item`` or ``album`` (e.g., ``item.track``) would cause a crash. Thanks to :user:`broddo`. :bug:`2740` - :doc:`/plugins/play`: When ``relative_to`` is set, the plugin correctly emits relative paths even when querying for albums rather than tracks. Thanks to :user:`j000`. :bug:`2702` - We suppress a spurious Python warning about a ``BrokenPipeError`` being ignored. This was an issue when using beets in simple shell scripts. Thanks to :user:`Azphreal`. :bug:`2622` :bug:`2631` - :doc:`/plugins/replaygain`: Fix a regression in the previous release related to the new R128 tags. :bug:`2615` :bug:`2623` - :doc:`/plugins/lyrics`: The MusixMatch backend now detects and warns when the server has blocked the client. Thanks to :user:`anarcat`. :bug:`2634` :bug:`2632` - :doc:`/plugins/importfeeds`: Fix an error on Python 3 in certain configurations. Thanks to :user:`djl`. :bug:`2467` :bug:`2658` - :doc:`/plugins/edit`: Fix a bug when editing items during a re-import with the ``-L`` flag. Previously, diffs against against unrelated items could be shown or beets could crash. :bug:`2659` - :doc:`/plugins/kodiupdate`: Fix the server URL and add better error reporting. :bug:`2662` - Fixed a problem where "no-op" modifications would reset files' mtimes, resulting in unnecessary writes. This most prominently affected the :doc:`/plugins/edit` when saving the text file without making changes to some music. :bug:`2667` - :doc:`/plugins/chroma`: Fix a crash when running the ``submit`` command on Python 3 on Windows with non-ASCII filenames. :bug:`2671` - :doc:`/plugins/absubmit`: Fix an occasional crash on Python 3 when the AB analysis tool produced non-ASCII metadata. :bug:`2673` - :doc:`/plugins/duplicates`: Use the default tiebreak for items or albums when the configuration only specifies a tiebreak for the other kind of entity. Thanks to :user:`cgevans`. :bug:`2758` - :doc:`/plugins/duplicates`: Fix the ``--key`` command line option, which was ignored. - :doc:`/plugins/replaygain`: Fix album ReplayGain calculation with the GStreamer backend. :bug:`2636` - :doc:`/plugins/scrub`: Handle errors when manipulating files using newer versions of Mutagen. :bug:`2716` - :doc:`/plugins/fetchart`: The plugin no longer gets skipped during import when the "Edit Candidates" option is used from the :doc:`/plugins/edit`. :bug:`2734` - Fix a crash when numeric metadata fields contain just a minus or plus sign with no following numbers. Thanks to :user:`eigengrau`. :bug:`2741` - :doc:`/plugins/fromfilename`: Recognize file names that contain *only* a track number, such as ``01.mp3``. Also, the plugin now allows underscores as a separator between fields. Thanks to :user:`Vrihub`. :bug:`2738` :bug:`2759` - Fixed an issue where images would be resized according to their longest edge, instead of their width, when using the ``maxwidth`` config option in the :doc:`/plugins/fetchart` and :doc:`/plugins/embedart`. Thanks to :user:`sekjun9878`. :bug:`2729` There are some changes for developers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - "Fixed fields" in Album and Item objects are now more strict about translating missing values into type-specific null-like values. This should help in cases where a string field is unexpectedly ``None`` sometimes instead of just showing up as an empty string. :bug:`2605` - Refactored the move functions the ``beets.library`` module and the ``manipulate_files`` function in ``beets.importer`` to use a single parameter describing the file operation instead of multiple Boolean flags. There is a new numerated type describing how to move, copy, or link files. :bug:`2682` 1.4.5 (June 20, 2017) --------------------- Version 1.4.5 adds some oft-requested features. When you're importing files, you can now manually set fields on the new music. Date queries have gotten much more powerful: you can write precise queries down to the second, and we now have *relative* queries like ``-1w``, which means *one week ago*. Here are the new features ~~~~~~~~~~~~~~~~~~~~~~~~~ - You can now set fields to certain values during :ref:`import-cmd`, using either a ``--set field=value`` command-line flag or a new :ref:`set_fields` configuration option under the ``importer`` section. Thanks to :user:`bartkl`. :bug:`1881` :bug:`2581` - :ref:`Date queries <datequery>` can now include times, so you can filter your music down to the second. Thanks to :user:`discopatrick`. :bug:`2506` :bug:`2528` - :ref:`Date queries <datequery>` can also be *relative*. You can say ``added:-1w..`` to match music added in the last week, for example. Thanks to :user:`euri10`. :bug:`2598` - A new ``/plugins/gmusic`` lets you interact with your Google Play Music library. Thanks to :user:`tigranl`. :bug:`2553` :bug:`2586` - :doc:`/plugins/replaygain`: We now keep R128 data in separate tags from classic ReplayGain data for formats that need it (namely, Ogg Opus). A new ``r128`` configuration option enables this behavior for specific formats. Thanks to :user:`autrimpo`. :bug:`2557` :bug:`2560` - The :ref:`move-cmd` command gained a new ``--export`` flag, which copies files to an external location without changing their paths in the library database. Thanks to :user:`SpirosChadoulos`. :bug:`435` :bug:`2510` There are also some bug fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/lastgenre`: Fix a crash when using the ``prefer_specific`` and ``canonical`` options together. Thanks to :user:`yacoob`. :bug:`2459` :bug:`2583` - :doc:`/plugins/web`: Fix a crash on Windows under Python 2 when serving non-ASCII filenames. Thanks to :user:`robot3498712`. :bug:`2592` :bug:`2593` - :doc:`/plugins/metasync`: Fix a crash in the Amarok backend when filenames contain quotes. Thanks to :user:`aranc23`. :bug:`2595` :bug:`2596` - More informative error messages are displayed when the file format is not recognized. :bug:`2599` 1.4.4 (June 10, 2017) --------------------- This release built up a longer-than-normal list of nifty new features. We now support DSF audio files and the importer can hard-link your files, for example. Here's a full list of new features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Added support for DSF files, once a future version of Mutagen is released that supports them. Thanks to :user:`docbobo`. :bug:`459` :bug:`2379` - A new :ref:`hardlink` config option instructs the importer to create hard links on filesystems that support them. Thanks to :user:`jacobwgillespie`. :bug:`2445` - A new :doc:`/plugins/kodiupdate` lets you keep your Kodi library in sync with beets. Thanks to :user:`Pauligrinder`. :bug:`2411` - A new :ref:`bell` configuration option under the ``import`` section enables a terminal bell when input is required. Thanks to :user:`SpirosChadoulos`. :bug:`2366` :bug:`2495` - A new field, ``composer_sort``, is now supported and fetched from MusicBrainz. Thanks to :user:`dosoe`. :bug:`2519` :bug:`2529` - The MusicBrainz backend and :doc:`/plugins/discogs` now both provide a new attribute called ``track_alt`` that stores more nuanced, possibly non-numeric track index data. For example, some vinyl or tape media will report the side of the record using a letter instead of a number in that field. :bug:`1831` :bug:`2363` - :doc:`/plugins/web`: Added a new endpoint, ``/item/path/foo``, which will return the item info for the file at the given path, or 404. - :doc:`/plugins/web`: Added a new config option, ``include_paths``, which will cause paths to be included in item API responses if set to true. - The ``%aunique`` template function for :ref:`aunique` now takes a third argument that specifies which brackets to use around the disambiguator value. The argument can be any two characters that represent the left and right brackets. It defaults to ``[]`` and can also be blank to turn off bracketing. :bug:`2397` :bug:`2399` - Added a ``--move`` or ``-m`` option to the importer so that the files can be moved to the library instead of being copied or added "in place." :bug:`2252` :bug:`2429` - :doc:`/plugins/badfiles`: Added a ``--verbose`` or ``-v`` option. Results are now displayed only for corrupted files by default and for all the files when the verbose option is set. :bug:`1654` :bug:`2434` - :doc:`/plugins/embedart`: The explicit ``embedart`` command now asks for confirmation before embedding art into music files. Thanks to :user:`Stunner`. :bug:`1999` - You can now run beets by typing ``python -m beets``. :bug:`2453` - :doc:`/plugins/smartplaylist`: Different playlist specifications that generate identically-named playlist files no longer conflict; instead, the resulting lists of tracks are concatenated. :bug:`2468` - :doc:`/plugins/missing`: A new mode lets you see missing albums from artists you have in your library. Thanks to :user:`qlyoung`. :bug:`2481` - :doc:`/plugins/web` : Add new ``reverse_proxy`` config option to allow serving the web plugins under a reverse proxy. - Importing a release with multiple release events now selects the event based on your :ref:`preferred` countries. :bug:`2501` - :doc:`/plugins/play`: A new ``-y`` or ``--yes`` parameter lets you skip the warning message if you enqueue more items than the warning threshold usually allows. - Fix a bug where commands which forked subprocesses would sometimes prevent further inputs. This bug mainly affected :doc:`/plugins/convert`. Thanks to :user:`jansol`. :bug:`2488` :bug:`2524` There are also quite a few fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - In the :ref:`replace` configuration option, we now replace a leading hyphen (-) with an underscore. :bug:`549` :bug:`2509` - :doc:`/plugins/absubmit`: We no longer filter audio files for specific formats---we will attempt the submission process for all formats. :bug:`2471` - :doc:`/plugins/mpdupdate`: Fix Python 3 compatibility. :bug:`2381` - :doc:`/plugins/replaygain`: Fix Python 3 compatibility in the ``bs1770gain`` backend. :bug:`2382` - :doc:`/plugins/bpd`: Report playback times as integers. :bug:`2394` - :doc:`/plugins/mpdstats`: Fix Python 3 compatibility. The plugin also now requires version 0.4.2 or later of the ``python-mpd2`` library. :bug:`2405` - :doc:`/plugins/mpdstats`: Improve handling of MPD status queries. - :doc:`/plugins/badfiles`: Fix Python 3 compatibility. - Fix some cases where album-level ReplayGain/SoundCheck metadata would be written to files incorrectly. :bug:`2426` - :doc:`/plugins/badfiles`: The command no longer bails out if the validator command is not found or exits with an error. :bug:`2430` :bug:`2433` - :doc:`/plugins/lyrics`: The Google search backend no longer crashes when the server responds with an error. :bug:`2437` - :doc:`/plugins/discogs`: You can now authenticate with Discogs using a personal access token. :bug:`2447` - Fix Python 3 compatibility when extracting rar archives in the importer. Thanks to :user:`Lompik`. :bug:`2443` :bug:`2448` - :doc:`/plugins/duplicates`: Fix Python 3 compatibility when using the ``copy`` and ``move`` options. :bug:`2444` - :doc:`/plugins/mbsubmit`: The tracks are now sorted properly. Thanks to :user:`awesomer`. :bug:`2457` - :doc:`/plugins/thumbnails`: Fix a string-related crash on Python 3. :bug:`2466` - :doc:`/plugins/beatport`: More than just 10 songs are now fetched per album. :bug:`2469` - On Python 3, the :ref:`terminal_encoding` setting is respected again for output and printing will no longer crash on systems configured with a limited encoding. - :doc:`/plugins/convert`: The default configuration uses FFmpeg's built-in AAC codec instead of faac. Thanks to :user:`jansol`. :bug:`2484` - Fix the importer's detection of multi-disc albums when other subdirectories are present. :bug:`2493` - Invalid date queries now print an error message instead of being silently ignored. Thanks to :user:`discopatrick`. :bug:`2513` :bug:`2517` - When the SQLite database stops being accessible, we now print a friendly error message. Thanks to :user:`Mary011196`. :bug:`1676` :bug:`2508` - :doc:`/plugins/web`: Avoid a crash when sending binary data, such as Chromaprint fingerprints, in music attributes. :bug:`2542` :bug:`2532` - Fix a hang when parsing templates that end in newlines. :bug:`2562` - Fix a crash when reading non-ASCII characters in configuration files on Windows under Python 3. :bug:`2456` :bug:`2565` :bug:`2566` We removed backends from two metadata plugins because of bitrot ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/lyrics`: The Lyrics.com backend has been removed. (It stopped working because of changes to the site's URL structure.) :bug:`2548` :bug:`2549` - :doc:`/plugins/fetchart`: The documentation no longer recommends iTunes Store artwork lookup because the unmaintained python-itunes_ is broken. Want to adopt it? :bug:`2371` :bug:`1610` .. _python-itunes: https://github.com/ocelma/python-itunes 1.4.3 (January 9, 2017) ----------------------- Happy new year! This new version includes a cornucopia of new features from contributors, including new tags related to classical music and a new :doc:`/plugins/absubmit` for performing acoustic analysis on your music. The :doc:`/plugins/random` has a new mode that lets you generate time-limited music---for example, you might generate a random playlist that lasts the perfect length for your walk to work. We also access as many Web services as possible over secure connections now---HTTPS everywhere! The most visible new features are ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - We now support the composer, lyricist, and arranger tags. The MusicBrainz data source will fetch data for these fields when the next version of python-musicbrainzngs_ is released. Thanks to :user:`ibmibmibm`. :bug:`506` :bug:`507` :bug:`1547` :bug:`2333` - A new :doc:`/plugins/absubmit` lets you run acoustic analysis software and upload the results for others to use. Thanks to :user:`inytar`. :bug:`2253` :bug:`2342` - :doc:`/plugins/play`: The plugin now provides an importer prompt choice to play the music you're about to import. Thanks to :user:`diomekes`. :bug:`2008` :bug:`2360` - We now use SSL to access Web services whenever possible. That includes MusicBrainz itself, several album art sources, some lyrics sources, and other servers. Thanks to :user:`tigranl`. :bug:`2307` - :doc:`/plugins/random`: A new ``--time`` option lets you generate a random playlist that takes a given amount of time. Thanks to :user:`diomekes`. :bug:`2305` :bug:`2322` Some smaller new features ~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/zero`: A new ``zero`` command manually triggers the zero plugin. Thanks to :user:`SJoshBrown`. :bug:`2274` :bug:`2329` - :doc:`/plugins/acousticbrainz`: The plugin will avoid re-downloading data for files that already have it by default. You can override this behavior using a new ``force`` option. Thanks to :user:`SusannaMaria`. :bug:`2347` :bug:`2349` - :doc:`/plugins/bpm`: The ``import.write`` configuration option now decides whether or not to write tracks after updating their BPM. :bug:`1992` And the fixes ~~~~~~~~~~~~~ - :doc:`/plugins/bpd`: Fix a crash on non-ASCII MPD commands. :bug:`2332` - :doc:`/plugins/scrub`: Avoid a crash when files cannot be read or written. :bug:`2351` - :doc:`/plugins/scrub`: The image type values on scrubbed files are preserved instead of being reset to "other." :bug:`2339` - :doc:`/plugins/web`: Fix a crash on Python 3 when serving files from the filesystem. :bug:`2353` - :doc:`/plugins/discogs`: Improve the handling of releases that contain subtracks. :bug:`2318` - :doc:`/plugins/discogs`: Fix a crash when a release does not contain format information, and increase robustness when other fields are missing. :bug:`2302` - :doc:`/plugins/lyrics`: The plugin now reports a beets-specific User-Agent header when requesting lyrics. :bug:`2357` - :doc:`/plugins/embyupdate`: The plugin now checks whether an API key or a password is provided in the configuration. - :doc:`/plugins/play`: The misspelled configuration option ``warning_treshold`` is no longer supported. For plugin developers ~~~~~~~~~~~~~~~~~~~~~ - :ref:`append_prompt_choices`: When providing new importer prompt choices, you can now provide new candidates for the user to consider. For example, you might provide an alternative strategy for picking between the available alternatives or for looking up a release on MusicBrainz. 1.4.2 (December 16, 2016) ------------------------- This is just a little bug fix release. With 1.4.2, we're also confident enough to recommend that anyone who's interested give Python 3 a try: bugs may still lurk, but we've deemed things safe enough for broad adoption. If you can, please install beets with ``pip3`` instead of ``pip2`` this time and let us know how it goes! Here are the fixes ~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/badfiles`: Fix a crash on non-ASCII filenames. :bug:`2299` - The ``%asciify{}`` path formatting function and the :ref:`asciify-paths` setting properly substitute path separators generated by converting some Unicode characters, such as ½ and ¢, into ASCII. - :doc:`/plugins/convert`: Fix a logging-related crash when filenames contain curly braces. Thanks to :user:`kierdavis`. :bug:`2323` - We've rolled back some changes to the included zsh completion script that were causing problems for some users. :bug:`2266` Also, we've removed some special handling for logging in the :doc:`/plugins/discogs` that we believe was unnecessary. If spurious log messages appear in this version, please let us know by filing a bug. 1.4.1 (November 25, 2016) ------------------------- Version 1.4 has **alpha-level** Python 3 support. Thanks to the heroic efforts of :user:`jrobeson`, beets should run both under Python 2.7, as before, and now under Python 3.4 and above. The support is still new: it undoubtedly contains bugs, so it may replace all your music with Limp Bizkit---but if you're brave and you have backups, please try installing on Python 3. Let us know how it goes. If you package beets for distribution, here's what you'll want to know ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - This version of beets now depends on the six_ library. - We also bumped our minimum required version of Mutagen_ to 1.33 (from 1.27). - Please don't package beets as a Python 3 application *yet*, even though most things work under Python 3.4 and later. This version also makes a few changes to the command-line interface and configuration that you may need to know about: - :doc:`/plugins/duplicates`: The ``duplicates`` command no longer accepts multiple field arguments in the form ``-k title albumartist album``. Each argument must be prefixed with ``-k``, as in ``-k title -k albumartist -k album``. - The old top-level ``colors`` configuration option has been removed (the setting is now under ``ui``). - The deprecated ``list_format_album`` and ``list_format_item`` configuration options have been removed (see :ref:`format_album` and :ref:`format_item`). The are a few new features ~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/mpdupdate`, :doc:`/plugins/mpdstats`: When the ``host`` option is not set, these plugins will now look for the ``$MPD_HOST`` environment variable before falling back to ``localhost``. Thanks to :user:`tarruda`. :bug:`2175` - :doc:`/plugins/web`: Added an ``expand`` option to show the items of an album. :bug:`2050` - :doc:`/plugins/embyupdate`: The plugin can now use an API key instead of a password to authenticate with Emby. :bug:`2045` :bug:`2117` - :doc:`/plugins/acousticbrainz`: The plugin now adds a ``bpm`` field. - ``beet --version`` now includes the Python version used to run beets. - :doc:`/reference/pathformat` can now include unescaped commas (``,``) when they are not part of a function call. :bug:`2166` :bug:`2213` - The :ref:`update-cmd` command takes a new ``-F`` flag to specify the fields to update. Thanks to :user:`dangmai`. :bug:`2229` :bug:`2231` And there are a few bug fixes too ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/convert`: The plugin no longer asks for confirmation if the query did not return anything to convert. :bug:`2260` :bug:`2262` - :doc:`/plugins/embedart`: The plugin now uses ``jpg`` as an extension rather than ``jpeg``, to ensure consistency with the :doc:`plugins/fetchart`. Thanks to :user:`tweitzel`. :bug:`2254` :bug:`2255` - :doc:`/plugins/embedart`: The plugin now works for all jpeg files, including those that are only recognizable by their magic bytes. :bug:`1545` :bug:`2255` - :doc:`/plugins/web`: The JSON output is no longer pretty-printed (for a space savings). :bug:`2050` - :doc:`/plugins/permissions`: Fix a regression in the previous release where the plugin would always fail to set permissions (and log a warning). :bug:`2089` - :doc:`/plugins/beatport`: Use track numbers from Beatport (instead of determining them from the order of tracks) and set the ``medium_index`` value. - With :ref:`per_disc_numbering` enabled, some metadata sources (notably, the :doc:`/plugins/beatport`) would not set the track number at all. This is fixed. :bug:`2085` - :doc:`/plugins/play`: Fix ``$args`` getting passed verbatim to the play command if it was set in the configuration but ``-A`` or ``--args`` was omitted. - With :ref:`ignore_hidden` enabled, non-UTF-8 filenames would cause a crash. This is fixed. :bug:`2168` - :doc:`/plugins/embyupdate`: Fixes authentication header problem that caused a problem that it was not possible to get tokens from the Emby API. - :doc:`/plugins/lyrics`: Some titles use a colon to separate the main title from a subtitle. To find more matches, the plugin now also searches for lyrics using the part part preceding the colon character. :bug:`2206` - Fix a crash when a query uses a date field and some items are missing that field. :bug:`1938` - :doc:`/plugins/discogs`: Subtracks are now detected and combined into a single track, two-sided mediums are treated as single discs, and tracks have ``media``, ``medium_total`` and ``medium`` set correctly. :bug:`2222` :bug:`2228`. - :doc:`/plugins/missing`: ``missing`` is now treated as an integer, allowing the use of (for example) ranges in queries. - :doc:`/plugins/smartplaylist`: Playlist names will be sanitized to ensure valid filenames. :bug:`2258` - The ID3 APIC tag now uses the Latin-1 encoding when possible instead of a Unicode encoding. This should increase compatibility with other software, especially with iTunes and when using ID3v2.3. Thanks to :user:`lazka`. :bug:`899` :bug:`2264` :bug:`2270` The last release, 1.3.19, also erroneously reported its version as "1.3.18" when you typed ``beet version``. This has been corrected. .. _six: https://pypi.org/project/six/ 1.3.19 (June 25, 2016) ---------------------- This is primarily a bug fix release: it cleans up a couple of regressions that appeared in the last version. But it also features the triumphant return of the :doc:`/plugins/beatport` and a modernized :doc:`/plugins/bpd`. It's also the first version where beets passes all its tests on Windows! May this herald a new age of cross-platform reliability for beets. New features ~~~~~~~~~~~~ - :doc:`/plugins/beatport`: This metadata source plugin has arisen from the dead! It now works with Beatport's new OAuth-based API. Thanks to :user:`jbaiter`. :bug:`1989` :bug:`2067` - :doc:`/plugins/bpd`: The plugin now uses the modern GStreamer 1.0 instead of the old 0.10. Thanks to :user:`philippbeckmann`. :bug:`2057` :bug:`2062` - A new ``--force`` option for the :ref:`remove-cmd` command allows removal of items without prompting beforehand. :bug:`2042` - A new :ref:`duplicate_action` importer config option controls how duplicate albums or tracks treated in import task. :bug:`185` Some fixes for Windows ~~~~~~~~~~~~~~~~~~~~~~ - Queries are now detected as paths when they contain backslashes (in addition to forward slashes). This only applies on Windows. - :doc:`/plugins/embedart`: Image similarity comparison with ImageMagick should now work on Windows. - :doc:`/plugins/fetchart`: The plugin should work more reliably with non-ASCII paths. And other fixes ~~~~~~~~~~~~~~~ - :doc:`/plugins/replaygain`: The ``bs1770gain`` backend now correctly calculates sample peak instead of true peak. This comes with a major speed increase. :bug:`2031` - :doc:`/plugins/lyrics`: Avoid a crash and a spurious warning introduced in the last version about a Google API key, which appeared even when you hadn't enabled the Google lyrics source. - Fix a hard-coded path to ``bash-completion`` to work better with Homebrew installations. Thanks to :user:`bismark`. :bug:`2038` - Fix a crash introduced in the previous version when the standard input was connected to a Unix pipe. :bug:`2041` - Fix a crash when specifying non-ASCII format strings on the command line with the ``-f`` option for many commands. :bug:`2063` - :doc:`/plugins/fetchart`: Determine the file extension for downloaded images based on the image's magic bytes. The plugin prints a warning if result is not consistent with the server-supplied ``Content-Type`` header. In previous versions, the plugin would use a ``.jpg`` extension for all images. :bug:`2053` 1.3.18 (May 31, 2016) --------------------- This update adds a new :doc:`/plugins/hook` that lets you integrate beets with command-line tools and an :doc:`/plugins/export` that can dump data from the beets database as JSON. You can also automatically translate lyrics using a machine translation service. The ``echonest`` plugin has been removed in this version because the API it used is `shutting down`_. You might want to try the :doc:`/plugins/acousticbrainz` instead. .. _shutting down: https://web.archive.org/web/20260000000000*/developer.spotify.com/news-stories/2016/03/29/api-improvements-update Some of the larger new features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The new :doc:`/plugins/hook` lets you execute commands in response to beets events. - The new :doc:`/plugins/export` can export data from beets' database as JSON. Thanks to :user:`GuilhermeHideki`. - :doc:`/plugins/lyrics`: The plugin can now translate the fetched lyrics to your native language using the Bing translation API. Thanks to :user:`Kraymer`. - :doc:`/plugins/fetchart`: Album art can now be fetched from fanart.tv_. Smaller new things ~~~~~~~~~~~~~~~~~~ - There are two new functions available in templates: ``%first`` and ``%ifdef``. See :ref:`template-functions`. - :doc:`/plugins/convert`: A new ``album_art_maxwidth`` setting lets you resize album art while copying it. - :doc:`/plugins/convert`: The ``extension`` setting is now optional for conversion formats. By default, the extension is the same as the name of the configured format. - :doc:`/plugins/importadded`: A new ``preserve_write_mtimes`` option lets you preserve mtime of files even when beets updates their metadata. - :doc:`/plugins/fetchart`: The ``enforce_ratio`` option now lets you tolerate images that are *almost* square but differ slightly from an exact 1:1 aspect ratio. - :doc:`/plugins/fetchart`: The plugin can now optionally save the artwork's source in an attribute in the database. - The :ref:`terminal_encoding` configuration option can now also override the *input* encoding. (Previously, it only affected the encoding of the standard *output* stream.) - A new :ref:`ignore_hidden` configuration option lets you ignore files that your OS marks as invisible. - :doc:`/plugins/web`: A new ``values`` endpoint lets you get the distinct values of a field. Thanks to :user:`sumpfralle`. :bug:`2010` .. _fanart.tv: https://fanart.tv/ Fixes ~~~~~ - Fix a problem with the :ref:`stats-cmd` command in exact mode when filenames on Windows use non-ASCII characters. :bug:`1891` - Fix a crash when iTunes Sound Check tags contained invalid data. :bug:`1895` - :doc:`/plugins/mbcollection`: The plugin now redacts your MusicBrainz password in the ``beet config`` output. :bug:`1907` - :doc:`/plugins/scrub`: Fix an occasional problem where scrubbing on import could undo the :ref:`id3v23` setting. :bug:`1903` - :doc:`/plugins/lyrics`: Add compatibility with some changes to the LyricsWiki page markup. :bug:`1912` :bug:`1909` - :doc:`/plugins/lyrics`: Fix retrieval from Musixmatch by improving the way we guess the URL for lyrics on that service. :bug:`1880` - :doc:`/plugins/edit`: Fail gracefully when the configured text editor command can't be invoked. :bug:`1927` - :doc:`/plugins/fetchart`: Fix a crash in the Wikipedia backend on non-ASCII artist and album names. :bug:`1960` - :doc:`/plugins/convert`: Change the default ``ogg`` encoding quality from 2 to 3 (to fit the default from the ``oggenc(1)`` manpage). :bug:`1982` - :doc:`/plugins/convert`: The ``never_convert_lossy_files`` option now considers AIFF a lossless format. :bug:`2005` - :doc:`/plugins/web`: A proper 404 error, instead of an internal exception, is returned when missing album art is requested. Thanks to :user:`sumpfralle`. :bug:`2011` - Tolerate more malformed floating-point numbers in metadata tags. :bug:`2014` - The :ref:`ignore` configuration option now includes the ``lost+found`` directory by default. - :doc:`/plugins/acousticbrainz`: AcousticBrainz lookups are now done over HTTPS. Thanks to :user:`Freso`. :bug:`2007` 1.3.17 (February 7, 2016) ------------------------- This release introduces one new plugin to fetch audio information from the AcousticBrainz_ project and another plugin to make it easier to submit your handcrafted metadata back to MusicBrainz. The importer also gained two oft-requested features: a way to skip the initial search process by specifying an ID ahead of time, and a way to *manually* provide metadata in the middle of the import process (via the :doc:`/plugins/edit`). Also, as of this release, the beets project has some new Internet homes! Our new domain name is beets.io_, and we have a shiny new GitHub organization: beetbox_. Here are the big new features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - A new :doc:`/plugins/acousticbrainz` fetches acoustic-analysis information from the AcousticBrainz_ project. Thanks to :user:`opatel99`, and thanks to `Google Code-In`_! :bug:`1784` - A new :doc:`/plugins/mbsubmit` lets you print music's current metadata in a format that the MusicBrainz data parser can understand. You can trigger it during an interactive import session. :bug:`1779` - A new ``--search-id`` importer option lets you manually specify IDs (i.e., MBIDs or Discogs IDs) for imported music. Doing this skips the initial candidate search, which can be important for huge albums where this initial lookup is slow. Also, the ``enter Id`` prompt choice now accepts several IDs, separated by spaces. :bug:`1808` - :doc:`/plugins/edit`: You can now edit metadata *on the fly* during the import process. The plugin provides two new interactive options: one to edit *your music's* metadata, and one to edit the *matched metadata* retrieved from MusicBrainz (or another data source). This feature is still in its early stages, so please send feedback if you find anything missing. :bug:`1846` :bug:`396` There are even more new features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/fetchart`: The Google Images backend has been restored. It now requires an API key from Google. Thanks to :user:`lcharlick`. :bug:`1778` - :doc:`/plugins/info`: A new option will print only fields' names and not their values. Thanks to :user:`GuilhermeHideki`. :bug:`1812` - The :ref:`fields-cmd` command now displays flexible attributes. Thanks to :user:`GuilhermeHideki`. :bug:`1818` - The :ref:`modify-cmd` command lets you interactively select which albums or items you want to change. :bug:`1843` - The :ref:`move-cmd` command gained a new ``--timid`` flag to print and confirm which files you want to move. :bug:`1843` - The :ref:`move-cmd` command no longer prints filenames for files that don't actually need to be moved. :bug:`1583` .. _acousticbrainz: https://acousticbrainz.org/ .. _google code-in: https://codein.withgoogle.com/archive/ Fixes ~~~~~ - :doc:`/plugins/play`: Fix a regression in the last version where there was no default command. :bug:`1793` - :doc:`/plugins/lastimport`: The plugin now works again after being broken by some unannounced changes to the Last.fm API. :bug:`1574` - :doc:`/plugins/play`: Fixed a typo in a configuration option. The option is now ``warning_threshold`` instead of ``warning_treshold``, but we kept the old name around for compatibility. Thanks to :user:`JesseWeinstein`. :bug:`1802` :bug:`1803` - :doc:`/plugins/edit`: Editing metadata now moves files, when appropriate (like the :ref:`modify-cmd` command). :bug:`1804` - The :ref:`stats-cmd` command no longer crashes when files are missing or inaccessible. :bug:`1806` - :doc:`/plugins/fetchart`: Possibly fix a Unicode-related crash when using some versions of pyOpenSSL. :bug:`1805` - :doc:`/plugins/replaygain`: Fix an intermittent crash with the GStreamer backend. :bug:`1855` - :doc:`/plugins/lastimport`: The plugin now works with the beets API key by default. You can still provide a different key the configuration. - :doc:`/plugins/replaygain`: Fix a crash using the Python Audio Tools backend. :bug:`1873` .. _beetbox: https://github.com/beetbox .. _beets.io: https://beets.io/ 1.3.16 (December 28, 2015) -------------------------- The big news in this release is a new :doc:`interactive editor plugin </plugins/edit>`. It's really nifty: you can now change your music's metadata by making changes in a visual text editor, which can sometimes be far more efficient than the built-in :ref:`modify-cmd` command. No more carefully retyping the same artist name with slight capitalization changes. This version also adds an oft-requested "not" operator to beets' queries, so you can exclude music from any operation. It also brings friendlier formatting (and querying!) of song durations. The big new stuff ~~~~~~~~~~~~~~~~~ - A new :doc:`/plugins/edit` lets you manually edit your music's metadata using your favorite text editor. :bug:`164` :bug:`1706` - Queries can now use "not" logic. Type a ``^`` before part of a query to *exclude* matching music from the results. For example, ``beet list -a beatles ^album:1`` will find all your albums by the Beatles except for their singles compilation, "1." See :ref:`not_query`. :bug:`819` :bug:`1728` - A new :doc:`/plugins/embyupdate` can trigger a library refresh on an Emby_ server when your beets database changes. - Track length is now displayed as "M:SS" rather than a raw number of seconds. Queries on track length also accept this format: for example, ``beet list length:5:30..`` will find all your tracks that have a duration over 5 minutes and 30 seconds. You can turn off this new behavior using the ``format_raw_length`` configuration option. :bug:`1749` Smaller changes ~~~~~~~~~~~~~~~ - Three commands, ``modify``, ``update``, and ``mbsync``, would previously move files by default after changing their metadata. Now, these commands will only move files if you have the :ref:`config-import-copy` or :ref:`config-import-move` options enabled in your importer configuration. This way, if you configure the importer not to touch your filenames, other commands will respect that decision by default too. Each command also sprouted a ``--move`` command-line option to override this default (in addition to the ``--nomove`` flag they already had). :bug:`1697` - A new configuration option, ``va_name``, controls the album artist name for various-artists albums. The setting defaults to "Various Artists," the MusicBrainz standard. In order to match MusicBrainz, the :doc:`/plugins/discogs` also adopts the same setting. - :doc:`/plugins/info`: The ``info`` command now accepts a ``-f/--format`` option for customizing how items are displayed, just like the built-in ``list`` command. :bug:`1737` Some changes for developers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Two new :ref:`plugin hooks <plugin_events>`, ``albuminfo_received`` and ``trackinfo_received``, let plugins intercept metadata as soon as it is received, before it is applied to music in the database. :bug:`872` - Plugins can now add options to the interactive importer prompts. See :ref:`append_prompt_choices`. :bug:`1758` Fixes ~~~~~ - :doc:`/plugins/plexupdate`: Fix a crash when Plex libraries use non-ASCII collection names. :bug:`1649` - :doc:`/plugins/discogs`: Maybe fix a crash when using some versions of the ``requests`` library. :bug:`1656` - Fix a race in the importer when importing two albums with the same artist and name in quick succession. The importer would fail to detect them as duplicates, claiming that there were "empty albums" in the database even when there were not. :bug:`1652` - :doc:`plugins/lastgenre`: Clean up the reggae-related genres somewhat. Thanks to :user:`Freso`. :bug:`1661` - The importer now correctly moves album art files when re-importing. :bug:`314` - :doc:`/plugins/fetchart`: In auto mode, the plugin now skips albums that already have art attached to them so as not to interfere with re-imports. :bug:`314` - :doc:`plugins/fetchart`: The plugin now only resizes album art if necessary, rather than always by default. :bug:`1264` - :doc:`plugins/fetchart`: Fix a bug where a database reference to a non-existent album art file would prevent the command from fetching new art. :bug:`1126` - :doc:`/plugins/thumbnails`: Fix a crash with Unicode paths. :bug:`1686` - :doc:`/plugins/embedart`: The ``remove_art_file`` option now works on import (as well as with the explicit command). :bug:`1662` :bug:`1675` - :doc:`/plugins/metasync`: Fix a crash when syncing with recent versions of iTunes. :bug:`1700` - :doc:`/plugins/duplicates`: Fix a crash when merging items. :bug:`1699` - :doc:`/plugins/smartplaylist`: More gracefully handle malformed queries and missing configuration. - Fix a crash with some files with unreadable iTunes SoundCheck metadata. :bug:`1666` - :doc:`/plugins/thumbnails`: Fix a nasty segmentation fault crash that arose with some library versions. :bug:`1433` - :doc:`/plugins/convert`: Fix a crash with Unicode paths in ``--pretend`` mode. :bug:`1735` - Fix a crash when sorting by nonexistent fields on queries. :bug:`1734` - Probably fix some mysterious errors when dealing with images using ImageMagick on Windows. :bug:`1721` - Fix a crash when writing some Unicode comment strings to MP3s that used older encodings. The encoding is now always updated to UTF-8. :bug:`879` - :doc:`/plugins/fetchart`: The Google Images backend has been removed. It used an API that has been shut down. :bug:`1760` - :doc:`/plugins/lyrics`: Fix a crash in the Google backend when searching for bands with regular-expression characters in their names, like Sunn O))). :bug:`1673` - :doc:`/plugins/scrub`: In ``auto`` mode, the plugin now *actually* only scrubs files on import, as the documentation always claimed it did---not every time files were written, as it previously did. :bug:`1657` - :doc:`/plugins/scrub`: Also in ``auto`` mode, album art is now correctly restored. :bug:`1657` - Possibly allow flexible attributes to be used with the ``%aunique`` template function. :bug:`1775` - :doc:`/plugins/lyrics`: The Genius backend is now more robust to communication errors. The backend has also been disabled by default, since the API it depends on is currently down. :bug:`1770` .. _emby: https://emby.media 1.3.15 (October 17, 2015) ------------------------- This release adds a new plugin for checking file quality and a new source for lyrics. The larger features are: - A new :doc:`/plugins/badfiles` helps you scan for corruption in your music collection. Thanks to :user:`fxthomas`. :bug:`1568` - :doc:`/plugins/lyrics`: You can now fetch lyrics from Genius.com. Thanks to :user:`sadatay`. :bug:`1626` :bug:`1639` - :doc:`/plugins/zero`: The plugin can now use a "whitelist" policy as an alternative to the (default) "blacklist" mode. Thanks to :user:`adkow`. :bug:`1621` :bug:`1641` And there are smaller new features too ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Add new color aliases for standard terminal color names (e.g., cyan and magenta). Thanks to :user:`mathstuf`. :bug:`1548` - :doc:`/plugins/play`: A new ``--args`` option lets you specify options for the player command. :bug:`1532` - :doc:`/plugins/play`: A new ``raw`` configuration option lets the command work with players (such as VLC) that expect music filenames as arguments, rather than in a playlist. Thanks to :user:`nathdwek`. :bug:`1578` - :doc:`/plugins/play`: You can now configure the number of tracks that trigger a "lots of music" warning. :bug:`1577` - :doc:`/plugins/embedart`: A new ``remove_art_file`` option lets you clean up if you prefer *only* embedded album art. Thanks to :user:`jackwilsdon`. :bug:`1591` :bug:`733` - :doc:`/plugins/plexupdate`: A new ``library_name`` option allows you to select which Plex library to update. :bug:`1572` :bug:`1595` - A new ``include`` option lets you import external configuration files. This release has plenty of fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/lastgenre`: Fix a bug that prevented tag popularity from being considered. Thanks to :user:`svoos`. :bug:`1559` - Fixed a bug where plugins wouldn't be notified of the deletion of an item's art, for example with the ``clearart`` command from the :doc:`/plugins/embedart`. Thanks to :user:`nathdwek`. :bug:`1565` - :doc:`/plugins/fetchart`: The Google Images source is disabled by default (as it was before beets 1.3.9), as is the Wikipedia source (which was causing lots of unnecessary delays due to DBpedia downtime). To re-enable these sources, add ``wikipedia google`` to your ``sources`` configuration option. - The :ref:`list-cmd` command's help output now has a small query and format string example. Thanks to :user:`pkess`. :bug:`1582` - :doc:`/plugins/fetchart`: The plugin now fetches PNGs but not GIFs. (It still fetches JPEGs.) This avoids an error when trying to embed images, since not all formats support GIFs. :bug:`1588` - Date fields are now written in the correct order (year-month-day), which eliminates an intermittent bug where the latter two fields would not get written to files. Thanks to :user:`jdetrey`. :bug:`1303` :bug:`1589` - :doc:`/plugins/replaygain`: Avoid a crash when the PyAudioTools backend encounters an error. :bug:`1592` - The case sensitivity of path queries is more useful now: rather than just guessing based on the platform, we now check the case sensitivity of your filesystem. :bug:`1586` - Case-insensitive path queries might have returned nothing because of a wrong SQL query. - Fix a crash when a query contains a "+" or "-" alone in a component. :bug:`1605` - Fixed unit of file size to powers of two (MiB, GiB, etc.) instead of powers of ten (MB, GB, etc.). :bug:`1623` 1.3.14 (August 2, 2015) ----------------------- This is mainly a bugfix release, but we also have a nifty new plugin for ipfs_ and a bunch of new configuration options. The new features ~~~~~~~~~~~~~~~~ - A new :doc:`/plugins/ipfs` lets you share music via a new, global, decentralized filesystem. :bug:`1397` - :doc:`/plugins/duplicates`: You can now merge duplicate track metadata (when detecting duplicate items), or duplicate album tracks (when detecting duplicate albums). - :doc:`/plugins/duplicates`: Duplicate resolution now uses an ordering to prioritize duplicates. By default, it prefers music with more complete metadata, but you can configure it to use any list of attributes. - :doc:`/plugins/metasync`: Added a new backend to fetch metadata from iTunes. This plugin is still in an experimental phase. :bug:`1450` - The ``move`` command has a new ``--pretend`` option, making the command show how the items will be moved without actually changing anything. - The importer now supports matching of "pregap" or HTOA (hidden track-one audio) tracks when they are listed in MusicBrainz. (This feature depends on a new version of the python-musicbrainzngs_ library that is not yet released, but will start working when it is available.) Thanks to :user:`ruippeixotog`. :bug:`1104` :bug:`1493` - :doc:`/plugins/plexupdate`: A new ``token`` configuration option lets you specify a key for Plex Home setups. Thanks to :user:`edcarroll`. :bug:`1494` Fixes ~~~~~ - :doc:`/plugins/fetchart`: Complain when the ``enforce_ratio`` or ``min_width`` options are enabled but no local imaging backend is available to carry them out. :bug:`1460` - :doc:`/plugins/importfeeds`: Avoid generating incorrect m3u filename when both of the ``m3u`` and ``m3u_multi`` options are enabled. :bug:`1490` - :doc:`/plugins/duplicates`: Avoid a crash when misconfigured. :bug:`1457` - :doc:`/plugins/mpdstats`: Avoid a crash when the music played is not in the beets library. Thanks to :user:`CodyReichert`. :bug:`1443` - Fix a crash with ArtResizer on Windows systems (affecting :doc:`/plugins/embedart`, :doc:`/plugins/fetchart`, and :doc:`/plugins/thumbnails`). :bug:`1448` - :doc:`/plugins/permissions`: Fix an error with non-ASCII paths. :bug:`1449` - Fix sorting by paths when the :ref:`sort_case_insensitive` option is enabled. :bug:`1451` - :doc:`/plugins/embedart`: Avoid an error when trying to embed invalid images into MPEG-4 files. - :doc:`/plugins/fetchart`: The Wikipedia source can now better deal artists that use non-standard capitalization (e.g., alt-J, dEUS). - :doc:`/plugins/web`: Fix searching for non-ASCII queries. Thanks to :user:`oldtopman`. :bug:`1470` - :doc:`/plugins/mpdupdate`: We now recommend the newer ``python-mpd2`` library instead of its unmaintained parent. Thanks to :user:`Somasis`. :bug:`1472` - The importer interface and log file now output a useful list of files (instead of the word "None") when in album-grouping mode. :bug:`1475` :bug:`825` - Fix some logging errors when filenames and other user-provided strings contain curly braces. :bug:`1481` - Regular expression queries over paths now work more reliably with non-ASCII characters in filenames. :bug:`1482` - Fix a bug where the autotagger's :ref:`ignored` setting was sometimes, well, ignored. :bug:`1487` - Fix a bug with Unicode strings when generating image thumbnails. :bug:`1485` - :doc:`/plugins/keyfinder`: Fix handling of Unicode paths. :bug:`1502` - :doc:`/plugins/fetchart`: When album art is already present, the message is now printed in the ``text_highlight_minor`` color (light gray). Thanks to :user:`Somasis`. :bug:`1512` - Some messages in the console UI now use plural nouns correctly. Thanks to :user:`JesseWeinstein`. :bug:`1521` - Sorting numerical fields (such as track) now works again. :bug:`1511` - :doc:`/plugins/replaygain`: Missing GStreamer plugins now cause a helpful error message instead of a crash. :bug:`1518` - Fix an edge case when producing sanitized filenames where the maximum path length conflicted with the :ref:`replace` rules. Thanks to Ben Ockmore. :bug:`496` :bug:`1361` - Fix an incompatibility with OS X 10.11 (where ``/usr/sbin`` seems not to be on the user's path by default). - Fix an incompatibility with certain JPEG files. Here's a relevant `Python bug`_. Thanks to :user:`nathdwek`. :bug:`1545` - Fix the :ref:`group_albums` importer mode so that it works correctly when files are not already in order by album. :bug:`1550` - The ``fields`` command no longer separates built-in fields from plugin-provided ones. This distinction was becoming increasingly unreliable. - :doc:`/plugins/duplicates`: Fix a Unicode warning when paths contained non-ASCII characters. :bug:`1551` - :doc:`/plugins/fetchart`: Work around a urllib3 bug that could cause a crash. :bug:`1555` :bug:`1556` - When you edit the configuration file with ``beet config -e`` and the file does not exist, beets creates an empty file before editing it. This fixes an error on OS X, where the ``open`` command does not work with non-existent files. :bug:`1480` - :doc:`/plugins/convert`: Fix a problem with filename encoding on Windows under Python 3. :bug:`2515` :bug:`2516` .. _ipfs: https://about.ipfs.io/ .. _python bug: https://bugs.python.org/issue16512 1.3.13 (April 24, 2015) ----------------------- This is a tiny bug-fix release. It copes with a dependency upgrade that broke beets. There are just two fixes: - Fix compatibility with Jellyfish_ version 0.5.0. - :doc:`/plugins/embedart`: In ``auto`` mode (the import hook), the plugin now respects the ``write`` config option under ``import``. If this is disabled, album art is no longer embedded on import in order to leave files untouched---in effect, ``auto`` is implicitly disabled. :bug:`1427` 1.3.12 (April 18, 2015) ----------------------- This little update makes queries more powerful, sorts music more intelligently, and removes a performance bottleneck. There's an experimental new plugin for synchronizing metadata with music players. Packagers should also note a new dependency in this version: the Jellyfish_ Python library makes our text comparisons (a big part of the auto-tagging process) go much faster. New features ~~~~~~~~~~~~ - Queries can now use **"or" logic**: if you use a comma to separate parts of a query, items and albums will match *either* side of the comma. For example, ``beet ls foo , bar`` will get all the items matching ``foo`` or matching ``bar``. See :ref:`combiningqueries`. :bug:`1423` - The autotagger's **matching algorithm is faster**. We now use the Jellyfish_ library to compute string similarity, which is better optimized than our hand-rolled edit distance implementation. :bug:`1389` - Sorting is now **case insensitive** by default. This means that artists will be sorted lexicographically regardless of case. For example, the artist alt-J will now properly sort before YACHT. (Previously, it would have ended up at the end of the list, after all the capital-letter artists.) You can turn this new behavior off using the :ref:`sort_case_insensitive` configuration option. See :ref:`query-sort`. :bug:`1429` - An experimental new :doc:`/plugins/metasync` lets you get metadata from your favorite music players, starting with Amarok. :bug:`1386` - :doc:`/plugins/fetchart`: There are new settings to control what constitutes "acceptable" images. The ``minwidth`` option constrains the minimum image width in pixels and the ``enforce_ratio`` option requires that images be square. :bug:`1394` Little fixes and improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/fetchart`: Remove a hard size limit when fetching from the Cover Art Archive. - The output of the :ref:`fields-cmd` command is now sorted. Thanks to :user:`multikatt`. :bug:`1402` - :doc:`/plugins/replaygain`: Fix a number of issues with the new ``bs1770gain`` backend on Windows. Also, fix missing debug output in import mode. :bug:`1398` - Beets should now be better at guessing the appropriate output encoding on Windows. (Specifically, the console output encoding is guessed separately from the encoding for command-line arguments.) A bug was also fixed where beets would ignore the locale settings and use UTF-8 by default. :bug:`1419` - :doc:`/plugins/discogs`: Better error handling when we can't communicate with Discogs on setup. :bug:`1417` - :doc:`/plugins/importadded`: Fix a crash when importing singletons in-place. :bug:`1416` - :doc:`/plugins/fuzzy`: Fix a regression causing a crash in the last release. :bug:`1422` - Fix a crash when the importer cannot open its log file. Thanks to :user:`barsanuphe`. :bug:`1426` - Fix an error when trying to write tags for items with flexible fields called ``date`` and ``original_date`` (which are not built-in beets fields). :bug:`1404` .. _jellyfish: https://github.com/jamesturk/jellyfish 1.3.11 (April 5, 2015) ---------------------- In this release, we refactored the logging system to be more flexible and more useful. There are more granular levels of verbosity, the output from plugins should be more consistent, and several kinds of logging bugs should be impossible in the future. There are also two new plugins: one for filtering the files you import and an evolved plugin for using album art as directory thumbnails in file managers. There's a new source for album art, and the importer now records the source of match data. This is a particularly huge release---there's lots more below. There's one big change with this release: **Python 2.6 is no longer supported**. You'll need Python 2.7. Please trust us when we say this let us remove a surprising number of ugly hacks throughout the code. Major new features and bigger changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - There are now **multiple levels of output verbosity**. On the command line, you can make beets somewhat verbose with ``-v`` or very verbose with ``-vv``. For the importer especially, this makes the first verbose mode much more manageable, while still preserving an option for overwhelmingly verbose debug output. :bug:`1244` - A new :doc:`/plugins/filefilter` lets you write regular expressions to automatically **avoid importing** certain files. Thanks to :user:`mried`. :bug:`1186` - A new :doc:`/plugins/thumbnails` generates cover-art **thumbnails for album folders** for Freedesktop.org-compliant file managers. (This replaces the :doc:`/plugins/freedesktop`, which only worked with the Dolphin file manager.) - :doc:`/plugins/replaygain`: There is a new backend that uses the bs1770gain_ analysis tool. Thanks to :user:`jmwatte`. :bug:`1343` - A new ``filesize`` field on items indicates the number of bytes in the file. :bug:`1291` - A new :conf:`plugins.index:search_limit` configuration option allows you to specify how many search results you wish to see when looking up releases at MusicBrainz during import. :bug:`1245` - The importer now records the data source for a match in a new flexible attribute ``data_source`` on items and albums. :bug:`1311` - The colors used in the terminal interface are now configurable via the new config option ``colors``, nested under the option ``ui``. (Also, the ``color`` config option has been moved from top-level to under ``ui``. Beets will respect the old color setting, but will warn the user with a deprecation message.) :bug:`1238` - :doc:`/plugins/fetchart`: There's a new Wikipedia image source that uses DBpedia to find albums. Thanks to Tom Jaspers. :bug:`1194` - In the :ref:`config-cmd` command, the output is now redacted by default. Sensitive information like passwords and API keys is not included. The new ``--clear`` option disables redaction. :bug:`1376` You should probably also know about these core changes to the way beets works ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - As mentioned above, Python 2.6 is no longer supported. - The ``tracktotal`` attribute is now a *track-level field* instead of an album-level one. This field stores the total number of tracks on the album, or if the :ref:`per_disc_numbering` config option is set, the total number of tracks on a particular medium (i.e., disc). The field was causing problems with that :ref:`per_disc_numbering` mode: different discs on the same album needed different track totals. The field can now work correctly in either mode. - To replace ``tracktotal`` as an album-level field, there is a new ``albumtotal`` computed attribute that provides the total number of tracks on the album. (The :ref:`per_disc_numbering` option has no influence on this field.) - The ``list_format_album`` and ``list_format_item`` configuration keys now affect (almost) every place where objects are printed and logged. (Previously, they only controlled the :ref:`list-cmd` command and a few other scattered pieces.) :bug:`1269` - Relatedly, the ``beet`` program now accept top-level options ``--format-item`` and ``--format-album`` before any subcommand to control how items and albums are displayed. :bug:`1271` - ``list_format_album`` and ``list_format_album`` have respectively been renamed :ref:`format_album` and :ref:`format_item`. The old names still work but each triggers a warning message. :bug:`1271` - :ref:`Path queries <pathquery>` are automatically triggered only if the path targeted by the query exists. Previously, just having a slash somewhere in the query was enough, so ``beet ls AC/DC`` wouldn't work to refer to the artist. There are also lots of medium-sized features in this update ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/duplicates`: The command has a new ``--strict`` option that will only report duplicates if all attributes are explicitly set. :bug:`1000` - :doc:`/plugins/smartplaylist`: Playlist updating should now be faster: the plugin detects, for each playlist, whether it needs to be regenerated, instead of obliviously regenerating all of them. The ``splupdate`` command can now also take additional parameters that indicate the names of the playlists to regenerate. - :doc:`/plugins/play`: The command shows the output of the underlying player command and lets you interact with it. :bug:`1321` - The summary shown to compare duplicate albums during import now displays the old and new filesizes. :bug:`1291` - :doc:`/plugins/lastgenre`: Add *comedy*, *humor*, and *stand-up* as well as a longer list of classical music genre tags to the built-in whitelist and canonicalization tree. :bug:`1206` :bug:`1239` :bug:`1240` - :doc:`/plugins/web`: Add support for *cross-origin resource sharing* for more flexible in-browser clients. Thanks to Andre Miller. :bug:`1236` :bug:`1237` - :doc:`plugins/mbsync`: A new ``-f/--format`` option controls the output format when listing unrecognized items. The output is also now more helpful by default. :bug:`1246` - :doc:`/plugins/fetchart`: A new option, ``-n``, extracts the cover art of all matched albums into their respective directories. Another new flag, ``-a``, associates the extracted files with the albums in the database. :bug:`1261` - :doc:`/plugins/info`: A new option, ``-i``, can display only a specified subset of properties. :bug:`1287` - The number of missing/unmatched tracks is shown during import. :bug:`1088` - :doc:`/plugins/permissions`: The plugin now also adjusts the permissions of the directories. (Previously, it only affected files.) :bug:`1308` :bug:`1324` - :doc:`/plugins/ftintitle`: You can now configure the format that the plugin uses to add the artist to the title. Thanks to :user:`amishb`. :bug:`1377` And many little fixes and improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/replaygain`: Stop applying replaygain directly to source files when using the mp3gain backend. :bug:`1316` - Path queries are case-sensitive on non-Windows OSes. :bug:`1165` - :doc:`/plugins/lyrics`: Silence a warning about insecure requests in the new MusixMatch backend. :bug:`1204` - Fix a crash when ``beet`` is invoked without arguments. :bug:`1205` :bug:`1207` - :doc:`/plugins/fetchart`: Do not attempt to import directories as album art. :bug:`1177` :bug:`1211` - :doc:`/plugins/mpdstats`: Avoid double-counting some play events. :bug:`773` :bug:`1212` - Fix a crash when the importer deals with Unicode metadata in ``--pretend`` mode. :bug:`1214` - :doc:`/plugins/smartplaylist`: Fix ``album_query`` so that individual files are added to the playlist instead of directories. :bug:`1225` - Remove the ``beatport`` plugin. Beatport_ has shut off public access to their API and denied our request for an account. We have not heard from the company since 2013, so we are assuming access will not be restored. - Incremental imports now (once again) show a "skipped N directories" message. - :doc:`/plugins/embedart`: Handle errors in ImageMagick's output. :bug:`1241` - :doc:`/plugins/keyfinder`: Parse the underlying tool's output more robustly. :bug:`1248` - :doc:`/plugins/embedart`: We now show a comprehensible error message when ``beet embedart -f FILE`` is given a non-existent path. :bug:`1252` - Fix a crash when a file has an unrecognized image type tag. Thanks to Matthias Kiefer. :bug:`1260` - :doc:`/plugins/importfeeds` and :doc:`/plugins/smartplaylist`: Automatically create parent directories for playlist files (instead of crashing when the parent directory does not exist). :bug:`1266` - The :ref:`write-cmd` command no longer tries to "write" non-writable fields, such as the bitrate. :bug:`1268` - The error message when MusicBrainz is not reachable on the network is now much clearer. Thanks to Tom Jaspers. :bug:`1190` :bug:`1272` - Improve error messages when parsing query strings with shlex. :bug:`1290` - :doc:`/plugins/embedart`: Fix a crash that occurred when used together with the *check* plugin. :bug:`1241` - :doc:`/plugins/scrub`: Log an error instead of stopping when the ``beet scrub`` command cannot write a file. Also, avoid problems on Windows with Unicode filenames. :bug:`1297` - :doc:`/plugins/discogs`: Handle and log more kinds of communication errors. :bug:`1299` :bug:`1305` - :doc:`/plugins/lastgenre`: Bugs in the ``pylast`` library can no longer crash beets. - :doc:`/plugins/convert`: You can now configure the temporary directory for conversions. Thanks to :user:`autochthe`. :bug:`1382` :bug:`1383` - :doc:`/plugins/rewrite`: Fix a regression that prevented the plugin's rewriting from applying to album-level fields like ``$albumartist``. :bug:`1393` - :doc:`/plugins/play`: The plugin now sorts items according to the configuration in album mode. - :doc:`/plugins/fetchart`: The name for extracted art files is taken from the ``art_filename`` configuration option. :bug:`1258` - When there's a parse error in a query (for example, when you type a malformed date in a :ref:`date query <datequery>`), beets now stops with an error instead of silently ignoring the query component. - :doc:`/plugins/smartplaylist`: Stream-friendly smart playlists. The ``splupdate`` command can now also add a URL-encodable prefix to every path in the playlist file. For developers ~~~~~~~~~~~~~~ - The ``database_change`` event now sends the item or album that is subject to a change. - The ``OptionParser`` is now a ``CommonOptionsParser`` that offers facilities for adding usual options (``--album``, ``--path`` and ``--format``). See :ref:`add_subcommands`. :bug:`1271` - The logging system in beets has been overhauled. Plugins now each have their own logger, which helps by automatically adjusting the verbosity level in import mode and by prefixing the plugin's name. Logging levels are dynamically set when a plugin is called, depending on how it is called (import stage, event or direct command). Finally, logging calls can (and should!) use modern ``{}``-style string formatting lazily. See :ref:`plugin-logging` in the plugin API docs. - A new ``import_task_created`` event lets you manipulate import tasks immediately after they are initialized. It's also possible to replace the originally created tasks by returning new ones using this event. .. _bs1770gain: https://sourceforge.net/projects/bs1770gain/ 1.3.10 (January 5, 2015) ------------------------ This version adds a healthy helping of new features and fixes a critical MPEG-4--related bug. There are more lyrics sources, there new plugins for managing permissions and integrating with Plex_, and the importer has a new ``--pretend`` flag that shows which music *would* be imported. One backwards-compatibility note: the :doc:`/plugins/lyrics` now requires the requests_ library. If you use this plugin, you will need to install the library by typing ``pip install requests`` or the equivalent for your OS. Also, as an advance warning, this will be one of the last releases to support Python 2.6. If you have a system that cannot run Python 2.7, please consider upgrading soon. The new features are ~~~~~~~~~~~~~~~~~~~~ - A new :doc:`/plugins/permissions` makes it easy to fix permissions on music files as they are imported. Thanks to :user:`xsteadfastx`. :bug:`1098` - A new :doc:`/plugins/plexupdate` lets you notify a Plex_ server when the database changes. Thanks again to xsteadfastx. :bug:`1120` - The :ref:`import-cmd` command now has a ``--pretend`` flag that lists the files that will be imported. Thanks to :user:`mried`. :bug:`1162` - :doc:`/plugins/lyrics`: Add Musixmatch_ source and introduce a new ``sources`` config option that lets you choose exactly where to look for lyrics and in which order. - :doc:`/plugins/lyrics`: Add Brazilian and Spanish sources to Google custom search engine. - Add a warning when importing a directory that contains no music. :bug:`1116` :bug:`1127` - :doc:`/plugins/zero`: Can now remove embedded images. :bug:`1129` :bug:`1100` - The :ref:`config-cmd` command can now be used to edit the configuration even when it has syntax errors. :bug:`1123` :bug:`1128` - :doc:`/plugins/lyrics`: Added a new ``force`` config option. :bug:`1150` As usual, there are loads of little fixes and improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Fix a new crash with the latest version of Mutagen (1.26). - :doc:`/plugins/lyrics`: Avoid fetching truncated lyrics from the Google backed by merging text blocks separated by empty ``<div>`` tags before scraping. - We now print a better error message when the database file is corrupted. - :doc:`/plugins/discogs`: Only prompt for authentication when running the :ref:`import-cmd` command. :bug:`1123` - When deleting fields with the :ref:`modify-cmd` command, do not crash when the field cannot be removed (i.e., when it does not exist, when it is a built-in field, or when it is a computed field). :bug:`1124` - The deprecated ``echonest_tempo`` plugin has been removed. Please use the ``echonest`` plugin instead. - ``echonest`` plugin: Fingerprint-based lookup has been removed in accordance with `API changes`_. :bug:`1121` - ``echonest`` plugin: Avoid a crash when the song has no duration information. :bug:`896` - :doc:`/plugins/lyrics`: Avoid a crash when retrieving non-ASCII lyrics from the Google backend. :bug:`1135` :bug:`1136` - :doc:`/plugins/smartplaylist`: Sort specifiers are now respected in queries. Thanks to :user:`djl`. :bug:`1138` :bug:`1137` - :doc:`/plugins/ftintitle` and :doc:`/plugins/lyrics`: Featuring artists can now be detected when they use the Spanish word *con*. :bug:`1060` :bug:`1143` - :doc:`/plugins/mbcollection`: Fix an "HTTP 400" error caused by a change in the MusicBrainz API. :bug:`1152` - The ``%`` and ``_`` characters in path queries do not invoke their special SQL meaning anymore. :bug:`1146` - :doc:`/plugins/convert`: Command-line argument construction now works on Windows. Thanks to :user:`mluds`. :bug:`1026` :bug:`1157` :bug:`1158` - :doc:`/plugins/embedart`: Fix an erroneous missing-art error on Windows. Thanks to :user:`mluds`. :bug:`1163` - :doc:`/plugins/importadded`: Now works with in-place and symlinked imports. :bug:`1170` - :doc:`/plugins/ftintitle`: The plugin is now quiet when it runs as part of the import process. Thanks to :user:`Freso`. :bug:`1176` :bug:`1172` - :doc:`/plugins/ftintitle`: Fix weird behavior when the same artist appears twice in the artist string. Thanks to Marc Addeo. :bug:`1179` :bug:`1181` - :doc:`/plugins/lastgenre`: Match songs more robustly when they contain dashes. Thanks to :user:`djl`. :bug:`1156` - The :ref:`config-cmd` command can now use ``$EDITOR`` variables with arguments. .. _api changes: https://web.archive.org/web/20160814092627/https://developer.echonest.com/forums/thread/3650 .. _musixmatch: https://www.musixmatch.com/ .. _plex: https://watch.plex.tv/ 1.3.9 (November 17, 2014) ------------------------- This release adds two new standard plugins to beets: one for synchronizing Last.fm listening data and one for integrating with Linux desktops. And at long last, imports can now create symbolic links to music files instead of copying or moving them. We also gained the ability to search for album art on the iTunes Store and a new way to compute ReplayGain levels. The major new features are ~~~~~~~~~~~~~~~~~~~~~~~~~~ - A new :doc:`/plugins/lastimport` lets you download your play count data from Last.fm into a flexible attribute. Thanks to Rafael Bodill. - A new :doc:`/plugins/freedesktop` creates metadata files for Freedesktop.org--compliant file managers. Thanks to :user:`kerobaros`. :bug:`1056`, :bug:`707` - A new :ref:`link` option in the ``import`` section creates symbolic links during import instead of moving or copying. Thanks to Rovanion Luckey. :bug:`710`, :bug:`114` - :doc:`/plugins/fetchart`: You can now search for art on the iTunes Store. There's also a new ``sources`` config option that lets you choose exactly where to look for images and in which order. - :doc:`/plugins/replaygain`: A new Python Audio Tools backend was added. Thanks to Francesco Rubino. :bug:`1070` - :doc:`/plugins/embedart`: You can now automatically check that new art looks similar to existing art---ensuring that you only get a better "version" of the art you already have. See :ref:`image-similarity-check`. - :doc:`/plugins/ftintitle`: The plugin now runs automatically on import. To disable this, unset the ``auto`` config flag. There are also core improvements and other substantial additions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The ``media`` attribute is now a *track-level field* instead of an album-level one. This field stores the delivery mechanism for the music, so in its album-level incarnation, it could not represent heterogeneous releases---for example, an album consisting of a CD and a DVD. Now, tracks accurately indicate the media they appear on. Thanks to Heinz Wiesinger. - Re-imports of your existing music (see :ref:`reimport`) now preserve its added date and flexible attributes. Thanks to Stig Inge Lea Bjørnsen. - Slow queries, such as those over flexible attributes, should now be much faster when used with certain commands---notably, the :doc:`/plugins/play`. - :doc:`/plugins/bpd`: Add a new configuration option for setting the default volume. Thanks to IndiGit. - :doc:`/plugins/embedart`: A new ``ifempty`` config option lets you only embed album art when no album art is present. Thanks to kerobaros. - :doc:`/plugins/discogs`: Authenticate with the Discogs server. The plugin now requires a Discogs account due to new API restrictions. Thanks to :user:`multikatt`. :bug:`1027`, :bug:`1040` And countless little improvements and fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Standard cover art in APEv2 metadata is now supported. Thanks to Matthias Kiefer. :bug:`1042` - :doc:`/plugins/convert`: Avoid a crash when embedding cover art fails. - :doc:`/plugins/mpdstats`: Fix an error on start (introduced in the previous version). Thanks to Zach Denton. - :doc:`/plugins/convert`: The ``--yes`` command-line flag no longer expects an argument. - :doc:`/plugins/play`: Remove the temporary .m3u file after sending it to the player. - The importer no longer tries to highlight partial differences in numeric quantities (track numbers and durations), which was often confusing. - Date-based queries that are malformed (not parse-able) no longer crash beets and instead fail silently. - :doc:`/plugins/duplicates`: Emit an error when the ``checksum`` config option is set incorrectly. - The migration from pre-1.1, non-YAML configuration files has been removed. If you need to upgrade an old config file, use an older version of beets temporarily. - :doc:`/plugins/discogs`: Recover from HTTP errors when communicating with the Discogs servers. Thanks to Dustin Rodriguez. - :doc:`/plugins/embedart`: Do not log "embedding album art into..." messages during the import process. - Fix a crash in the autotagger when files had only whitespace in their metadata. - :doc:`/plugins/play`: Fix a potential crash when the command outputs special characters. :bug:`1041` - :doc:`/plugins/web`: Queries typed into the search field are now treated as separate query components. :bug:`1045` - Date tags that use slashes instead of dashes as separators are now interpreted correctly. And WMA (ASF) files now map the ``comments`` field to the "Description" tag (in addition to "WM/Comments"). Thanks to Matthias Kiefer. :bug:`1043` - :doc:`/plugins/embedart`: Avoid resizing the image multiple times when embedding into an album. Thanks to :user:`kerobaros`. :bug:`1028`, :bug:`1036` - :doc:`/plugins/discogs`: Avoid a situation where a trailing comma could be appended to some artist names. :bug:`1049` - The output of the :ref:`stats-cmd` command is slightly different: the approximate size is now marked as such, and the total number of seconds only appears in exact mode. - :doc:`/plugins/convert`: A new ``copy_album_art`` option puts images alongside converted files. Thanks to Ã�ngel Alonso. :bug:`1050`, :bug:`1055` - There is no longer a "conflict" between two plugins that declare the same field with the same type. Thanks to Peter Schnebel. :bug:`1059` :bug:`1061` - :doc:`/plugins/chroma`: Limit the number of releases and recordings fetched as the result of an Acoustid match to avoid extremely long processing times for very popular music. :bug:`1068` - Fix an issue where modifying an album's field without actually changing it would not update the corresponding tracks to bring differing tracks back in line with the album. :bug:`856` - ``echonest`` plugin: When communicating with the Echo Nest servers fails repeatedly, log an error instead of exiting. :bug:`1096` - :doc:`/plugins/lyrics`: Avoid an error when the Google source returns a result without a title. Thanks to Alberto Leal. :bug:`1097` - Importing an archive will no longer leave temporary files behind in ``/tmp``. Thanks to :user:`multikatt`. :bug:`1067`, :bug:`1091` 1.3.8 (September 17, 2014) -------------------------- This release has two big new chunks of functionality. Queries now support **sorting** and user-defined fields can now have **types**. If you want to see all your songs in reverse chronological order, just type ``beet list year-``. It couldn't be easier. For details, see :ref:`query-sort`. Flexible field types mean that some functionality that has previously only worked for built-in fields, like range queries, can now work with plugin- and user-defined fields too. For starters, the ``echonest`` plugin and :doc:`/plugins/mpdstats` now mark the types of the fields they provide---so you can now say, for example, ``beet ls liveness:0.5..1.5`` for the Echo Nest "liveness" attribute. The :doc:`/plugins/types` makes it easy to specify field types in your config file. One upgrade note: if you use the :doc:`/plugins/discogs`, you will need to upgrade the Discogs client library to use this version. Just type ``pip install -U discogs-client``. Other new features ~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/info`: Target files can now be specified through library queries (in addition to filenames). The ``--library`` option prints library fields instead of tags. Multiple files can be summarized together with the new ``--summarize`` option. - :doc:`/plugins/mbcollection`: A new option lets you automatically update your collection on import. Thanks to Olin Gay. - :doc:`/plugins/convert`: A new ``never_convert_lossy_files`` option can prevent lossy transcoding. Thanks to Simon Kohlmeyer. - :doc:`/plugins/convert`: A new ``--yes`` command-line flag skips the confirmation. Still more fixes and little improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Invalid state files don't crash the importer. - :doc:`/plugins/lyrics`: Only strip featured artists and parenthesized title suffixes if no lyrics for the original artist and title were found. - Fix a crash when reading some files with missing tags. - :doc:`/plugins/discogs`: Compatibility with the new 2.0 version of the discogs_client_ Python library. If you were using the old version, you will need to upgrade to the latest version of the library to use the correspondingly new version of the plugin (e.g., with ``pip install -U discogs-client``). Thanks to Andriy Kohut. - Fix a crash when writing files that can't be read. Thanks to Jocelyn De La Rosa. - The :ref:`stats-cmd` command now counts album artists. The album count also more accurately reflects the number of albums in the database. - :doc:`/plugins/convert`: Avoid crashes when tags cannot be written to newly converted files. - Formatting templates with item data no longer confusingly shows album-level data when the two are inconsistent. - Resuming imports and beginning incremental imports should now be much faster when there is a lot of previously-imported music to skip. - :doc:`/plugins/lyrics`: Remove ``<script>`` tags from scraped lyrics. Thanks to Bombardment. - :doc:`/plugins/play`: Add a ``relative_to`` config option. Thanks to BrainDamage. - Fix a crash when a MusicBrainz release has zero tracks. - The ``--version`` flag now works as an alias for the ``version`` command. - :doc:`/plugins/lastgenre`: Remove some unhelpful genres from the default whitelist. Thanks to gwern. - :doc:`/plugins/importfeeds`: A new ``echo`` output mode prints files' paths to standard error. Thanks to robotanarchy. - :doc:`/plugins/replaygain`: Restore some error handling when ``mp3gain`` output cannot be parsed. The verbose log now contains the bad tool output in this case. - :doc:`/plugins/convert`: Fix filename extensions when converting automatically. - The ``write`` plugin event allows plugins to change the tags that are written to a media file. - :doc:`/plugins/zero`: Do not delete database values; only media file tags are affected. .. _discogs_client: https://github.com/discogs/discogs_client 1.3.7 (August 22, 2014) ----------------------- This release of beets fixes all the bugs, and you can be confident that you will never again find any bugs in beets, ever. It also adds support for plain old AIFF files and adds three more plugins, including a nifty one that lets you measure a song's tempo by tapping out the beat on your keyboard. The importer deals more elegantly with duplicates and you can broaden your cover art search to the entire web with Google Image Search. The big new features are ~~~~~~~~~~~~~~~~~~~~~~~~ - Support for AIFF files. Tags are stored as ID3 frames in one of the file's IFF chunks. Thanks to Evan Purkhiser for contributing support to Mutagen_. - The new :doc:`/plugins/importadded` reads files' modification times to set their "added" date. Thanks to Stig Inge Lea Bjørnsen. - The new :doc:`/plugins/bpm` lets you manually measure the tempo of a playing song. Thanks to aroquen. - The new :doc:`/plugins/spotify` generates playlists for your Spotify_ account. Thanks to Olin Gay. - A new :ref:`required` configuration option for the importer skips matches that are missing certain data. Thanks to oprietop. - When the importer detects duplicates, it now shows you some details about the potentially-replaced music so you can make an informed decision. Thanks to Howard Jones. - :doc:`/plugins/fetchart`: You can now optionally search for cover art on Google Image Search. Thanks to Lemutar. - A new :ref:`asciify-paths` configuration option replaces all non-ASCII characters in paths. .. _mutagen: https://github.com/quodlibet/mutagen .. _spotify: https://open.spotify.com/ And the multitude of little improvements and fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Compatibility with the latest version of Mutagen_, 1.23. - :doc:`/plugins/web`: Lyrics now display readably with correct line breaks. Also, the detail view scrolls to reveal all of the lyrics. Thanks to Meet Udeshi. - :doc:`/plugins/play`: The ``command`` config option can now contain arguments (rather than just an executable). Thanks to Alessandro Ghedini. - Fix an error when using the :ref:`modify-cmd` command to remove a flexible attribute. Thanks to Pierre Rust. - :doc:`/plugins/info`: The command now shows audio properties (e.g., bitrate) in addition to metadata. Thanks Alessandro Ghedini. - Avoid a crash on Windows when writing to files with special characters in their names. - :doc:`/plugins/play`: Playing albums now generates filenames by default (as opposed to directories) for better compatibility. The ``use_folders`` option restores the old behavior. Thanks to Lucas Duailibe. - Fix an error when importing an empty directory with the ``--flat`` option. - :doc:`/plugins/mpdstats`: The last song in a playlist is now correctly counted as played. Thanks to Johann Klähn. - :doc:`/plugins/zero`: Prevent accidental nulling of dangerous fields (IDs and paths). Thanks to brunal. - The :ref:`remove-cmd` command now shows the paths of files that will be deleted. Thanks again to brunal. - Don't display changes for fields that are not in the restricted field set. This fixes :ref:`write-cmd` showing changes for fields that are not written to the file. - The :ref:`write-cmd` command avoids displaying the item name if there are no changes for it. - When using both the :doc:`/plugins/convert` and the :doc:`/plugins/scrub`, avoid scrubbing the source file of conversions. (Fix a regression introduced in the previous release.) - :doc:`/plugins/replaygain`: Logging is now quieter during import. Thanks to Yevgeny Bezman. - :doc:`/plugins/fetchart`: When loading art from the filesystem, we now prioritize covers with more keywords in them. This means that ``cover-front.jpg`` will now be taken before ``cover-back.jpg`` because it contains two keywords rather than one. Thanks to Fabrice Laporte. - :doc:`/plugins/lastgenre`: Remove duplicates from canonicalized genre lists. Thanks again to Fabrice Laporte. - The importer now records its progress when skipping albums. This means that incremental imports will no longer try to import albums again after you've chosen to skip them, and erroneous invitations to resume "interrupted" imports should be reduced. Thanks to jcassette. - :doc:`/plugins/bucket`: You can now customize the definition of alphanumeric "ranges" using regular expressions. And the heuristic for detecting years has been improved. Thanks to sotho. - Already-imported singleton tracks are skipped when resuming an import. - :doc:`/plugins/chroma`: A new ``auto`` configuration option disables fingerprinting on import. Thanks to ddettrittus. - :doc:`/plugins/convert`: A new ``--format`` option to can select the transcoding preset from the command-line. - :doc:`/plugins/convert`: Transcoding presets can now omit their filename extensions (extensions default to the name of the preset). - :doc:`/plugins/convert`: A new ``--pretend`` option lets you preview the commands the plugin will execute without actually taking any action. Thanks to Dietrich Daroch. - Fix a crash when a float-valued tag field only contained a ``+`` or ``-`` character. - Fixed a regression in the core that caused the :doc:`/plugins/scrub` not to work in ``auto`` mode. Thanks to Harry Khanna. - The :ref:`write-cmd` command now has a ``--force`` flag. Thanks again to Harry Khanna. - :doc:`/plugins/mbsync`: Track alignment now works with albums that have multiple copies of the same recording. Thanks to Rui Gonçalves. 1.3.6 (May 10, 2014) -------------------- This is primarily a bugfix release, but it also brings two new plugins: one for playing music in desktop players and another for organizing your directories into "buckets." It also brings huge performance optimizations to queries---your ``beet ls`` commands will now go much faster. New features ~~~~~~~~~~~~ - The new :doc:`/plugins/play` lets you start your desktop music player with the songs that match a query. Thanks to David Hamp-Gonsalves. - The new :doc:`/plugins/bucket` provides a ``%bucket{}`` function for path formatting to generate folder names representing ranges of years or initial letter. Thanks to Fabrice Laporte. - Item and album queries are much faster. - :doc:`/plugins/ftintitle`: A new option lets you remove featured artists entirely instead of moving them to the title. Thanks to SUTJael. And those all-important bug fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/mbsync`: Fix a regression in 1.3.5 that broke the plugin entirely. - :ref:`Shell completion <completion>` now searches more common paths for its ``bash_completion`` dependency. - Fix encoding-related logging errors in :doc:`/plugins/convert` and :doc:`/plugins/replaygain`. - :doc:`/plugins/replaygain`: Suppress a deprecation warning emitted by later versions of PyGI. - Fix a crash when reading files whose iTunes SoundCheck tags contain non-ASCII characters. - The ``%if{}`` template function now appropriately interprets the condition as false when it contains the string "false". Thanks to Ayberk Yilmaz. - :doc:`/plugins/convert`: Fix conversion for files that include a video stream by ignoring it. Thanks to brunal. - :doc:`/plugins/fetchart`: Log an error instead of crashing when tag manipulation fails. - :doc:`/plugins/convert`: Log an error instead of crashing when embedding album art fails. - :doc:`/plugins/convert`: Embed cover art into converted files. Previously they were embedded into the source files. - New plugin event: ``before_item_moved``. Thanks to Robert Speicher. 1.3.5 (April 15, 2014) ---------------------- This is a short-term release that adds some great new stuff to beets. There's support for tracking and calculating musical keys, the ReplayGain plugin was expanded to work with more music formats via GStreamer, we can now import directly from compressed archives, and the lyrics plugin is more robust. One note for upgraders and packagers: this version of beets has a new dependency in enum34_, which is a backport of the new enum_ standard library module. The major new features are ~~~~~~~~~~~~~~~~~~~~~~~~~~ - Beets can now import ``zip``, ``tar``, and ``rar`` archives. Just type ``beet import music.zip`` to have beets transparently extract the files to import. - :doc:`/plugins/replaygain`: Added support for calculating ReplayGain values with GStreamer as well the mp3gain program. This enables ReplayGain calculation for any audio format. Thanks to Yevgeny Bezman. - :doc:`/plugins/lyrics`: Lyrics should now be found for more songs. Searching is now sensitive to featured artists and parenthesized title suffixes. When a song has multiple titles, lyrics from all the named songs are now concatenated. Thanks to Fabrice Laporte and Paul Phillips. In particular, a full complement of features for supporting musical keys are new in this release: - A new ``initial_key`` field is available in the database and files' tags. You can set the field manually using a command like ``beet modify initial_key=Am``. - The ``echonest`` plugin sets the ``initial_key`` field if the data is available. - A new :doc:`/plugins/keyfinder` runs a command-line tool to get the key from audio data and store it in the ``initial_key`` field. There are also many bug fixes and little enhancements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ``echonest`` plugin: Truncate files larger than 50MB before uploading for analysis. - :doc:`/plugins/fetchart`: Fix a crash when the server does not specify a content type. Thanks to Lee Reinhardt. - :doc:`/plugins/convert`: The ``--keep-new`` flag now works correctly and the library includes the converted item. - The importer now logs a message instead of crashing when errors occur while opening the files to be imported. - :doc:`/plugins/embedart`: Better error messages in exceptional conditions. - Silenced some confusing error messages when searching for a non-MusicBrainz ID. Using an invalid ID (of any kind---Discogs IDs can be used there too) at the "Enter ID:" importer prompt now just silently returns no results. More info is in the verbose logs. - :doc:`/plugins/mbsync`: Fix application of album-level metadata. Due to a regression a few releases ago, only track-level metadata was being updated. - On Windows, paths on network shares (UNC paths) no longer cause "invalid filename" errors. - :doc:`/plugins/replaygain`: Fix crashes when attempting to log errors. - The :ref:`modify-cmd` command can now accept query arguments that contain = signs. An argument is considered a query part when a : appears before any =s. Thanks to mook. .. _enum: https://docs.python.org/3.4/library/enum.html .. _enum34: https://pypi.org/project/enum34/ 1.3.4 (April 5, 2014) --------------------- This release brings a hodgepodge of medium-sized conveniences to beets. A new :ref:`config-cmd` command manages your configuration, we now have :ref:`bash completion <completion>`, and the :ref:`modify-cmd` command can delete attributes. There are also some significant performance optimizations to the autotagger's matching logic. One note for upgraders: if you use the :doc:`/plugins/fetchart`, it has a new dependency, the requests_ module. New stuff ~~~~~~~~~ - Added a :ref:`config-cmd` command to manage your configuration. It can show you what you currently have in your config file, point you at where the file should be, or launch your text editor to let you modify the file. Thanks to geigerzaehler. - Beets now ships with a shell command completion script! See :ref:`completion`. Thanks to geigerzaehler. - The :ref:`modify-cmd` command now allows removing flexible attributes. For example, ``beet modify artist:beatles oldies!`` deletes the ``oldies`` attribute from matching items. Thanks to brilnius. - Internally, beets has laid the groundwork for supporting multi-valued fields. Thanks to geigerzaehler. - The importer interface now shows the URL for MusicBrainz matches. Thanks to johtso. - :doc:`/plugins/smartplaylist`: Playlists can now be generated from multiple queries (combined with "or" logic). Album-level queries are also now possible and automatic playlist regeneration can now be disabled. Thanks to brilnius. - ``echonest`` plugin: Echo Nest similarity now weights the tempo in better proportion to other metrics. Also, options were added to specify custom thresholds and output formats. Thanks to Adam M. - Added the :ref:`after_write <plugin_events>` plugin event. - :doc:`/plugins/lastgenre`: Separator in genre lists can now be configured. Thanks to brilnius. - We now only use "primary" aliases for artist names from MusicBrainz. This eliminates some strange naming that could occur when the ``languages`` config option was set. Thanks to Filipe Fortes. - The performance of the autotagger's matching mechanism is vastly improved. This should be noticeable when matching against very large releases such as box sets. - The :ref:`import-cmd` command can now accept individual files as arguments even in non-singleton mode. Files are imported as one-track albums. Fixes ~~~~~ - Error messages involving paths no longer escape non-ASCII characters (for legibility). - Fixed a regression that made it impossible to use the :ref:`modify-cmd` command to add new flexible fields. Thanks to brilnius. - ``echonest`` plugin: Avoid crashing when the audio analysis fails. Thanks to Pedro Silva. - :doc:`/plugins/duplicates`: Fix checksumming command execution for files with quotation marks in their names. Thanks again to Pedro Silva. - Fix a crash when importing with both of the :ref:`group_albums` and :ref:`incremental` options enabled. Thanks to geigerzaehler. - Give a sensible error message when ``BEETSDIR`` points to a file. Thanks again to geigerzaehler. - Fix a crash when reading WMA files whose boolean-valued fields contain strings. Thanks to johtso. - :doc:`/plugins/fetchart`: The plugin now sends "beets" as the User-Agent when making scraping requests. This helps resolve some blocked requests. The plugin now also depends on the requests_ Python library. - The :ref:`write-cmd` command now only shows the changes to fields that will actually be written to a file. - :doc:`/plugins/duplicates`: Spurious reports are now avoided for tracks with missing values (e.g., no MBIDs). Thanks to Pedro Silva. - The default :ref:`replace` sanitation options now remove leading whitespace by default. Thanks to brilnius. - :doc:`/plugins/importfeeds`: Fix crash when importing albums containing ``/`` with the ``m3u_multi`` format. - Avoid crashing on Mutagen bugs while writing files' tags. - :doc:`/plugins/convert`: Display a useful error message when the FFmpeg executable can't be found. .. _requests: https://requests.readthedocs.io/en/latest/ 1.3.3 (February 26, 2014) ------------------------- Version 1.3.3 brings a bunch changes to how item and album fields work internally. Along with laying the groundwork for some great things in the future, this brings a number of improvements to how you interact with beets. Here's what's new with fields in particular: - Plugin-provided fields can now be used in queries. For example, if you use the :doc:`/plugins/inline` to define a field called ``era``, you can now filter your library based on that field by typing something like ``beet list era:goldenage``. - Album-level flexible attributes and plugin-provided attributes can now be used in path formats (and other item-level templates). - :ref:`Date-based queries <datequery>` are now possible. Try getting every track you added in February 2014 with ``beet ls added:2014-02`` or in the whole decade with ``added:2010..``. Thanks to Stig Inge Lea Bjørnsen. - The :ref:`modify-cmd` command is now better at parsing and formatting fields. You can assign to boolean fields like ``comp``, for example, using either the words "true" or "false" or the numerals 1 and 0. Any boolean-esque value is normalized to a real boolean. The :ref:`update-cmd` and :ref:`write-cmd` commands also got smarter at formatting and colorizing changes. For developers, the short version of the story is that Item and Album objects provide *uniform access* across fixed, flexible, and computed attributes. You can write ``item.foo`` to access the ``foo`` field without worrying about where the data comes from. Unrelated new stuff ~~~~~~~~~~~~~~~~~~~ - The importer has a new interactive option (*G* for "Group albums"), command-line flag (``--group-albums``), and config option (:ref:`group_albums`) that lets you split apart albums that are mixed together in a single directory. Thanks to geigerzaehler. - A new ``--config`` command-line option lets you specify an additional configuration file. This option *combines* config settings with your default config file. (As part of this change, the ``BEETSDIR`` environment variable no longer combines---it *replaces* your default config file.) Thanks again to geigerzaehler. - :doc:`/plugins/ihate`: The plugin's configuration interface was overhauled. Its configuration is now much simpler---it uses beets queries instead of an ad-hoc per-field configuration. This is *backwards-incompatible*---if you use this plugin, you will need to update your configuration. Thanks to BrainDamage. Other little fixes ~~~~~~~~~~~~~~~~~~ - ``echonest`` plugin: Tempo (BPM) is now always stored as an integer. Thanks to Heinz Wiesinger. - Fix Python 2.6 compatibility in some logging statements in :doc:`/plugins/chroma` and :doc:`/plugins/lastgenre`. - Prevent some crashes when things go really wrong when writing file metadata at the end of the import process. - New plugin events: ``item_removed`` (thanks to Romuald Conty) and ``item_copied`` (thanks to Stig Inge Lea Bjørnsen). - The ``pluginpath`` config option can now point to the directory containing plugin code. (Previously, it awkwardly needed to point at a directory containing a ``beetsplug`` directory, which would then contain your code. This is preserved as an option for backwards compatibility.) This change should also work around a long-standing issue when using ``pluginpath`` when beets is installed using pip. Many thanks to geigerzaehler. - :doc:`/plugins/web`: The ``/item/`` and ``/album/`` API endpoints now produce full details about albums and items, not just lists of IDs. Thanks to geigerzaehler. - Fix a potential crash when using image resizing with the :doc:`/plugins/fetchart` or :doc:`/plugins/embedart` without ImageMagick installed. - Also, when invoking ``convert`` for image resizing fails, we now log an error instead of crashing. - :doc:`/plugins/fetchart`: The ``beet fetchart`` command can now associate local images with albums (unless ``--force`` is provided). Thanks to brilnius. - :doc:`/plugins/fetchart`: Command output is now colorized. Thanks again to brilnius. - The :ref:`modify-cmd` command avoids writing files and committing to the database when nothing has changed. Thanks once more to brilnius. - The importer now uses the album artist field when guessing existing metadata for albums (rather than just the track artist field). Thanks to geigerzaehler. - :doc:`/plugins/fromfilename`: Fix a crash when a filename contained only a track number (e.g., ``02.mp3``). - :doc:`/plugins/convert`: Transcoding should now work on Windows. - :doc:`/plugins/duplicates`: The ``move`` and ``copy`` destination arguments are now treated as directories. Thanks to Pedro Silva. - The :ref:`modify-cmd` command now skips confirmation and prints a message if no changes are necessary. Thanks to brilnius. - :doc:`/plugins/fetchart`: When using the ``remote_priority`` config option, local image files are no longer completely ignored. - ``echonest`` plugin: Fix an issue causing the plugin to appear twice in the output of the ``beet version`` command. - :doc:`/plugins/lastgenre`: Fix an occasional crash when no tag weight was returned by Last.fm. - :doc:`/plugins/mpdstats`: Restore the ``last_played`` field. Thanks to Johann Klähn. - The :ref:`modify-cmd` command's output now clearly shows when a file has been deleted. - Album art in files with Vorbis Comments is now marked with the "front cover" type. Thanks to Jason Lefley. 1.3.2 (December 22, 2013) ------------------------- This update brings new plugins for fetching acoustic metrics and listening statistics, many more options for the duplicate detection plugin, and flexible options for fetching multiple genres. The "core" of beets gained a new built-in command: :ref:`beet write <write-cmd>` updates the metadata tags for files, bringing them back into sync with your database. Thanks to Heinz Wiesinger. We added some plugins and overhauled some existing ones ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The new ``echonest`` plugin plugin can fetch a wide range of `acoustic attributes`_ from `The Echo Nest`_, including the "speechiness" and "liveness" of each track. The new plugin supersedes an older version (``echonest_tempo``) that only fetched the BPM field. Thanks to Pedro Silva and Peter Schnebel. - The :doc:`/plugins/duplicates` got a number of new features, thanks to Pedro Silva: - The ``keys`` option lets you specify the fields used detect duplicates. - You can now use checksumming (via an external command) to find duplicates instead of metadata via the ``checksum`` option. - The plugin can perform actions on the duplicates it find. The new ``copy``, ``move``, ``delete``, ``delete_file``, and ``tag`` options perform those actions. - The new :doc:`/plugins/mpdstats` collects statistics about your listening habits from MPD_. Thanks to Peter Schnebel and Johann Klähn. - :doc:`/plugins/lastgenre`: The new ``multiple`` option has been replaced with the ``count`` option, which lets you limit the number of genres added to your music. (No more thousand-character genre fields!) Also, the ``min_weight`` field filters out nonsense tags to make your genres more relevant. Thanks to Peter Schnebel and rashley60. - :doc:`/plugins/lyrics`: A new ``--force`` option optionally re-downloads lyrics even when files already have them. Thanks to Bitdemon. As usual, there are also innumerable little fixes and improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - When writing ID3 tags for ReplayGain normalization, tags are written with both upper-case and lower-case TXXX frame descriptions. Previous versions of beets used only the upper-case style, which seems to be more standard, but some players (namely, Quod Libet and foobar2000) seem to only use lower-case names. - :doc:`/plugins/missing`: Avoid a possible error when an album's ``tracktotal`` field is missing. - :doc:`/plugins/ftintitle`: Fix an error when the sort artist is missing. - ``echonest_tempo``: The plugin should now match songs more reliably (i.e., fewer "no tempo found" messages). Thanks to Peter Schnebel. - :doc:`/plugins/convert`: Fix an "Item has no library" error when using the ``auto`` config option. - :doc:`/plugins/convert`: Fix an issue where files of the wrong format would have their transcoding skipped (and files with the right format would be needlessly transcoded). Thanks to Jakob Schnitzer. - Fix an issue that caused the :ref:`id3v23` option to work only occasionally. - Also fix using :ref:`id3v23` in conjunction with the ``scrub`` and ``embedart`` plugins. Thanks to Chris Cogburn. - :doc:`/plugins/ihate`: Fix an error when importing singletons. Thanks to Mathijs de Bruin. - The :ref:`clutter` option can now be a whitespace-separated list in addition to a YAML list. - Values for the :ref:`replace` option can now be empty (i.e., null is equivalent to the empty string). - :doc:`/plugins/lastgenre`: Fix a conflict between canonicalization and multiple genres. - When a match has a year but not a month or day, the autotagger now "zeros out" the month and day fields after applying the year. - For plugin developers: added an ``optparse`` callback utility function for performing actions based on arguments. Thanks to Pedro Silva. - :doc:`/plugins/scrub`: Fix scrubbing of MPEG-4 files. Thanks to Yevgeny Bezman. .. _acoustic attributes: https://web.archive.org/web/20160701063109/http://developer.echonest.com/acoustic-attributes.html .. _mpd: https://www.musicpd.org/ 1.3.1 (October 12, 2013) ------------------------ This release boasts a host of new little features, many of them contributed by beets' amazing and prolific community. It adds support for Opus_ files, transcoding to any format, and two new plugins: one that guesses metadata for "blank" files based on their filenames and one that moves featured artists into the title field. Here's the new stuff ~~~~~~~~~~~~~~~~~~~~ - Add Opus_ audio support. Thanks to Rowan Lewis. - :doc:`/plugins/convert`: You can now transcode files to any audio format, rather than just MP3. Thanks again to Rowan Lewis. - The new :doc:`/plugins/fromfilename` guesses tags from the filenames during import when metadata tags themselves are missing. Thanks to Jan-Erik Dahlin. - The :doc:`/plugins/ftintitle`, by `@Verrus`_, is now distributed with beets. It helps you rewrite tags to move "featured" artists from the artist field to the title field. - The MusicBrainz data source now uses track artists over recording artists. This leads to better metadata when tagging classical music. Thanks to Henrique Ferreiro. - :doc:`/plugins/lastgenre`: You can now get multiple genres per album or track using the ``multiple`` config option. Thanks to rashley60 on GitHub. - A new :ref:`id3v23` config option makes beets write MP3 files' tags using the older ID3v2.3 metadata standard. Use this if you want your tags to be visible to Windows and some older players. And some fixes ~~~~~~~~~~~~~~ - :doc:`/plugins/fetchart`: Better error message when the image file has an unrecognized type. - :doc:`/plugins/mbcollection`: Detect, log, and skip invalid MusicBrainz IDs (instead of failing with an API error). - :doc:`/plugins/info`: Fail gracefully when used erroneously with a directory. - ``echonest_tempo``: Fix an issue where the plugin could use the tempo from the wrong song when the API did not contain the requested song. - Fix a crash when a file's metadata included a very large number (one wider than 64 bits). These huge numbers are now replaced with zeroes in the database. - When a track on a MusicBrainz release has a different length from the underlying recording's length, the track length is now used instead. - With :ref:`per_disc_numbering` enabled, the ``tracktotal`` field is now set correctly (i.e., to the number of tracks on the disc). - :doc:`/plugins/scrub`: The ``scrub`` command now restores album art in addition to other (database-backed) tags. - :doc:`/plugins/mpdupdate`: Domain sockets can now begin with a tilde (which is correctly expanded to ``$HOME``) as well as a slash. Thanks to Johann Klähn. - :doc:`/plugins/lastgenre`: Fix a regression that could cause new genres found during import not to be persisted. - Fixed a crash when imported album art was also marked as "clutter" where the art would be deleted before it could be moved into place. This led to a "image.jpg not found during copy" error. Now clutter is removed (and directories pruned) much later in the process, after the ``import_task_files`` hook. - :doc:`/plugins/missing`: Fix an error when printing missing track names. Thanks to Pedro Silva. - Fix an occasional KeyError in the :ref:`update-cmd` command introduced in 1.3.0. - :doc:`/plugins/scrub`: Avoid preserving certain non-standard ID3 tags such as NCON. .. _@verrus: https://github.com/Verrus .. _opus: https://www.opus-codec.org/ 1.3.0 (September 11, 2013) -------------------------- Albums and items now have **flexible attributes**. This means that, when you want to store information about your music in the beets database, you're no longer constrained to the set of fields it supports out of the box (title, artist, track, etc.). Instead, you can use any field name you can think of and treat it just like the built-in fields. For example, you can use the :ref:`modify-cmd` command to set a new field on a track: :: $ beet modify mood=sexy artist:miguel and then query your music based on that field: :: $ beet ls mood:sunny or use templates to see the value of the field: :: $ beet ls -f '$title: $mood' While this feature is nifty when used directly with the usual command-line suspects, it's especially useful for plugin authors and for future beets features. Stay tuned for great things built on this flexible attribute infrastructure. One side effect of this change: queries that include unknown fields will now match *nothing* instead of *everything*. So if you type ``beet ls fieldThatDoesNotExist:foo``, beets will now return no results, whereas previous versions would spit out a warning and then list your entire library. There's more detail than you could ever need `on the beets blog`_. .. _on the beets blog: https://beets.io/blog/flexattr.html 1.2.2 (August 27, 2013) ----------------------- This is a bugfix release. We're in the midst of preparing for a large change in beets 1.3, so 1.2.2 resolves some issues that came up over the last few weeks. Stay tuned! The improvements in this release are ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - A new plugin event, ``item_moved``, is sent when files are moved on disk. Thanks to dsedivec. - :doc:`/plugins/lyrics`: More improvements to the Google backend by Fabrice Laporte. - :doc:`/plugins/bpd`: Fix for a crash when searching, thanks to Simon Chopin. - Regular expression queries (and other query types) over paths now work. (Previously, special query types were ignored for the ``path`` field.) - :doc:`/plugins/fetchart`: Look for images in the Cover Art Archive for the release group in addition to the specific release. Thanks to Filipe Fortes. - Fix a race in the importer that could cause files to be deleted before they were imported. This happened when importing one album, importing a duplicate album, and then asking for the first album to be replaced with the second. The situation could only arise when importing music from the library directory and when the two albums are imported close in time. 1.2.1 (June 22, 2013) --------------------- This release introduces a major internal change in the way that similarity scores are handled. It means that the importer interface can now show you exactly why a match is assigned its score and that the autotagger gained a few new options that let you customize how matches are prioritized and recommended. The refactoring work is due to the continued efforts of Tai Lee. The changes you'll notice while using the autotagger are: - The top 3 distance penalties are now displayed on the release listing, and all album and track penalties are now displayed on the track changes list. This should make it clear exactly which metadata is contributing to a low similarity score. - When displaying differences, the colorization has been made more consistent and helpful: red for an actual difference, yellow to indicate that a distance penalty is being applied, and light gray for no penalty (e.g., case changes) or disambiguation data. There are also three new (or overhauled) configuration options that let you customize the way that matches are selected: - The :ref:`ignored` setting lets you instruct the importer not to show you matches that have a certain penalty applied. - The :ref:`preferred` collection of settings specifies a sorted list of preferred countries and media types, or prioritizes releases closest to the original year for an album. - The :ref:`max_rec` settings can now be used for any distance penalty component. The recommendation will be downgraded if a non-zero penalty is being applied to the specified field. And some little enhancements and bug fixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Multi-disc directory names can now contain "disk" (in addition to "disc"). Thanks to John Hawthorn. - :doc:`/plugins/web`: Item and album counts are now exposed through the API for use with the Tomahawk resolver. Thanks to Uwe L. Korn. - Python 2.6 compatibility for ``beatport``, :doc:`/plugins/missing`, and :doc:`/plugins/duplicates`. Thanks to Wesley Bitter and Pedro Silva. - Don't move the config file during a null migration. Thanks to Theofilos Intzoglou. - Fix an occasional crash in the ``beatport`` when a length field was missing from the API response. Thanks to Timothy Appnel. - :doc:`/plugins/scrub`: Handle and log I/O errors. - :doc:`/plugins/lyrics`: The Google backend should now turn up more results. Thanks to Fabrice Laporte. - :doc:`/plugins/random`: Fix compatibility with Python 2.6. Thanks to Matthias Drochner. 1.2.0 (June 5, 2013) -------------------- There's a *lot* of new stuff in this release: new data sources for the autotagger, new plugins to look for problems in your library, tracking the date that you acquired new music, an awesome new syntax for doing queries over numeric fields, support for ALAC files, and major enhancements to the importer's UI and distance calculations. A special thanks goes out to all the contributors who helped make this release awesome. For the first time, beets can now tag your music using additional **data sources** to augment the matches from MusicBrainz. When you enable either of these plugins, the importer will start showing you new kinds of matches: - New :doc:`/plugins/discogs`: Get matches from the Discogs_ database. Thanks to Artem Ponomarenko and Tai Lee. - New ``beatport`` plugin: Get matches from the Beatport_ database. Thanks to Johannes Baiter. We also have two other new plugins that can scan your library to check for common problems, both by Pedro Silva: - New :doc:`/plugins/duplicates`: Find tracks or albums in your library that are **duplicated**. - New :doc:`/plugins/missing`: Find albums in your library that are **missing tracks**. There are also three more big features added to beets core ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Your library now keeps track of **when music was added** to it. The new ``added`` field is a timestamp reflecting when each item and album was imported and the new ``%time{}`` template function lets you format this timestamp for humans. Thanks to Lucas Duailibe. - When using queries to match on quantitative fields, you can now use **numeric ranges**. For example, you can get a list of albums from the '90s by typing ``beet ls year:1990..1999`` or find high-bitrate music with ``bitrate:128000..``. See :ref:`numericquery`. Thanks to Michael Schuerig. - **ALAC files** are now marked as ALAC instead of being conflated with AAC audio. Thanks to Simon Luijk. In addition, the importer saw various UI enhancements, thanks to Tai Lee ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - More consistent format and colorization of album and track metadata. - Display data source URL for matches from the new data source plugins. This should make it easier to migrate data from Discogs or Beatport into MusicBrainz. - Display album disambiguation and disc titles in the track listing, when available. - Track changes are highlighted in yellow when they indicate a change in format to or from the style of :ref:`per_disc_numbering`. (As before, no penalty is applied because the track number is still "correct", just in a different format.) - Sort missing and unmatched tracks by index and title and group them together for better readability. - Indicate MusicBrainz ID mismatches. The calculation of the similarity score for autotagger matches was also improved, again thanks to Tai Lee. These changes, in general, help deal with the new metadata sources and help disambiguate between similar releases in the same MusicBrainz release group: - Strongly prefer releases with a matching MusicBrainz album ID. This helps beets re-identify the same release when re-importing existing files. - Prefer releases that are closest to the tagged ``year``. Tolerate files tagged with release or original year. - The new ``preferred_media`` config option lets you prefer a certain media type when the ``media`` field is unset on an album. - Apply minor penalties across a range of fields to differentiate between nearly identical releases: ``disctotal``, ``label``, ``catalognum``, ``country`` and ``albumdisambig``. As usual, there were also lots of other great littler enhancements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/random`: A new ``-e`` option gives an equal chance to each artist in your collection to avoid biasing random samples to prolific artists. Thanks to Georges Dubus. - The :ref:`modify-cmd` now correctly converts types when modifying non-string fields. You can now safely modify the "comp" flag and the "year" field, for example. Thanks to Lucas Duailibe. - :doc:`/plugins/convert`: You can now configure the path formats for converted files separately from your main library. Thanks again to Lucas Duailibe. - The importer output now shows the number of audio files in each album. Thanks to jayme on GitHub. - Plugins can now provide fields for both Album and Item templates, thanks to Pedro Silva. Accordingly, the :doc:`/plugins/inline` can also now define album fields. For consistency, the ``pathfields`` configuration section has been renamed ``item_fields`` (although the old name will still work for compatibility). - Plugins can also provide metadata matches for ID searches. For example, the new Discogs plugin lets you search for an album by its Discogs ID from the same prompt that previously just accepted MusicBrainz IDs. Thanks to Johannes Baiter. - The :ref:`fields-cmd` command shows template fields provided by plugins. Thanks again to Pedro Silva. - :doc:`/plugins/mpdupdate`: You can now communicate with MPD over a Unix domain socket. Thanks to John Hawthorn. And a batch of fixes ~~~~~~~~~~~~~~~~~~~~ - Album art filenames now respect the :ref:`replace` configuration. - Friendly error messages are now printed when trying to read or write files that go missing. - The :ref:`modify-cmd` command can now change albums' album art paths (i.e., ``beet modify artpath=...`` works). Thanks to Lucas Duailibe. - :doc:`/plugins/zero`: Fix a crash when nulling out a field that contains None. - Templates can now refer to non-tag item fields (e.g., ``$id`` and ``$album_id``). - :doc:`/plugins/lyrics`: Lyrics searches should now turn up more results due to some fixes in dealing with special characters. .. _beatport: https://www.beatport.com/ .. _discogs: https://discogs.com/ 1.1.0 (April 29, 2013) ---------------------- This final release of 1.1 brings a little polish to the betas that introduced the new configuration system. The album art and lyrics plugins also got a little love. If you're upgrading from 1.0.0 or earlier, this release (like the 1.1 betas) will automatically migrate your configuration to the new system. - :doc:`/plugins/embedart`: The ``embedart`` command now embeds each album's associated art by default. The ``--file`` option invokes the old behavior, in which a specific image file is used. - :doc:`/plugins/lyrics`: A new (optional) Google Custom Search backend was added for finding lyrics on a wide array of sites. Thanks to Fabrice Laporte. - When automatically detecting the filesystem's maximum filename length, never guess more than 200 characters. This prevents errors on systems where the maximum length was misreported. You can, of course, override this default with the :ref:`max_filename_length` option. - :doc:`/plugins/fetchart`: Two new configuration options were added: ``cover_names``, the list of keywords used to identify preferred images, and ``cautious``, which lets you avoid falling back to images that don't contain those keywords. Thanks to Fabrice Laporte. - Avoid some error cases in the ``update`` command and the ``embedart`` and ``mbsync`` plugins. Invalid or missing files now cause error logs instead of crashing beets. Thanks to Lucas Duailibe. - :doc:`/plugins/lyrics`: Searches now strip "featuring" artists when searching for lyrics, which should increase the hit rate for these tracks. Thanks to Fabrice Laporte. - When listing the items in an album, the items are now always in track-number order. This should lead to more predictable listings from the :doc:`/plugins/importfeeds`. - :doc:`/plugins/smartplaylist`: Queries are now split using shell-like syntax instead of just whitespace, so you can now construct terms that contain spaces. - :doc:`/plugins/lastgenre`: The ``force`` config option now defaults to true and controls the behavior of the import hook. (Previously, new genres were always forced during import.) - :doc:`/plugins/web`: Fix an error when specifying the hostname on the command line. - :doc:`/plugins/web`: The underlying API was expanded slightly to support Tomahawk_ collections. And file transfers now have a "Content-Length" header. Thanks to Uwe L. Korn. - :doc:`/plugins/lastgenre`: Fix an error when using genre canonicalization. .. _tomahawk: https://github.com/tomahawk-player/tomahawk 1.1b3 (March 16, 2013) ---------------------- This third beta of beets 1.1 brings a hodgepodge of little new features (and internal overhauls that will make improvements easier in the future). There are new options for getting metadata in a particular language and seeing more detail during the import process. There's also a new plugin for synchronizing your metadata with MusicBrainz. Under the hood, plugins can now extend the query syntax. New configuration options ~~~~~~~~~~~~~~~~~~~~~~~~~ - :ref:`languages` controls the preferred languages when selecting an alias from MusicBrainz. This feature requires python-musicbrainzngs_ 0.3 or later. Thanks to Sam Doshi. - :ref:`detail` enables a mode where all tracks are listed in the importer UI, as opposed to only changed tracks. - The ``--flat`` option to the ``beet import`` command treats an entire directory tree of music files as a single album. This can help in situations where a multi-disc album is split across multiple directories. - :doc:`/plugins/importfeeds`: An option was added to use absolute, rather than relative, paths. Thanks to Lucas Duailibe. Other stuff ~~~~~~~~~~~ - A new :doc:`/plugins/mbsync` provides a command that looks up each item and track in MusicBrainz and updates your library to reflect it. This can help you easily correct errors that have been fixed in the MB database. Thanks to Jakob Schnitzer. - :doc:`/plugins/fuzzy`: The ``fuzzy`` command was removed and replaced with a new query type. To perform fuzzy searches, use the ``~`` prefix with :ref:`list-cmd` or other commands. Thanks to Philippe Mongeau. - As part of the above, plugins can now extend the query syntax and new kinds of matching capabilities to beets. See :ref:`extend-query`. Thanks again to Philippe Mongeau. - :doc:`/plugins/convert`: A new ``--keep-new`` option lets you store transcoded files in your library while backing up the originals (instead of vice-versa). Thanks to Lucas Duailibe. - :doc:`/plugins/convert`: Also, a new ``auto`` config option will transcode audio files automatically during import. Thanks again to Lucas Duailibe. - :doc:`/plugins/chroma`: A new ``fingerprint`` command lets you generate and store fingerprints for items that don't yet have them. One more round of applause for Lucas Duailibe. - ``echonest_tempo``: API errors now issue a warning instead of exiting with an exception. We also avoid an error when track metadata contains newlines. - When the importer encounters an error (insufficient permissions, for example) when walking a directory tree, it now logs an error instead of crashing. - In path formats, null database values now expand to the empty string instead of the string "None". - Add "System Volume Information" (an internal directory found on some Windows filesystems) to the default ignore list. - Fix a crash when ReplayGain values were set to null. - Fix a crash when iTunes Sound Check tags contained invalid data. - Fix an error when the configuration file (``config.yaml``) is completely empty. - Fix an error introduced in 1.1b1 when importing using timid mode. Thanks to Sam Doshi. - :doc:`/plugins/convert`: Fix a bug when creating files with Unicode pathnames. - Fix a spurious warning from the Unidecode module when matching albums that are missing all metadata. - Fix Unicode errors when a directory or file doesn't exist when invoking the import command. Thanks to Lucas Duailibe. - :doc:`/plugins/mbcollection`: Show friendly, human-readable errors when MusicBrainz exceptions occur. - ``echonest_tempo``: Catch socket errors that are not handled by the Echo Nest library. - :doc:`/plugins/chroma`: Catch Acoustid Web service errors when submitting fingerprints. 1.1b2 (February 16, 2013) ------------------------- The second beta of beets 1.1 uses the fancy new configuration infrastructure to add many, many new config options. The import process is more flexible; filenames can be customized in more detail; and more. This release also supports Windows Media (ASF) files and iTunes Sound Check volume normalization. This version introduces one **change to the default behavior** that you should be aware of. Previously, when importing new albums matched in MusicBrainz, the date fields (``year``, ``month``, and ``day``) would be set to the release date of the *original* version of the album, as opposed to the specific date of the release selected. Now, these fields reflect the specific release and ``original_year``, etc., reflect the earlier release date. If you want the old behavior, just set :ref:`original_date` to true in your config file. New configuration options ~~~~~~~~~~~~~~~~~~~~~~~~~ - :ref:`default_action` lets you determine the default (just-hit-return) option is when considering a candidate. - :ref:`none_rec_action` lets you skip the prompt, and automatically choose an action, when there is no good candidate. Thanks to Tai Lee. - :ref:`max_rec` lets you define a maximum recommendation for albums with missing/extra tracks or differing track lengths/numbers. Thanks again to Tai Lee. - :ref:`original_date` determines whether, when importing new albums, the ``year``, ``month``, and ``day`` fields should reflect the specific (e.g., reissue) release date or the original release date. Note that the original release date is always available as ``original_year``, etc. - :ref:`clutter` controls which files should be ignored when cleaning up empty directories. Thanks to Steinþór Pálsson. - :doc:`/plugins/lastgenre`: A new configuration option lets you choose to retrieve artist-level tags as genres instead of album- or track-level tags. Thanks to Peter Fern and Peter Schnebel. - :ref:`max_filename_length` controls truncation of long filenames. Also, beets now tries to determine the filesystem's maximum length automatically if you leave this option unset. - :doc:`/plugins/fetchart`: The ``remote_priority`` option searches remote (Web) art sources even when local art is present. - You can now customize the character substituted for path separators (e.g., /) in filenames via ``path_sep_replace``. The default is an underscore. Use this setting with caution. Other new stuff ~~~~~~~~~~~~~~~ - Support for Windows Media/ASF audio files. Thanks to Dave Hayes. - New :doc:`/plugins/smartplaylist`: generate and maintain m3u playlist files based on beets queries. Thanks to Dang Mai Hai. - ReplayGain tags on MPEG-4/AAC files are now supported. And, even more astonishingly, ReplayGain values in MP3 and AAC files are now compatible with `iTunes Sound Check`_. Thanks to Dave Hayes. - Track titles in the importer UI's difference display are now either aligned vertically or broken across two lines for readability. Thanks to Tai Lee. - Albums and items have new fields reflecting the *original* release date (``original_year``, ``original_month``, and ``original_day``). Previously, when tagging from MusicBrainz, *only* the original date was stored; now, the old fields refer to the *specific* release date (e.g., when the album was reissued). - Some changes to the way candidates are recommended for selection, thanks to Tai Lee: - According to the new :ref:`max_rec` configuration option, partial album matches are downgraded to a "low" recommendation by default. - When a match isn't great but is either better than all the others or the only match, it is given a "low" (rather than "medium") recommendation. - There is no prompt default (i.e., input is required) when matches are bad: "low" or "none" recommendations or when choosing a candidate other than the first. - The importer's heuristic for coalescing the directories in a multi-disc album has been improved. It can now detect when two directories alongside each other share a similar prefix but a different number (e.g., "Album Disc 1" and "Album Disc 2") even when they are not alone in a common parent directory. Thanks once again to Tai Lee. - Album listings in the importer UI now show the release medium (CD, Vinyl, 3xCD, etc.) as well as the disambiguation string. Thanks to Peter Schnebel. - :doc:`/plugins/lastgenre`: The plugin can now get different genres for individual tracks on an album. Thanks to Peter Schnebel. - When getting data from MusicBrainz, the album disambiguation string (``albumdisambig``) now reflects both the release and the release group. - :doc:`/plugins/mpdupdate`: Sends an update message whenever *anything* in the database changes---not just when importing. Thanks to Dang Mai Hai. - When the importer UI shows a difference in track numbers or durations, they are now colorized based on the *suffixes* that differ. For example, when showing the difference between 2:01 and 2:09, only the last digit will be highlighted. - The importer UI no longer shows a change when the track length difference is less than 10 seconds. (This threshold was previously 2 seconds.) - Two new plugin events were added: *database_change* and *cli_exit*. Thanks again to Dang Mai Hai. - Plugins are now loaded in the order they appear in the config file. Thanks to Dang Mai Hai. - :doc:`/plugins/bpd`: Browse by album artist and album artist sort name. Thanks to Steinþór Pálsson. - ``echonest_tempo``: Don't attempt a lookup when the artist or track title is missing. - Fix an error when migrating the ``.beetsstate`` file on Windows. - A nicer error message is now given when the configuration file contains tabs. (YAML doesn't like tabs.) - Fix the ``-l`` (log path) command-line option for the ``import`` command. .. _itunes sound check: https://support.apple.com/itunes 1.1b1 (January 29, 2013) ------------------------ This release entirely revamps beets' configuration system. The configuration file is now a YAML_ document and is located, along with other support files, in a common directory (e.g., ``~/.config/beets`` on Unix-like systems). .. _yaml: https://en.wikipedia.org/wiki/YAML - Renamed plugins: The ``rdm`` plugin has been renamed to ``random`` and ``fuzzy_search`` has been renamed to ``fuzzy``. - Renamed config options: Many plugins have a flag dictating whether their action runs at import time. This option had many names (``autofetch``, ``autoembed``, etc.) but is now consistently called ``auto``. - Reorganized import config options: The various ``import_*`` options are now organized under an ``import:`` heading and their prefixes have been removed. - New default file locations: The default filename of the library database is now ``library.db`` in the same directory as the config file, as opposed to ``~/.beetsmusic.blb`` previously. Similarly, the runtime state file is now called ``state.pickle`` in the same directory instead of ``~/.beetsstate``. It also adds some new features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :doc:`/plugins/inline`: Inline definitions can now contain statements or blocks in addition to just expressions. Thanks to Florent Thoumie. - Add a configuration option, :ref:`terminal_encoding`, controlling the text encoding used to print messages to standard output. - The MusicBrainz hostname (and rate limiting) are now configurable. See :ref:`musicbrainz-config`. - You can now configure the similarity thresholds used to determine when the autotagger automatically accepts a metadata match. See :ref:`match-config`. - :doc:`/plugins/importfeeds`: Added a new configuration option that controls the base for relative paths used in m3u files. Thanks to Philippe Mongeau. 1.0.0 (January 29, 2013) ------------------------ After fifteen betas and two release candidates, beets has finally hit one-point-oh. Congratulations to everybody involved. This version of beets will remain stable and receive only bug fixes from here on out. New development is ongoing in the betas of version 1.1. - :doc:`/plugins/scrub`: Fix an incompatibility with Python 2.6. - :doc:`/plugins/lyrics`: Fix an issue that failed to find lyrics when metadata contained "real" apostrophes. - :doc:`/plugins/replaygain`: On Windows, emit a warning instead of crashing when analyzing non-ASCII filenames. - Silence a spurious warning from version 0.04.12 of the Unidecode module. 1.0rc2 (December 31, 2012) -------------------------- This second release candidate follows quickly after rc1 and fixes a few small bugs found since that release. There were a couple of regressions and some bugs in a newly added plugin. - ``echonest_tempo``: If the Echo Nest API limit is exceeded or a communication error occurs, the plugin now waits and tries again instead of crashing. Thanks to Zach Denton. - :doc:`/plugins/fetchart`: Fix a regression that caused crashes when art was not available from some sources. - Fix a regression on Windows that caused all relative paths to be "not found". 1.0rc1 (December 17, 2012) -------------------------- The first release candidate for beets 1.0 includes a deluge of new features contributed by beets users. The vast majority of the credit for this release goes to the growing and vibrant beets community. A million thanks to everybody who contributed to this release. There are new plugins for transcoding music, fuzzy searches, tempo collection, and fiddling with metadata. The ReplayGain plugin has been rebuilt from scratch. Album art images can now be resized automatically. Many other smaller refinements make things "just work" as smoothly as possible. With this release candidate, beets 1.0 is feature-complete. We'll be fixing bugs on the road to 1.0 but no new features will be added. Concurrently, work begins today on features for version 1.1. - New plugin: :doc:`/plugins/convert` **transcodes** music and embeds album art while copying to a separate directory. Thanks to Jakob Schnitzer and Andrew G. Dunn. - New plugin: :doc:`/plugins/fuzzy` lets you find albums and tracks using **fuzzy string matching** so you don't have to type (or even remember) their exact names. Thanks to Philippe Mongeau. - New plugin: ``echonest_tempo`` fetches **tempo** (BPM) information from `The Echo Nest`_. Thanks to David Brenner. - New plugin: :doc:`/plugins/the` adds a template function that helps format text for nicely-sorted directory listings. Thanks to Blemjhoo Tezoulbr. - New plugin: :doc:`/plugins/zero` **filters out undesirable fields** before they are written to your tags. Thanks again to Blemjhoo Tezoulbr. - New plugin: :doc:`/plugins/ihate` automatically skips (or warns you about) importing albums that match certain criteria. Thanks once again to Blemjhoo Tezoulbr. - :doc:`/plugins/replaygain`: This plugin has been completely overhauled to use the mp3gain_ or aacgain_ command-line tools instead of the failure-prone Gstreamer ReplayGain implementation. Thanks to Fabrice Laporte. - :doc:`/plugins/fetchart` and :doc:`/plugins/embedart`: Both plugins can now **resize album art** to avoid excessively large images. Use the ``maxwidth`` config option with either plugin. Thanks to Fabrice Laporte. - :doc:`/plugins/scrub`: Scrubbing now removes *all* types of tags from a file rather than just one. For example, if your FLAC file has both ordinary FLAC tags and ID3 tags, the ID3 tags are now also removed. - :ref:`stats-cmd` command: New ``--exact`` switch to make the file size calculation more accurate (thanks to Jakob Schnitzer). - :ref:`list-cmd` command: Templates given with ``-f`` can now show items' and albums' paths (using ``$path``). - The output of the :ref:`update-cmd`, :ref:`remove-cmd`, and :ref:`modify-cmd` commands now respects the :ref:`list_format_album` and :ref:`list_format_item` config options. Thanks to Mike Kazantsev. - The :ref:`art-filename` option can now be a template rather than a simple string. Thanks to Jarrod Beardwood. - Fix album queries for ``artpath`` and other non-item fields. - Null values in the database can now be matched with the empty-string regular expression, ``^$``. - Queries now correctly match non-string values in path format predicates. - When autotagging a various-artists album, the album artist field is now used instead of the majority track artist. - :doc:`/plugins/lastgenre`: Use the albums' existing genre tags if they pass the whitelist (thanks to Fabrice Laporte). - :doc:`/plugins/lastgenre`: Add a ``lastgenre`` command for fetching genres post facto (thanks to Jakob Schnitzer). - :doc:`/plugins/fetchart`: Local image filenames are now used in alphabetical order. - :doc:`/plugins/fetchart`: Fix a bug where cover art filenames could lack a ``.jpg`` extension. - :doc:`/plugins/lyrics`: Fix an exception with non-ASCII lyrics. - :doc:`/plugins/web`: The API now reports file sizes (for use with the `Tomahawk resolver`_). - :doc:`/plugins/web`: Files now download with a reasonable filename rather than just being called "file" (thanks to Zach Denton). - :doc:`/plugins/importfeeds`: Fix error in symlink mode with non-ASCII filenames. - :doc:`/plugins/mbcollection`: Fix an error when submitting a large number of releases (we now submit only 200 releases at a time instead of 350). Thanks to Jonathan Towne. - :doc:`/plugins/embedart`: Made the method for embedding art into FLAC files `standard <https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE>`_-compliant. Thanks to Daniele Sluijters. - Add the track mapping dictionary to the ``album_distance`` plugin function. - When an exception is raised while reading a file, the path of the file in question is now logged (thanks to Mike Kazantsev). - Truncate long filenames based on their *bytes* rather than their Unicode *characters*, fixing situations where encoded names could be too long. - Filename truncation now incorporates the length of the extension. - Fix an assertion failure when the MusicBrainz main database and search server disagree. - Fix a bug that caused the :doc:`/plugins/lastgenre` and other plugins not to modify files' tags even when they successfully change the database. - Fix a VFS bug leading to a crash in the :doc:`/plugins/bpd` when files had non-ASCII extensions. - Fix for changing date fields (like "year") with the :ref:`modify-cmd` command. - Fix a crash when input is read from a pipe without a specified encoding. - Fix some problem with identifying files on Windows with Unicode directory names in their path. - Fix a crash when Unicode queries were used with ``import -L`` re-imports. - Fix an error when fingerprinting files with Unicode filenames on Windows. - Warn instead of crashing when importing a specific file in singleton mode. - Add human-readable error messages when writing files' tags fails or when a directory can't be created. - Changed plugin loading so that modules can be imported without unintentionally loading the plugins they contain. .. _aacgain: https://github.com/dgilman/aacgain .. _mp3gain: https://sourceforge.net/projects/mp3gain/ .. _the echo nest: https://web.archive.org/web/20180329103558/http://the.echonest.com/ .. _tomahawk resolver: https://beets.io/blog/tomahawk-resolver.html 1.0b15 (July 26, 2012) ---------------------- The fifteenth (!) beta of beets is compendium of small fixes and features, most of which represent long-standing requests. The improvements include matching albums with extra tracks, per-disc track numbering in multi-disc albums, an overhaul of the album art downloader, and robustness enhancements that should keep beets running even when things go wrong. All these smaller changes should help us focus on some larger changes coming before 1.0. Please note that this release contains one backwards-incompatible change: album art fetching, which was previously baked into the import workflow, is now encapsulated in a plugin (the :doc:`/plugins/fetchart`). If you want to continue fetching cover art for your music, enable this plugin after upgrading to beets 1.0b15. - The autotagger can now find matches for albums when you have **extra tracks** on your filesystem that aren't present in the MusicBrainz catalog. Previously, if you tried to match album with 15 audio files but the MusicBrainz entry had only 14 tracks, beets would ignore this match. Now, beets will show you matches even when they are "too short" and indicate which tracks from your disk are unmatched. - Tracks on multi-disc albums can now be **numbered per-disc** instead of per-album via the :ref:`per_disc_numbering` config option. - The default output format for the ``beet list`` command is now configurable via the :ref:`list_format_item` and :ref:`list_format_album` config options. Thanks to Fabrice Laporte. - Album **cover art fetching** is now encapsulated in the :doc:`/plugins/fetchart`. Be sure to enable this plugin if you're using this functionality. As a result of this new organization, the new plugin has gained a few new features: - "As-is" and non-autotagged imports can now have album art imported from the local filesystem (although Web repositories are still not searched in these cases). - A new command, ``beet fetchart``, allows you to download album art post-import. If you only want to fetch art manually, not automatically during import, set the new plugin's ``autofetch`` option to ``no``. - New album art sources have been added. - Errors when communicating with MusicBrainz now log an error message instead of halting the importer. - Similarly, filesystem manipulation errors now print helpful error messages instead of a messy traceback. They still interrupt beets, but they should now be easier for users to understand. Tracebacks are still available in verbose mode. - New metadata fields for `artist credits`_: ``artist_credit`` and ``albumartist_credit`` can now contain release- and recording-specific variations of the artist's name. See :ref:`itemfields`. - Revamped the way beets handles concurrent database access to avoid nondeterministic SQLite-related crashes when using the multithreaded importer. On systems where SQLite was compiled without ``usleep(3)`` support, multithreaded database access could cause an internal error (with the message "database is locked"). This release synchronizes access to the database to avoid internal SQLite contention, which should avoid this error. - Plugins can now add parallel stages to the import pipeline. See :ref:`basic-plugin-setup`. - Beets now prints out an error when you use an unrecognized field name in a query: for example, when running ``beet ls -a artist:foo`` (because ``artist`` is an item-level field). - New plugin events: - ``import_task_choice`` is called after an import task has an action assigned. - ``import_task_files`` is called after a task's file manipulation has finished (copying or moving files, writing metadata tags). - ``library_opened`` is called when beets starts up and opens the library database. - :doc:`/plugins/lastgenre`: Fixed a problem where path formats containing ``$genre`` would use the old genre instead of the newly discovered one. - Fix a crash when moving files to a Samba share. - :doc:`/plugins/mpdupdate`: Fix TypeError crash (thanks to Philippe Mongeau). - When re-importing files with ``import_copy`` enabled, only files inside the library directory are moved. Files outside the library directory are still copied. This solves a problem (introduced in 1.0b14) where beets could crash after adding files to the library but before finishing copying them; during the next import, the (external) files would be moved instead of copied. - Artist sort names are now populated correctly for multi-artist tracks and releases. (Previously, they only reflected the first artist.) - When previewing changes during import, differences in track duration are now shown as "2:50 vs. 3:10" rather than separated with ``->`` like track numbers. This should clarify that beets isn't doing anything to modify lengths. - Fix a problem with query-based path format matching where a field-qualified pattern, like ``albumtype_soundtrack``, would match everything. - :doc:`/plugins/chroma`: Fix matching with ambiguous Acoustids. Some Acoustids are identified with multiple recordings; beets now considers any associated recording a valid match. This should reduce some cases of errant track reordering when using chroma. - Fix the ID3 tag name for the catalog number field. - :doc:`/plugins/chroma`: Fix occasional crash at end of fingerprint submission and give more context to "failed fingerprint generation" errors. - Interactive prompts are sent to stdout instead of stderr. - :doc:`/plugins/embedart`: Fix crash when audio files are unreadable. - :doc:`/plugins/bpd`: Fix crash when sockets disconnect (thanks to Matteo Mecucci). - Fix an assertion failure while importing with moving enabled when the file was already at its destination. - Fix Unicode values in the ``replace`` config option (thanks to Jakob Borg). - Use a nicer error message when input is requested but stdin is closed. - Fix errors on Windows for certain Unicode characters that can't be represented in the MBCS encoding. This required a change to the way that paths are represented in the database on Windows; if you find that beets' paths are out of sync with your filesystem with this release, delete and recreate your database with ``beet import -AWC /path/to/music``. - Fix ``import`` with relative path arguments on Windows. .. _artist credits: https://wiki.musicbrainz.org/Artist_Credit 1.0b14 (May 12, 2012) --------------------- The centerpiece of this beets release is the graceful handling of similarly-named albums. It's now possible to import two albums with the same artist and title and to keep them from conflicting in the filesystem. Many other awesome new features were contributed by the beets community, including regular expression queries, artist sort names, moving files on import. There are three new plugins: random song/album selection; MusicBrainz "collection" integration; and a plugin for interoperability with other music library systems. A million thanks to the (growing) beets community for making this a huge release. - The importer now gives you **choices when duplicates are detected**. Previously, when beets found an existing album or item in your library matching the metadata on a newly-imported one, it would just skip the new music to avoid introducing duplicates into your library. Now, you have three choices: skip the new music (the previous behavior), keep both, or remove the old music. See the :ref:`guide-duplicates` section in the autotagging guide for details. - Beets can now avoid storing identically-named albums in the same directory. The new ``%aunique{}`` template function, which is included in the default path formats, ensures that Crystal Castles' albums will be placed into different directories. See :ref:`aunique` for details. - Beets queries can now use **regular expressions**. Use an additional ``:`` in your query to enable regex matching. See :ref:`regex` for the full details. Thanks to Matteo Mecucci. - Artist **sort names** are now fetched from MusicBrainz. There are two new data fields, ``artist_sort`` and ``albumartist_sort``, that contain sortable artist names like "Beatles, The". These fields are also used to sort albums and items when using the ``list`` command. Thanks to Paul Provost. - Many other **new metadata fields** were added, including ASIN, label catalog number, disc title, encoder, and MusicBrainz release group ID. For a full list of fields, see :ref:`itemfields`. - :doc:`/plugins/chroma`: A new command, ``beet submit``, will **submit fingerprints** to the Acoustid database. Submitting your library helps increase the coverage and accuracy of Acoustid fingerprinting. The Chromaprint fingerprint and Acoustid ID are also now stored for all fingerprinted tracks. This version of beets *requires* at least version 0.6 of pyacoustid_ for fingerprinting to work. - The importer can now **move files**. Previously, beets could only copy files and delete the originals, which is inefficient if the source and destination are on the same filesystem. Use the ``import_move`` configuration option and see :doc:`/reference/config` for more details. Thanks to Domen Kožar. - New :doc:`/plugins/random`: Randomly select albums and tracks from your library. Thanks to Philippe Mongeau. - The :doc:`/plugins/mbcollection` by Jeffrey Aylesworth was added to the core beets distribution. - New :doc:`/plugins/importfeeds`: Catalog imported files in ``m3u`` playlist files or as symlinks for easy importing to other systems. Thanks to Fabrice Laporte. - The ``-f`` (output format) option to the ``beet list`` command can now contain template functions as well as field references. Thanks to Steve Dougherty. - A new command ``beet fields`` displays the available metadata fields (thanks to Matteo Mecucci). - The ``import`` command now has a ``--noincremental`` or ``-I`` flag to disable incremental imports (thanks to Matteo Mecucci). - When the autotagger fails to find a match, it now displays the number of tracks on the album (to help you guess what might be going wrong) and a link to the FAQ. - The default filename character substitutions were changed to be more conservative. The Windows "reserved characters" are substituted by default even on Unix platforms (this causes less surprise when using Samba shares to store music). To customize your character substitutions, see :ref:`the replace config option <replace>`. - :doc:`/plugins/lastgenre`: Added a "fallback" option when no suitable genre can be found (thanks to Fabrice Laporte). - :doc:`/plugins/rewrite`: Unicode rewriting rules are now allowed (thanks to Nicolas Dietrich). - Filename collisions are now avoided when moving album art. - :doc:`/plugins/bpd`: Print messages to show when directory tree is being constructed. - :doc:`/plugins/bpd`: Use Gstreamer's ``playbin2`` element instead of the deprecated ``playbin``. - :doc:`/plugins/bpd`: Random and repeat modes are now supported (thanks to Matteo Mecucci). - :doc:`/plugins/bpd`: Listings are now sorted (thanks once again to Matteo Mecucci). - Filenames are normalized with Unicode Normal Form D (NFD) on Mac OS X and NFC on all other platforms. - Significant internal restructuring to avoid SQLite locking errors. As part of these changes, the not-very-useful "save" plugin event has been removed. .. _pyacoustid: https://github.com/beetbox/pyacoustid 1.0b13 (March 16, 2012) ----------------------- Beets 1.0b13 consists of a plethora of small but important fixes and refinements. A lyrics plugin is now included with beets; new audio properties are catalogged; the ``list`` command has been made more powerful; the autotagger is more tolerant of different tagging styles; and importing with original file deletion now cleans up after itself more thoroughly. Many, many bugs—including several crashers—were fixed. This release lays the foundation for more features to come in the next couple of releases. - The :doc:`/plugins/lyrics`, originally by `Peter Brunner`_, is revamped and included with beets, making it easy to fetch **song lyrics**. - Items now expose their audio **sample rate**, number of **channels**, and **bits per sample** (bitdepth). See :doc:`/reference/pathformat` for a list of all available audio properties. Thanks to Andrew Dunn. - The ``beet list`` command now accepts a "format" argument that lets you **show specific information about each album or track**. For example, run ``beet ls -af '$album: $tracktotal' beatles`` to see how long each Beatles album is. Thanks to Philippe Mongeau. - The autotagger now tolerates tracks on multi-disc albums that are numbered per-disc. For example, if track 24 on a release is the first track on the second disc, then it is not penalized for having its track number set to 1 instead of 24. - The autotagger sets the disc number and disc total fields on autotagged albums. - The autotagger now also tolerates tracks whose track artists tags are set to "Various Artists". - Terminal colors are now supported on Windows via Colorama_ (thanks to Karl). - When previewing metadata differences, the importer now shows discrepancies in track length. - Importing with ``import_delete`` enabled now cleans up empty directories that contained deleting imported music files. - Similarly, ``import_delete`` now causes original album art imported from the disk to be deleted. - Plugin-supplied template values, such as those created by ``rewrite``, are now properly sanitized (for example, ``AC/DC`` properly becomes ``AC_DC``). - Filename extensions are now always lower-cased when copying and moving files. - The ``inline`` plugin now prints a more comprehensible error when exceptions occur in Python snippets. - The ``replace`` configuration option can now remove characters entirely (in addition to replacing them) if the special string ``<strip>`` is specified as the replacement. - New plugin API: plugins can now add fields to the MediaFile tag abstraction layer. See :ref:`basic-plugin-setup`. - A reasonable error message is now shown when the import log file cannot be opened. - The import log file is now flushed and closed properly so that it can be used to monitor import progress, even when the import crashes. - Duplicate track matches are no longer shown when autotagging singletons. - The ``chroma`` plugin now logs errors when fingerprinting fails. - The ``lastgenre`` plugin suppresses more errors when dealing with the Last.fm API. - Fix a bug in the ``rewrite`` plugin that broke the use of multiple rules for a single field. - Fix a crash with non-ASCII characters in bytestring metadata fields (e.g., MusicBrainz IDs). - Fix another crash with non-ASCII characters in the configuration paths. - Fix a divide-by-zero crash on zero-length audio files. - Fix a crash in the ``chroma`` plugin when the Acoustid database had no recording associated with a fingerprint. - Fix a crash when an autotagging with an artist or album containing "AND" or "OR" (upper case). - Fix an error in the ``rewrite`` and ``inline`` plugins when the corresponding config sections did not exist. - Fix bitrate estimation for AAC files whose headers are missing the relevant data. - Fix the ``list`` command in BPD (thanks to Simon Chopin). .. _colorama: https://pypi.org/project/colorama/ 1.0b12 (January 16, 2012) ------------------------- This release focuses on making beets' path formatting vastly more powerful. It adds a function syntax for transforming text. Via a new plugin, arbitrary Python code can also be used to define new path format fields. Each path format template can now be activated conditionally based on a query. Character set substitutions are also now configurable. In addition, beets avoids problematic filename conflicts by appending numbers to filenames that would otherwise conflict. Three new plugins (``inline``, ``scrub``, and ``rewrite``) are included in this release. - **Functions in path formats** provide a simple way to write complex file naming rules: for example, ``%upper{%left{$artist,1}}`` will insert the capitalized first letter of the track's artist. For more details, see :doc:`/reference/pathformat`. If you're interested in adding your own template functions via a plugin, see :ref:`basic-plugin-setup`. - Plugins can also now define new path *fields* in addition to functions. - The new :doc:`/plugins/inline` lets you **use Python expressions to customize path formats** by defining new fields in the config file. - The configuration can **condition path formats based on queries**. That is, you can write a path format that is only used if an item matches a given query. (This supersedes the earlier functionality that only allowed conditioning on album type; if you used this feature in a previous version, you will need to replace, for example, ``soundtrack:`` with ``albumtype_soundtrack:``.) See :ref:`path-format-config`. - **Filename substitutions are now configurable** via the ``replace`` config value. You can choose which characters you think should be allowed in your directory and music file names. See :doc:`/reference/config`. - Beets now ensures that files have **unique filenames** by appending a number to any filename that would otherwise conflict with an existing file. - The new :doc:`/plugins/scrub` can remove extraneous metadata either manually or automatically. - The new :doc:`/plugins/rewrite` can canonicalize names for path formats. - The autotagging heuristics have been tweaked in situations where the MusicBrainz database did not contain track lengths. Previously, beets penalized matches where this was the case, leading to situations where seemingly good matches would have poor similarity. This penalty has been removed. - Fix an incompatibility in BPD with libmpc (the library that powers mpc and ncmpc). - Fix a crash when importing a partial match whose first track was missing. - The ``lastgenre`` plugin now correctly writes discovered genres to imported files (when tag-writing is enabled). - Add a message when skipping directories during an incremental import. - The default ignore settings now ignore all files beginning with a dot. - Date values in path formats (``$year``, ``$month``, and ``$day``) are now appropriately zero-padded. - Removed the ``--path-format`` global flag for ``beet``. - Removed the ``lastid`` plugin, which was deprecated in the previous version. 1.0b11 (December 12, 2011) -------------------------- This version of beets focuses on transitioning the autotagger to the new version of the MusicBrainz database (called NGS). This transition brings with it a number of long-overdue improvements: most notably, predictable behavior when tagging multi-disc albums and integration with the new Acoustid_ acoustic fingerprinting technology. The importer can also now tag *incomplete* albums when you're missing a few tracks from a given release. Two other new plugins are also included with this release: one for assigning genres and another for ReplayGain analysis. - Beets now communicates with MusicBrainz via the new `Next Generation Schema`_ (NGS) service via python-musicbrainzngs_. The bindings are included with this version of beets, but a future version will make them an external dependency. - The importer now detects **multi-disc albums** and tags them together. Using a heuristic based on the names of directories, certain structures are classified as multi-disc albums: for example, if a directory contains subdirectories labeled "disc 1" and "disc 2", these subdirectories will be coalesced into a single album for tagging. - The new :doc:`/plugins/chroma` uses the Acoustid_ **open-source acoustic fingerprinting** service. This replaces the old ``lastid`` plugin, which used Last.fm fingerprinting and is now deprecated. Fingerprinting with this library should be faster and more reliable. - The importer can now perform **partial matches**. This means that, if you're missing a few tracks from an album, beets can still tag the remaining tracks as a single album. (Thanks to `Simon Chopin`_.) - The new :doc:`/plugins/lastgenre` automatically **assigns genres to imported albums** and items based on Last.fm tags and an internal whitelist. (Thanks to KraYmer_.) - The :doc:`/plugins/replaygain`, written by `Peter Brunner`_, has been merged into the core beets distribution. Use it to analyze audio and **adjust playback levels** in ReplayGain-aware music players. - Albums are now tagged with their *original* release date rather than the date of any reissue, remaster, "special edition", or the like. - The config file and library databases are now given better names and locations on Windows. Namely, both files now reside in ``%APPDATA%``; the config file is named ``beetsconfig.ini`` and the database is called ``beetslibrary.blb`` (neither has a leading dot as on Unix). For backwards compatibility, beets will check the old locations first. - When entering an ID manually during tagging, beets now searches for anything that looks like an MBID in the entered string. This means that full MusicBrainz URLs now work as IDs at the prompt. (Thanks to derwin.) - The importer now ignores certain "clutter" files like ``.AppleDouble`` directories and ``._*`` files. The list of ignored patterns is configurable via the ``ignore`` setting; see :doc:`/reference/config`. - The database now keeps track of files' modification times so that, during an ``update``, unmodified files can be skipped. (Thanks to Jos van der Til.) - The album art fetcher now uses albumart.org_ as a fallback when the Amazon art downloader fails. - A new ``timeout`` config value avoids database locking errors on slow systems. - Fix a crash after using the "as Tracks" option during import. - Fix a Unicode error when tagging items with missing titles. - Fix a crash when the state file (``~/.beetsstate``) became emptied or corrupted. .. _acoustid: https://acoustid.org/ .. _albumart.org: https://web.archive.org/web/20191217041318/http://www.albumart.org/ .. _kraymer: https://github.com/KraYmer .. _next generation schema: https://musicbrainz.org/doc/MusicBrainz_API .. _peter brunner: https://github.com/Lugoues .. _python-musicbrainzngs: https://github.com/alastair/python-musicbrainzngs .. _simon chopin: https://github.com/laarmen 1.0b10 (September 22, 2011) --------------------------- This version of beets focuses on making it easier to manage your metadata *after* you've imported it. A bumper crop of new commands has been added: a manual tag editor (``modify``), a tool to pick up out-of-band deletions and modifications (``update``), and functionality for moving and copying files around (``move``). Furthermore, the concept of "re-importing" is new: you can choose to re-run beets' advanced autotagger on any files you already have in your library if you change your mind after you finish the initial import. As a couple of added bonuses, imports can now automatically skip previously-imported directories (with the ``-i`` flag) and there's an :doc:`experimental Web interface </plugins/web>` to beets in a new standard plugin. - A new ``beet modify`` command enables **manual, command-line-based modification** of music metadata. Pass it a query along with ``field=value`` pairs that specify the changes you want to make. - A new ``beet update`` command updates the database to reflect **changes in the on-disk metadata**. You can now use an external program to edit tags on files, remove files and directories, etc., and then run ``beet update`` to make sure your beets library is in sync. This will also rename files to reflect their new metadata. - A new ``beet move`` command can **copy or move files** into your library directory or to another specified directory. - When importing files that are already in the library database, the items are no longer duplicated---instead, the library is updated to reflect the new metadata. This way, the import command can be transparently used as a **re-import**. - Relatedly, the ``-L`` flag to the "import" command makes it take a query as its argument instead of a list of directories. The matched albums (or items, depending on the ``-s`` flag) are then re-imported. - A new flag ``-i`` to the import command runs **incremental imports**, keeping track of and skipping previously-imported directories. This has the effect of making repeated import commands pick up only newly-added directories. The ``import_incremental`` config option makes this the default. - When pruning directories, "clutter" files such as ``.DS_Store`` and ``Thumbs.db`` are ignored (and removed with otherwise-empty directories). - The :doc:`/plugins/web` encapsulates a simple **Web-based GUI for beets**. The current iteration can browse the library and play music in browsers that support HTML5 Audio. - When moving items that are part of an album, the album art implicitly moves too. - Files are no longer silently overwritten when moving and copying files. - Handle exceptions thrown when running Mutagen. - Fix a missing ``__future__`` import in ``embed art`` on Python 2.5. - Fix ID3 and MPEG-4 tag names for the album-artist field. - Fix Unicode encoding of album artist, album type, and label. - Fix crash when "copying" an art file that's already in place. 1.0b9 (July 9, 2011) -------------------- This release focuses on a large number of small fixes and improvements that turn beets into a well-oiled, music-devouring machine. See the full release notes, below, for a plethora of new features. - **Queries can now contain whitespace.** Spaces passed as shell arguments are now preserved, so you can use your shell's escaping syntax (quotes or backslashes, for instance) to include spaces in queries. For example, ``beet ls "the knife"`` or ``beet ls theknife``. Read more in :doc:`/reference/query`. - Queries can **match items from the library by directory**. A ``path:`` prefix is optional; any query containing a path separator (/ on POSIX systems) is assumed to be a path query. Running ``beet ls path/to/music`` will show all the music in your library under the specified directory. The :doc:`/reference/query` reference again has more details. - **Local album art** is now automatically discovered and copied from the imported directories when available. - When choosing the "as-is" import album (or doing a non-autotagged import), **every album either has an "album artist" set or is marked as a compilation (Various Artists)**. The choice is made based on the homogeneity of the tracks' artists. This prevents compilations that are imported as-is from being scattered across many directories after they are imported. - The release **label** for albums and tracks is now fetched from !MusicBrainz, written to files, and stored in the database. - The "list" command now accepts a ``-p`` switch that causes it to **show paths** instead of titles. This makes the output of ``beet ls -p`` suitable for piping into another command such as xargs_. - Release year and label are now shown in the candidate selection list to help disambiguate different releases of the same album. - Prompts in the importer interface are now colorized for easy reading. The default option is always highlighted. - The importer now provides the option to specify a MusicBrainz ID manually if the built-in searching isn't working for a particular album or track. - ``$bitrate`` in path formats is now formatted as a human-readable kbps value instead of as a raw integer. - The import logger has been improved for "always-on" use. First, it is now possible to specify a log file in .beetsconfig. Also, logs are now appended rather than overwritten and contain timestamps. - Album art fetching and plugin events are each now run in separate pipeline stages during imports. This should bring additional performance when using album art plugins like embedart or beets-lyrics. - Accents and other Unicode decorators on characters are now treated more fairly by the autotagger. For example, if you're missing the acute accent on the "e" in "café", that change won't be penalized. This introduces a new dependency on the unidecode_ Python module. - When tagging a track with no title set, the track's filename is now shown (instead of nothing at all). - The bitrate of lossless files is now calculated from their file size (rather than being fixed at 0 or reflecting the uncompressed audio bitrate). - Fixed a problem where duplicate albums or items imported at the same time would fail to be detected. - BPD now uses a persistent "virtual filesystem" in order to fake a directory structure. This means that your path format settings are respected in BPD's browsing hierarchy. This may come at a performance cost, however. The virtual filesystem used by BPD is available for reuse by plugins (e.g., the FUSE plugin). - Singleton imports (``beet import -s``) can now take individual files as arguments as well as directories. - Fix Unicode queries given on the command line. - Fix crasher in quiet singleton imports (``import -qs``). - Fix crash when autotagging files with no metadata. - Fix a rare deadlock when finishing the import pipeline. - Fix an issue that was causing mpdupdate to run twice for every album. - Fix a bug that caused release dates/years not to be fetched. - Fix a crasher when setting MBIDs on MP3s file metadata. - Fix a "broken pipe" error when piping beets' standard output. - A better error message is given when the database file is unopenable. - Suppress errors due to timeouts and bad responses from MusicBrainz. - Fix a crash on album queries with item-only field names. .. _unidecode: https://pypi.org/project/Unidecode/0.04.1/ .. _xargs: https://en.wikipedia.org/wiki/Xargs 1.0b8 (April 28, 2011) ---------------------- This release of beets brings two significant new features. First, beets now has first-class support for "singleton" tracks. Previously, it was only really meant to manage whole albums, but many of us have lots of non-album tracks to keep track of alongside our collections of albums. So now beets makes it easy to tag, catalog, and manipulate your individual tracks. Second, beets can now (optionally) embed album art directly into file metadata rather than only storing it in a "file on the side." Check out the :doc:`/plugins/embedart` for that functionality. - Better support for **singleton (non-album) tracks**. Whereas beets previously only really supported full albums, now it can also keep track of individual, off-album songs. The "singleton" path format can be used to customize where these tracks are stored. To import singleton tracks, provide the -s switch to the import command or, while doing a normal full-album import, choose the "as Tracks" (T) option to add singletons to your library. To list only singleton or only album tracks, use the new ``singleton:`` query term: the query ``singleton:true`` matches only singleton tracks; ``singleton:false`` matches only album tracks. The ``lastid`` plugin has been extended to support matching individual items as well. - The importer/autotagger system has been heavily refactored in this release. If anything breaks as a result, please get in touch or just file a bug. - Support for **album art embedded in files**. A new :doc:`/plugins/embedart` implements this functionality. Enable the plugin to automatically embed downloaded album art into your music files' metadata. The plugin also provides the "embedart" and "extractart" commands for moving image files in and out of metadata. See the wiki for more details. (Thanks, daenney!) - The "distance" number, which quantifies how different an album's current and proposed metadata are, is now displayed as "similarity" instead. This should be less noisy and confusing; you'll now see 99.5% instead of 0.00489323. - A new "timid mode" in the importer asks the user every time, even when it makes a match with very high confidence. The ``-t`` flag on the command line and the ``import_timid`` config option control this mode. (Thanks to mdecker on GitHub!) - The multithreaded importer should now abort (either by selecting aBort or by typing ^C) much more quickly. Previously, it would try to get a lot of work done before quitting; now it gives up as soon as it can. - Added a new plugin event, ``album_imported``, which is called every time an album is added to the library. (Thanks, Lugoues!) - A new plugin method, ``register_listener``, is an imperative alternative to the ``@listen`` decorator (Thanks again, Lugoues!) - In path formats, ``$albumartist`` now falls back to ``$artist`` (as well as the other way around). - The importer now prints "(unknown album)" when no tags are present. - When autotagging, "and" is considered equal to "&". - Fix some crashes when deleting files that don't exist. - Fix adding individual tracks in BPD. - Fix crash when ``~/.beetsconfig`` does not exist. 1.0b7 (April 5, 2011) --------------------- Beta 7's focus is on better support for "various artists" releases. These albums can be treated differently via the new ``[paths]`` config section and the autotagger is better at handling them. It also includes a number of oft-requested improvements to the ``beet`` command-line tool, including several new configuration options and the ability to clean up empty directory subtrees. - **"Various artists" releases** are handled much more gracefully. The autotagger now sets the ``comp`` flag on albums whenever the album is identified as a "various artists" release by !MusicBrainz. Also, there is now a distinction between the "album artist" and the "track artist", the latter of which is never "Various Artists" or other such bogus stand-in. *(Thanks to Jonathan for the bulk of the implementation work on this feature!)* - The directory hierarchy can now be **customized based on release type**. In particular, the ``path_format`` setting in .beetsconfig has been replaced with a new ``[paths]`` section, which allows you to specify different path formats for normal and "compilation" (various artists) releases as well as for each album type (see below). The default path formats have been changed to use ``$albumartist`` instead of ``$artist``. - A **new** ``albumtype`` **field** reflects the release type `as specified by MusicBrainz`_. - When deleting files, beets now appropriately "prunes" the directory tree---empty directories are automatically cleaned up. *(Thanks to wlof on GitHub for this!)* - The tagger's output now always shows the album directory that is currently being tagged. This should help in situations where files' current tags are missing or useless. - The logging option (``-l``) to the ``import`` command now logs duplicate albums. - A new ``import_resume`` configuration option can be used to disable the importer's resuming feature or force it to resume without asking. This option may be either ``yes``, ``no``, or ``ask``, with the obvious meanings. The ``-p`` and ``-P`` command-line flags override this setting and correspond to the "yes" and "no" settings. - Resuming is automatically disabled when the importer is in quiet (``-q``) mode. Progress is still saved, however, and the ``-p`` flag (above) can be used to force resuming. - The ``BEETSCONFIG`` environment variable can now be used to specify the location of the config file that is at ~/.beetsconfig by default. - A new ``import_quiet_fallback`` config option specifies what should happen in quiet mode when there is no strong recommendation. The options are ``skip`` (the default) and "asis". - When importing with the "delete" option and importing files that are already at their destination, files could be deleted (leaving zero copies afterward). This is fixed. - The ``version`` command now lists all the loaded plugins. - A new plugin, called ``info``, just prints out audio file metadata. - Fix a bug where some files would be erroneously interpreted as MPEG-4 audio. - Fix permission bits applied to album art files. - Fix malformed !MusicBrainz queries caused by null characters. - Fix a bug with old versions of the Monkey's Audio format. - Fix a crash on broken symbolic links. - Retry in more cases when !MusicBrainz servers are slow/overloaded. - The old "albumify" plugin for upgrading databases was removed. .. _as specified by musicbrainz: https://wiki.musicbrainz.org/ReleaseType 1.0b6 (January 20, 2011) ------------------------ This version consists primarily of bug fixes and other small improvements. It's in preparation for a more feature-ful release in beta 7. The most important issue involves correct ordering of autotagged albums. - **Quiet import:** a new "-q" command line switch for the import command suppresses all prompts for input; it pessimistically skips all albums that the importer is not completely confident about. - Added support for the **WavPack** and **Musepack** formats. Unfortunately, due to a limitation in the Mutagen library (used by beets for metadata manipulation), Musepack SV8 is not yet supported. Here's the `upstream bug`_ in question. - BPD now uses a pure-Python socket library and no longer requires eventlet/greenlet (the latter of which is a C extension). For the curious, the socket library in question is called Bluelet_. - Non-autotagged imports are now resumable (just like autotagged imports). - Fix a terrible and long-standing bug where track orderings were never applied. This manifested when the tagger appeared to be applying a reasonable ordering to the tracks but, later, the database reflects a completely wrong association of track names to files. The order applied was always just alphabetical by filename, which is frequently but not always what you want. - We now use Windows' "long filename" support. This API is fairly tricky, though, so some instability may still be present---please file a bug if you run into pathname weirdness on Windows. Also, filenames on Windows now never end in spaces. - Fix crash in lastid when the artist name is not available. - Fixed a spurious crash when ``LANG`` or a related environment variable is set to an invalid value (such as ``'UTF-8'`` on some installations of Mac OS X). - Fixed an error when trying to copy a file that is already at its destination. - When copying read-only files, the importer now tries to make the copy writable. (Previously, this would just crash the import.) - Fixed an ``UnboundLocalError`` when no matches are found during autotag. - Fixed a Unicode encoding error when entering special characters into the "manual search" prompt. - Added ``beet version`` command that just shows the current release version. .. _bluelet: https://github.com/sampsyo/bluelet .. _upstream bug: https://github.com/quodlibet/mutagen/issues/7 1.0b5 (September 28, 2010) -------------------------- This version of beets focuses on increasing the accuracy of the autotagger. The main addition is an included plugin that uses acoustic fingerprinting to match based on the audio content (rather than existing metadata). Additional heuristics were also added to the metadata-based tagger as well that should make it more reliable. This release also greatly expands the capabilities of beets' :doc:`plugin API </plugins/index>`. A host of other little features and fixes are also rolled into this release. - The ``lastid`` plugin adds Last.fm **acoustic fingerprinting support** to the autotagger. Similar to the PUIDs used by !MusicBrainz Picard, this system allows beets to recognize files that don't have any metadata at all. You'll need to install some dependencies for this plugin to work. - To support the above, there's also a new system for **extending the autotagger via plugins**. Plugins can currently add components to the track and album distance functions as well as augment the MusicBrainz search. The new API is documented at :doc:`/plugins/index`. - **String comparisons** in the autotagger have been augmented to act more intuitively. Previously, if your album had the title "Something (EP)" and it was officially called "Something", then beets would think this was a fairly significant change. It now checks for and appropriately reweights certain parts of each string. As another example, the title "The Great Album" is considered equal to "Great Album, The". - New **event system for plugins** (thanks, Jeff!). Plugins can now get callbacks from beets when certain events occur in the core. Again, the API is documented in :doc:`/plugins/index`. - The BPD plugin is now disabled by default. This greatly simplifies installation of the beets core, which is now 100% pure Python. To use BPD, though, you'll need to set ``plugins: bpd`` in your .beetsconfig. - The ``import`` command can now remove original files when it copies items into your library. (This might be useful if you're low on disk space.) Set the ``import_delete`` option in your .beetsconfig to ``yes``. - Importing without autotagging (``beet import -A``) now prints out album names as it imports them to indicate progress. - The new :doc:`/plugins/mpdupdate` will automatically update your MPD server's index whenever your beets library changes. - Efficiency tweak should reduce the number of !MusicBrainz queries per autotagged album. - A new ``-v`` command line switch enables debugging output. - Fixed bug that completely broke non-autotagged imports (``import -A``). - Fixed bug that logged the wrong paths when using ``import -l``. - Fixed autotagging for the creatively-named band `!!!`_. - Fixed normalization of relative paths. - Fixed escaping of ``/`` characters in paths on Windows. .. _!!!: https://musicbrainz.org/artist/f26c72d3-e52c-467b-b651-679c73d8e1a7 1.0b4 (August 9, 2010) ---------------------- This thrilling new release of beets focuses on making the tagger more usable in a variety of ways. First and foremost, it should now be much faster: the tagger now uses a multithreaded algorithm by default (although, because the new tagger is experimental, a single-threaded version is still available via a config option). Second, the tagger output now uses a little bit of ANSI terminal coloring to make changes stand out. This way, it should be faster to decide what to do with a proposed match: the more red you see, the worse the match is. Finally, the tagger can be safely interrupted (paused) and restarted later at the same point. Just enter ``b`` for aBort at any prompt to stop the tagging process and save its progress. (The progress-saving also works in the unthinkable event that beets crashes while tagging.) Among the under-the-hood changes in 1.0b4 is a major change to the way beets handles paths (filenames). This should make the whole system more tolerant to special characters in filenames, but it may break things (especially databases created with older versions of beets). As always, let me know if you run into weird problems with this release. Finally, this release's ``setup.py`` should install a ``beet.exe`` startup stub for Windows users. This should make running beets much easier: just type ``beet`` if you have your ``PATH`` environment variable set up correctly. The :doc:`/guides/main` guide has some tips on installing beets on Windows. Here's the detailed list of changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - **Parallel tagger.** The autotagger has been reimplemented to use multiple threads. This means that it can concurrently read files from disk, talk to the user, communicate with MusicBrainz, and write data back to disk. Not only does this make the tagger much faster because independent work may be performed in parallel, but it makes the tagging process much more pleasant for large imports. The user can let albums queue up in the background while making a decision rather than waiting for beets between each question it asks. The parallel tagger is on by default but a sequential (single- threaded) version is still available by setting the ``threaded`` config value to ``no`` (because the parallel version is still quite experimental). - **Colorized tagger output.** The autotagger interface now makes it a little easier to see what's going on at a glance by highlighting changes with terminal colors. This feature is on by default, but you can turn it off by setting ``color`` to ``no`` in your ``.beetsconfig`` (if, for example, your terminal doesn't understand colors and garbles the output). - **Pause and resume imports.** The ``import`` command now keeps track of its progress, so if you're interrupted (beets crashes, you abort the process, an alien devours your motherboard, etc.), beets will try to resume from the point where you left off. The next time you run ``import`` on the same directory, it will ask if you want to resume. It accomplishes this by "fast-forwarding" through the albums in the directory until it encounters the last one it saw. (This means it might fail if that album can't be found.) Also, you can now abort the tagging process by entering ``b`` (for aBort) at any of the prompts. - Overhauled methods for handling filesystem paths to allow filenames that have badly encoded special characters. These changes are pretty fragile, so please report any bugs involving ``UnicodeError`` or SQLite ``ProgrammingError`` messages in this version. - The destination paths (the library directory structure) now respect album-level metadata. This means that if you have an album in which two tracks have different album-level attributes (like year, for instance), they will still wind up in the same directory together. (There's currently not a very smart method for picking the "correct" album-level metadata, but we'll fix that later.) - Fixed a bug where the CLI would fail completely if the ``LANG`` environment variable was not set. - Fixed removal of albums (``beet remove -a``): previously, the album record would stay around although the items were deleted. - The setup script now makes a ``beet.exe`` startup stub on Windows; Windows users can now just type ``beet`` at the prompt to run beets. - Fixed an occasional bug where Mutagen would complain that a tag was already present. - Fixed a bug with reading invalid integers from ID3 tags. - The tagger should now be a little more reluctant to reorder tracks that already have indices. 1.0b3 (July 22, 2010) --------------------- This release features two major additions to the autotagger's functionality: album art fetching and MusicBrainz ID tags. It also contains some important under-the-hood improvements: a new plugin architecture is introduced and the database schema is extended with explicit support for albums. This release has one major backwards-incompatibility. Because of the new way beets handles albums in the library, databases created with an old version of beets might have trouble with operations that deal with albums (like the ``-a`` switch to ``beet list`` and ``beet remove``, as well as the file browser for BPD). To "upgrade" an old database, you can use the included ``albumify`` plugin (see the fourth bullet point below). - **Album art.** The tagger now, by default, downloads album art from Amazon that is referenced in the MusicBrainz database. It places the album art alongside the audio files in a file called (for example) ``cover.jpg``. The ``import_art`` config option controls this behavior, as do the ``-r`` and ``-R`` options to the import command. You can set the name (minus extension) of the album art file with the ``art_filename`` config option. (See :doc:`/reference/config` for more information about how to configure the album art downloader.) - **Support for MusicBrainz ID tags.** The autotagger now keeps track of the MusicBrainz track, album, and artist IDs it matched for each file. It also looks for album IDs in new files it's importing and uses those to look up data in MusicBrainz. Furthermore, track IDs are used as a component of the tagger's distance metric now. (This obviously lays the groundwork for a utility that can update tags if the MB database changes, but that's `for the future`_.) Tangentially, this change required the database code to support a lightweight form of migrations so that new columns could be added to old databases--this is a delicate feature, so it would be very wise to make a backup of your database before upgrading to this version. - **Plugin architecture.** Add-on modules can now add new commands to the beets command-line interface. The ``bpd`` and ``dadd`` commands were removed from the beets core and turned into plugins; BPD is loaded by default. To load the non-default plugins, use the config options ``plugins`` (a space-separated list of plugin names) and ``pluginpath`` (a colon-separated list of directories to search beyond ``sys.path``). Plugins are just Python modules under the ``beetsplug`` namespace package containing subclasses of |BeetsPlugin|. See `the beetsplug directory`_ for examples or :doc:`/plugins/index` for instructions. - As a consequence of adding album art, the database was significantly refactored to keep track of some information at an album (rather than item) granularity. Databases created with earlier versions of beets should work fine, but they won't have any "albums" in them--they'll just be a bag of items. This means that commands like ``beet ls -a`` and ``beet rm -a`` won't match anything. To "upgrade" your database, you can use the included ``albumify`` plugin. Running ``beets albumify`` with the plugin activated (set ``plugins=albumify`` in your config file) will group all your items into albums, making beets behave more or less as it did before. - Fixed some bugs with encoding paths on Windows. Also, ``:`` is now replaced with ``-`` in path names (instead of ``_``) for readability. - ``MediaFile`` now has a ``format`` attribute, so you can use ``$format`` in your library path format strings like ``$artist - $album ($format)`` to get directories with names like ``Paul Simon - Graceland (FLAC)``. .. _for the future: https://github.com/google-code-export/beets/issues/69 .. _the beetsplug directory: https://github.com/beetbox/beets/tree/master/beetsplug Beets also now has its first third-party plugin: beetfs_, by Martin Eve! It exposes your music in a FUSE filesystem using a custom directory structure. Even cooler: it lets you keep your files intact on-disk while correcting their tags when accessed through FUSE. Check it out! .. _beetfs: https://github.com/jbaiter/beetfs 1.0b2 (July 7, 2010) -------------------- This release focuses on high-priority fixes and conspicuously missing features. Highlights include support for two new audio formats (Monkey's Audio and Ogg Vorbis) and an option to log untaggable albums during import. - **Support for Ogg Vorbis and Monkey's Audio** files and their tags. (This support should be considered preliminary: I haven't tested it heavily because I don't use either of these formats regularly.) - An option to the ``beet import`` command for **logging albums that are untaggable** (i.e., are skipped or taken "as-is"). Use ``beet import -l LOGFILE PATHS``. The log format is very simple: it's just a status (either "skip" or "asis") followed by the path to the album in question. The idea is that you can tag a large collection and automatically keep track of the albums that weren't found in MusicBrainz so you can come back and look at them later. - Fixed a ``UnicodeEncodeError`` on terminals that don't (or don't claim to) support UTF-8. - Importing without autotagging (``beet import -A``) is now faster and doesn't print out a bunch of whitespace. It also lets you specify single files on the command line (rather than just directories). - Fixed importer crash when attempting to read a corrupt file. - Reorganized code for CLI in preparation for adding pluggable subcommands. Also removed dependency on the aging ``cmdln`` module in favor of `a hand-rolled solution`_. .. _a hand-rolled solution: https://gist.github.com/sampsyo/462717 1.0b1 (June 17, 2010) --------------------- Initial release. ��������������������������������������������beetbox-beets-00724b7/docs/reference/���������������������������������������������������������������0000775�0001750�0001750�00000000000�15253035401�016741� 5����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/docs/reference/index.rst������������������������������������������������������0000664�0001750�0001750�00000000422�15253035401�020600� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Reference ========= This section contains reference materials for various parts of beets. To get started with beets as a new user, though, you may want to read the :doc:`/guides/main` guide first. .. toctree:: :maxdepth: 2 cli config pathformat query ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/docs/reference/cli.rst��������������������������������������������������������0000664�0001750�0001750�00000057351�15253035401�020255� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Command-Line Interface ====================== .. only:: man SYNOPSIS -------- | **beet** [*args*...] *command* [*args*...] | **beet help** *command* .. only:: html **beet** is the command-line interface to beets. You invoke beets by specifying a *command*, like so:: beet COMMAND [ARGS...] The rest of this document describes the available commands. If you ever need a quick list of what's available, just type ``beet help`` or ``beet help COMMAND`` for help with a specific command. Beets also offers shell completion. For bash, see the `completion`_ command; for zsh, see the accompanying `completion script`_ for the ``beet`` command. Commands -------- .. only:: html Here are the built-in commands available in beets: .. contents:: :local: :depth: 1 Also be sure to see the :ref:`global flags <global-flags>`. .. _import-cmd: import ~~~~~~ :: beet import [-CMWAPRqst] [-l LOGPATH] PATH... beet import [options] -L QUERY Add music to your library, attempting to get correct tags for it from MusicBrainz. Point the command at some music: directories, single files, or compressed archives. The music will be copied to a configurable directory structure and added to a library database. The command is interactive and will try to get you to verify MusicBrainz tags that it thinks are suspect. See the :doc:`autotagging guide </guides/tagger>` for detail on how to use the interactive tag-correction flow. Directories passed to the import command can contain either a single album or many, in which case the leaf directories will be considered albums (the latter case is true of typical Artist/Album organizations and many people's "downloads" folders). The path can also be a single song or an archive. Beets supports ``zip`` and ``tar`` archives out of the box. To extract ``rar`` files, install the rarfile_ package and the ``unrar`` command. To extract ``7z`` files, install the py7zr_ package. Optional command flags: - By default, the command copies files to your library directory and updates the ID3 tags on your music. In order to move the files, instead of copying, use the ``-m`` (move) option. When importing an archive with ``-m``, if all files are imported, the archive is removed from disk. If you'd like to leave your music files untouched, try the ``-C`` (don't copy), ``-M`` (don't move), and ``-W`` (don't write tags) options. You can also disable this behavior by default in the configuration file (below). - Also, you can disable the autotagging behavior entirely using ``-A`` (don't autotag)---then your music will be imported with its existing metadata. - During a long tagging import, it can be useful to keep track of albums that weren't tagged successfully---either because they're not in the MusicBrainz database or because something's wrong with the files. Use the ``-l`` option to specify a filename to log every time you skip an album or import it "as-is" or an album gets skipped as a duplicate. You can later review the file manually or import skipped paths from the logfile automatically by using the ``--from-logfile LOGFILE`` argument. - Relatedly, the ``-q`` (quiet) option can help with large imports by autotagging without ever bothering to ask for user input. Whenever the normal autotagger mode would ask for confirmation, the quiet mode performs a fallback action that can be configured using the ``quiet_fallback`` configuration or ``--quiet-fallback`` CLI option. By default it pessimistically skips the file. Alternatively, it can be used as is, by configuring ``asis``. - Speaking of resuming interrupted imports, the tagger will prompt you if it seems like the last import of the directory was interrupted (by you or by a crash). If you want to skip this prompt, you can say "yes" automatically by providing ``-p`` or "no" using ``-P``. The resuming feature can be disabled by default using a configuration option (see below). - If you want to import only the *new* stuff from a directory, use the ``-i`` option to run an *incremental* import. With this flag, beets will keep track of every directory it ever imports and avoid importing them again. This is useful if you have an "incoming" directory that you periodically add things to. To get this to work correctly, you'll need to use an incremental import *every time* you run an import on the directory in question---including the first time, when no subdirectories will be skipped. So consider enabling the ``incremental`` configuration option. - If you don't want to record skipped files during an *incremental* import, use the ``--incremental-skip-later`` flag which corresponds to the ``incremental_skip_later`` configuration option. Setting the flag prevents beets from persisting skip decisions during a non-interactive import so that a user can make a decision regarding previously skipped files during a subsequent interactive import run. To record skipped files during incremental import explicitly, use the ``--noincremental-skip-later`` option. - When beets applies metadata to your music, it will retain the value of any existing tags that weren't overwritten, and import them into the database. You may prefer to only use existing metadata for finding matches, and to erase it completely when new metadata is applied. You can enforce this behavior with the ``--from-scratch`` option, or the ``from_scratch`` configuration option. - By default, beets will proceed without asking if it finds a very close metadata match. To disable this and have the importer ask you every time, use the ``-t`` (for *timid*) option. - The importer typically works in a whole-album-at-a-time mode. If you instead want to import individual, non-album tracks, use the *singleton* mode by supplying the ``-s`` option. - If you have an album that's split across several directories under a common top directory, use the ``--flat`` option. This takes all the music files under the directory (recursively) and treats them as a single large album instead of as one album per directory. This can help with your more stubborn multi-disc albums. - Similarly, if you have one directory that contains multiple albums, use the ``--group-albums`` option to split the files based on their metadata before matching them as separate albums. - If you want to preview which files would be imported, use the ``--pretend`` option. If set, beets will just print a list of files that it would otherwise import. - If you already have a metadata backend ID that matches the items to be imported, you can instruct beets to restrict the search to that ID instead of searching for other candidates by using the ``--search-id SEARCH_ID`` option. Multiple IDs can be specified by simply repeating the option several times. - You can supply ``--set field=value`` to assign ``field`` to ``value`` on import. Values support the same template syntax as beets' :doc:`path formats <pathformat>`. These assignments will merge with (and possibly override) the :ref:`set_fields` configuration dictionary. You can use the option multiple times on the command line, like so: .. code-block:: sh beet import --set genres="Alternative Rock" --set mood="emotional" .. _py7zr: https://pypi.org/project/py7zr/ .. _rarfile: https://pypi.org/project/rarfile/ .. only:: html .. _reimport: Reimporting ^^^^^^^^^^^ The ``import`` command can also be used to "reimport" music that you've already added to your library. This is useful when you change your mind about some selections you made during the initial import, or if you prefer to import everything "as-is" and then correct tags later. Just point the ``beet import`` command at a directory of files that are already catalogged in your library. Beets will automatically detect this situation and avoid duplicating any items. In this situation, the "copy files" option (``-c``/``-C`` on the command line or ``copy`` in the config file) has slightly different behavior: it causes files to be *moved*, rather than duplicated, if they're already in your library. (The same is true, of course, if ``move`` is enabled.) That is, your directory structure will be updated to reflect the new tags if copying is enabled; you never end up with two copies of the file. Using ``-C`` (don't copy) in combination with ``-M`` (don't move) will retag music while leaving the files where they are. This is useful for players/music servers that get confused when an item changes path and tags at the same time. One can later use the :ref:`move-cmd` command to move items based on their new tags. The ``-L`` (``--library``) flag is also useful for retagging. Instead of listing paths you want to import on the command line, specify a :doc:`query string <query>` that matches items from your library. In this case, the ``-s`` (singleton) flag controls whether the query matches individual items or full albums. If you want to retag your whole library, just supply a null query, which matches everything: ``beet import -L`` Note that, if you just want to update your files' tags according to changes in the MusicBrainz database, the :doc:`/plugins/mbsync` is a better choice. Reimporting uses the full matching machinery to guess metadata matches; ``mbsync`` just relies on MusicBrainz IDs. .. _list-cmd: list ~~~~ :: beet list [-apf] [-l LIMIT] QUERY :doc:`Queries <query>` the database for music. Want to search for "Gronlandic Edit" by of Montreal? Try ``beet list gronlandic``. Maybe you want to see everything released in 2009 with "vegetables" in the title? Try ``beet list year:2009 title:vegetables``. You can also specify the sort order. (Read more in :doc:`query`.) You can use the ``-a`` switch to search for albums instead of individual items. In this case, the queries you use are restricted to album-level fields: for example, you can search for ``year:1969`` but query parts for item-level fields like ``title:foo`` will be ignored. Remember that ``artist`` is an item-level field; ``albumartist`` is the corresponding album field. Use the ``-l LIMIT`` (``--limit=LIMIT``) flag when you want to cap the maximum number of items that are returned. The ``-p`` option makes beets print out filenames of matched items, which might be useful for piping into other Unix commands (such as `xargs <https://en.wikipedia.org/wiki/Xargs>`__). Similarly, the ``-f`` option lets you specify a specific format with which to print every album or track. This uses the same template syntax as beets' :doc:`path formats <pathformat>`. For example, the command ``beet ls -af '$album: $albumtotal' beatles`` prints out the number of tracks on each Beatles album. In Unix shells, remember to enclose the template argument in single quotes to avoid environment variable expansion. .. _remove-cmd: remove ~~~~~~ :: beet remove [-adf] QUERY Remove music from your library. This command uses the same :doc:`query <query>` syntax as the ``list`` command. By default, it just removes entries from the library database; it doesn't touch the files on disk. To actually delete the files, use the ``-d`` flag. When the ``-a`` flag is given, the command operates on albums instead of individual tracks. When you run the ``remove`` command, it prints a list of all affected items in the library and asks for your permission before removing them. You can then choose to abort (type ``n``), confirm (``y``), or interactively choose some of the items (``s``). In the latter case, the command will prompt you for every matching item or album and invite you to type ``y`` to remove the item/album, ``n`` to keep it or ``q`` to exit and only remove the items/albums selected up to this point. This option lets you choose precisely which tracks/albums to remove without spending too much time to carefully craft a query. If you do not want to be prompted at all, use the ``-f`` option. .. _modify-cmd: modify ~~~~~~ :: beet modify [-IMWay] [-f FORMAT] QUERY [FIELD=VALUE...] [FIELD+=VALUE...] [FIELD-=VALUE...] [FIELD!...] Change the metadata for items or albums in the database. Supply a :doc:`query <query>` matching the things you want to change and a series of ``field=value`` pairs. For example, ``beet modify genius of love artist="Tom Tom Club"`` will change the artist for the track "Genius of Love." To remove fields (which is only possible for flexible attributes), follow a field name with an exclamation point: ``field!``. Values can also be *templates*, using the same syntax as :doc:`path formats <pathformat>`. For example, ``beet modify artist='$artist_sort'`` will copy the artist sort name into the artist field for all your tracks, and ``beet modify title='$track $title'`` will add track numbers to their title metadata. To adjust a multi-valued field, such as ``genres``, ``remixers``, ``lyricists``, ``composers``, or ``arrangers``, separate the values with |semicolon_space|. For example, ``beet modify genres="rock; pop"``. For these multi-valued fields, you can also use ``+=`` to add values and ``-=`` to remove values, instead of replacing the whole field. For example, ``beet modify genres+=Funk`` adds "Funk" to the existing genres (without duplicating it if already present), and ``beet modify genres-=Pop`` removes "Pop" from the list, leaving the other values untouched. These operators are only valid for multi-valued fields. When modifying albums with ``-a``, multi-valued fields such as ``artists``, ``genres``, ``composers`` are also supported with the same semicolon-separated syntax. For compatibility, ``modify`` assignments and query expressions still accept legacy singular names such as ``genre``, ``composer``, ``lyricist``, ``remixer``, and ``arranger``, but beets will warn and translate them to the plural multi-valued fields. Prefer the plural field names in new commands. The ``-a`` option changes to querying album fields instead of track fields and also enables to operate on albums in addition to the individual tracks. Without this flag, the command will only change *track-level* data, even if all the tracks belong to the same album. If you want to change an *album-level* field, such as ``year`` or ``albumartist``, you'll want to use the ``-a`` flag to avoid a confusing situation where the data for individual tracks conflicts with the data for the whole album. Modifications issued using ``-a`` by default cascade to individual tracks. To prevent this behavior, use ``-I``/``--noinherit``. Items will automatically be moved around when necessary if they're in your library directory, but you can disable that with ``-M``. Tags will be written to the files according to the settings you have for imports, but these can be overridden with ``-w`` (write tags, the default) and ``-W`` (don't write tags). When you run the ``modify`` command, it prints a list of all affected items in the library and asks for your permission before making any changes. You can then choose to abort the change (type ``n``), confirm (``y``), or interactively choose some of the items (``s``). In the latter case, the command will prompt you for every matching item or album and invite you to type ``y`` to apply the changes, ``n`` to discard them or ``q`` to exit and apply the selected changes. This option lets you choose precisely which data to change without spending too much time to carefully craft a query. To skip the prompts entirely, use the ``-y`` option. .. _move-cmd: move ~~~~ :: beet move [-capt] [-d DIR] QUERY Move or copy items in your library. This command, by default, acts as a library consolidator: items matching the query are renamed into your library directory structure. By specifying a destination directory with ``-d`` manually, you can move items matching a query anywhere in your filesystem. The ``-c`` option copies files instead of moving them. As with other commands, the ``-a`` option matches albums instead of items. The ``-e`` flag (for "export") copies files without changing the database. To perform a "dry run", just use the ``-p`` (for "pretend") flag. This will show you a list of files that would be moved but won't actually change anything on disk. The ``-t`` option sets the timid mode which will ask again before really moving or copying the files. .. _update-cmd: update ~~~~~~ :: beet update [-F] FIELD [-e] EXCLUDE_FIELD [-aMp] QUERY Update the library (and, by default, move files) to reflect out-of-band metadata changes and file deletions. This will scan all the matched files and read their tags, populating the database with the new values. By default, files will be renamed according to their new metadata; disable this with ``-M``. Beets will skip files if their modification times have not changed, so any out-of-band metadata changes must also update these for ``beet update`` to recognise that the files have been edited. To perform a "dry run" of an update, just use the ``-p`` (for "pretend") flag. This will show you all the proposed changes but won't actually change anything on disk. By default, all the changed metadata will be populated back to the database. If you only want certain fields to be written, specify them with the ``-F`` flags (which can be used multiple times). Alternatively, specify fields to *not* write with ``-e`` flags (which can be used multiple times). For the list of supported fields, please see ``beet fields``. When an updated track is part of an album, the album-level fields of *all* tracks from the album are also updated. (Specifically, the command copies album-level data from the first track on the album and applies it to the rest of the tracks.) This means that, if album-level fields aren't identical within an album, some changes shown by the ``update`` command may be overridden by data from other tracks on the same album. This means that running the ``update`` command multiple times may show the same changes being applied. .. _write-cmd: write ~~~~~ :: beet write [-pf] [QUERY] Write metadata from the database into files' tags. When you make changes to the metadata stored in beets' library database (during import or with the :ref:`modify-cmd` command, for example), you often have the option of storing changes only in the database, leaving your files untouched. The ``write`` command lets you later change your mind and write the contents of the database into the files. By default, this writes the changes only if there is a difference between the database and the tags in the file. You can think of this command as the opposite of :ref:`update-cmd`. The ``-p`` option previews metadata changes without actually applying them. The ``-f`` option forces a write to the file, even if the file tags match the database. This is useful for making sure that enabled plugins that run on write (e.g., the Scrub and Zero plugins) are run on the file. .. _stats-cmd: stats ~~~~~ :: beet stats [-e] [QUERY] Show some statistics on your entire library (if you don't provide a :doc:`query <query>`) or the matched items (if you do). By default, the command calculates file sizes using their bitrate and duration. The ``-e`` (``--exact``) option reads the exact sizes of each file (but is slower). The exact mode also outputs the exact duration in seconds. .. _fields-cmd: fields ~~~~~~ :: beet fields Show the item and album metadata fields available for use in :doc:`query` and :doc:`pathformat`. The listing includes any template fields provided by plugins and any flexible attributes you've manually assigned to your items and albums. .. _config-cmd: config ~~~~~~ :: beet config [-pdc] beet config -e Show or edit the user configuration. This command does one of three things: - With no options, print a YAML representation of the current user configuration. With the ``--default`` option, beets' default options are also included in the dump. - The ``--path`` option instead shows the path to your configuration file. This can be combined with the ``--default`` flag to show where beets keeps its internal defaults. - By default, sensitive information like passwords is removed when dumping the configuration. The ``--clear`` option includes this sensitive data. - With the ``--edit`` option, beets attempts to open your config file for editing. It first tries the ``$EDITOR`` environment variable, followed by ``$EDITOR`` and then a fallback option depending on your platform: ``open`` on OS X, ``xdg-open`` on Unix, and direct invocation on Windows. .. _global-flags: Global Flags ------------ Beets has a few "global" flags that affect all commands. These must appear between the executable name (``beet``) and the command---for example, ``beet -v import ...``. - ``-l LIBPATH``: specify the library database file to use. - ``-d DIRECTORY``: specify the library root directory. - ``-v``: verbose mode; prints out a deluge of debugging information. Please use this flag when reporting bugs. You can use it twice, as in ``-vv``, to make beets even more verbose. - ``-c FILE``: read a specified YAML :doc:`configuration file <config>`. This configuration works as an overlay: rather than replacing your normal configuration options entirely, the two are merged. Any individual options set in this config file will override the corresponding settings in your base configuration. - ``-p plugins``: specify a comma-separated list of plugins to enable. If specified, the plugin list in your configuration is ignored. The long form of this argument also allows specifying no plugins, effectively disabling all plugins: ``--plugins=``. - ``-P plugins``: specify a comma-separated list of plugins to disable in a specific beets run. This will overwrite ``-p`` if used with it. To disable all plugins, use ``--plugins=`` instead. Beets also uses the ``BEETSDIR`` environment variable to look for configuration and data. .. _completion: Shell Completion ---------------- Beets includes support for shell command completion. The command ``beet completion`` prints out a bash_ 3.2 script; to enable completion put a line like this into your ``.bashrc`` or similar file: :: eval "$(beet completion)" Or, to avoid slowing down your shell startup time, you can pipe the ``beet completion`` output to a file and source that instead. You will also need to source the bash-completion_ script, which is probably available via your package manager. On OS X, you can install it via Homebrew with ``brew install bash-completion``; Homebrew will give you instructions for sourcing the script. .. _bash: https://www.gnu.org/software/bash/ .. _bash-completion: https://github.com/scop/bash-completion The completion script suggests names of subcommands and (after typing ``-``) options of the given command. If you are using a command that accepts a query, the script will also complete field names. :: beet list ar[TAB] # artist: artist_credit: artist_sort: artpath: beet list artp[TAB] beet list artpath\: (Don't worry about the slash in front of the colon: this is a escape sequence for the shell and won't be seen by beets.) Completion of plugin commands only works for those plugins that were enabled when running ``beet completion``. If you add a plugin later on you will want to re-generate the script. zsh ~~~ If you use zsh, take a look at the included `completion script`_. The script should be placed in a directory that is part of your ``fpath``, and ``not`` sourced in your ``.zshrc``. Running ``echo $fpath`` will give you a list of valid directories. Another approach is to use zsh's bash completion compatibility. This snippet defines some bash-specific functions to make this work without errors: :: autoload bashcompinit bashcompinit _get_comp_words_by_ref() { :; } compopt() { :; } _filedir() { :; } eval "$(beet completion)" .. _completion script: https://github.com/beetbox/beets/blob/master/extra/_beet .. only:: man See Also -------- ``https://beets.readthedocs.org/`` :manpage:`beetsconfig(5)` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/docs/reference/config.rst�����������������������������������������������������0000664�0001750�0001750�00000122135�15253035401�020744� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Configuration ============= Beets has an extensive configuration system that lets you customize nearly every aspect of its operation. To configure beets, you create a file called ``config.yaml``. The location of the file depends on your platform (type ``beet config -p`` to see the path on your system): - On Unix-like OSes, write ``~/.config/beets/config.yaml``. - On Windows, use ``%APPDATA%\beets\config.yaml``. This is usually in a directory like ``C:\Users\You\AppData\Roaming``. - On OS X, you can use either the Unix location or ``~/Library/Application Support/beets/config.yaml``. You can launch your text editor to create or update your configuration by typing ``beet config -e``. (See the :ref:`config-cmd` command for details.) It is also possible to customize the location of the configuration file and even use multiple layers of configuration. See `Configuration Location`_, below. The config file uses YAML_ syntax. You can use the full power of YAML, but most configuration options are simple key/value pairs. This means your config file will look like this: :: option: value another_option: foo bigger_option: key: value foo: bar In YAML, you will need to use spaces (not tabs!) to indent some lines. If you have questions about more sophisticated syntax, take a look at the YAML_ documentation. .. _yaml: https://yaml.org/ The rest of this page enumerates the dizzying litany of configuration options available in beets. You might also want to see an :ref:`example <config-example>`. .. contents:: :local: :depth: 2 Global Options -------------- These options control beets' global operation. library ~~~~~~~ Path to the beets library file. By default, beets will use a file called ``library.db`` alongside your configuration file. directory ~~~~~~~~~ The directory to which files will be copied/moved when adding them to the library. Defaults to a folder called ``Music`` in your home directory. tempfile_prefix ~~~~~~~~~~~~~~~ The prefix used for temporary files when moving files across filesystems. If unset, temporary files use a leading dot (``.``). This can be changed when moving files to a Windows or Samba share, where a leading dot may cause the file to be treated as hidden. editor ~~~~~~ The text editor to use when editing configuration files (e.g., via ``beet config -e``). Overrides the ``$VISUAL`` and ``$EDITOR`` environment variables. If none of these are set, beets falls back to the platform default. Example: :: editor: nano create_backup_before_migrations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Either ``yes`` or ``no``, indicating whether a backup of the database file should be created before applying any pending schema migrations after a beets upgrade. The backup is only made when there are actually migrations to run. Defaults to ``yes``. .. _plugins-config: plugins ~~~~~~~ A space-separated list of plugin module names to load. See :ref:`using-plugins`. include ~~~~~~~ A space-separated list of extra configuration files to include. Filenames are relative to the directory containing ``config.yaml``. pluginpath ~~~~~~~~~~ Directories to search for plugins. Each Python file or directory in a plugin path represents a plugin and should define a subclass of |BeetsPlugin|. A plugin can then be loaded by adding the plugin name to the ``plugins`` configuration. The plugin path can either be a single string or a list of strings---so, if you have multiple paths, format them as a YAML list like so: :: pluginpath: - /path/one - /path/two .. _ignore: ignore ~~~~~~ A list of glob patterns specifying file and directory names to be ignored when importing. By default, this consists of ``.*``, ``*~``, ``System Volume Information``, ``lost+found`` (i.e., beets ignores Unix-style hidden files, backup files, and directories that appears at the root of some Linux and Windows filesystems). .. _ignore_hidden: ignore_hidden ~~~~~~~~~~~~~ Either ``yes`` or ``no``; whether to ignore hidden files when importing. On Windows, the "Hidden" property of files is used to detect whether or not a file is hidden. On OS X, the file's "IsHidden" flag is used to detect whether or not a file is hidden. On both OS X and other platforms (excluding Windows), files (and directories) starting with a dot are detected as hidden files. .. _replace: replace ~~~~~~~ A set of regular expression/replacement pairs to be applied to all filenames created by beets. Typically, these replacements are used to avoid confusing problems or errors with the filesystem (for example, leading dots, which hide files on Unix, and trailing whitespace, which is illegal on Windows). To override these substitutions, specify a mapping from regular expression to replacement strings. For example, ``[xy]: z`` will make beets replace all instances of the characters ``x`` or ``y`` with the character ``z``. If you do change this value, be certain that you include at least enough substitutions to avoid causing errors on your operating system. Here are the default substitutions used by beets, which are sufficient to avoid unexpected behavior on all popular platforms: :: replace: '[\\/]': _ '^\.': _ '[\x00-\x1f]': _ '[<>:"\?\*\|]': _ '\.$': _ '\s+$': '' '^\s+': '' '^-': _ These substitutions remove forward and back slashes, leading dots, and control characters—all of which is a good idea on any OS. The fourth line removes the Windows "reserved characters" (useful even on Unix for compatibility with Windows-influenced network filesystems like Samba). Trailing dots and trailing whitespace, which can cause problems on Windows clients, are also removed. When replacements other than the defaults are used, it is possible that they will increase the length of the path. In the scenario where this leads to a conflict with the maximum filename length, the default replacements will be used to resolve the conflict and beets will display a warning. Note that paths might contain special characters such as typographical quotes (``“â€�``). With the configuration above, those will not be replaced as they don't match the typewriter quote (``"``). To also strip these special characters, you can either add them to the replacement list or use the :ref:`asciify-paths` configuration option below. .. _path-sep-replace: path_sep_replace ~~~~~~~~~~~~~~~~ A string that replaces the path separator (for example, the forward slash ``/`` on Linux and MacOS, and the backward slash ``\\`` on Windows) when generating filenames with beets. This option is related to :ref:`replace`, but is distinct from it for technical reasons. .. warning:: Changing this option is potentially dangerous. For example, setting it to the actual path separator could create directories in unexpected locations. Use caution when changing it and always try it out on a small number of files before applying it to your whole library. Default: ``_``. .. _asciify-paths: asciify_paths ~~~~~~~~~~~~~ Convert all non-ASCII characters in paths to ASCII equivalents. For example, if your path template for singletons is ``singletons/$title`` and the title of a track is "Café", then the track will be saved as ``singletons/Cafe.mp3``. The changes take place before applying the :ref:`replace` configuration and are roughly equivalent to wrapping all your path templates in the ``%asciify{}`` :ref:`template function <template-functions>`. This uses the `unidecode module <https://pypi.org/project/Unidecode>`__ which is language agnostic, so some characters may be transliterated from a different language than expected. For example, Japanese kanji will usually use their Chinese readings. Default: ``no``. .. _art-filename: art_filename ~~~~~~~~~~~~ When importing album art, the name of the file (without extension) where the cover art image should be placed. This is a template string, so you can use any of the syntax available to :doc:`/reference/pathformat`. Defaults to ``cover`` (i.e., images will be named ``cover.jpg`` or ``cover.png`` and placed in the album's directory). threaded ~~~~~~~~ Either ``yes`` or ``no``, indicating whether the autotagger should use multiple threads. This makes things substantially faster by overlapping work: for example, it can copy files for one album in parallel with looking up data in MusicBrainz for a different album. You may want to disable this when debugging problems with the autotagger. Defaults to ``yes``. .. _format_item: .. _list_format_item: format_item ~~~~~~~~~~~ Format to use when listing *individual items* with the :ref:`list-cmd` command and other commands that need to print out items. Defaults to ``$artist - $album - $title``. The ``-f`` command-line option overrides this setting. It used to be named ``list_format_item``. .. _format_album: .. _list_format_album: format_album ~~~~~~~~~~~~ Format to use when listing *albums* with :ref:`list-cmd` and other commands. Defaults to ``$albumartist - $album``. The ``-f`` command-line option overrides this setting. It used to be named ``list_format_album``. .. _sort_item: sort_item ~~~~~~~~~ Default sort order to use when fetching items from the database. Defaults to ``artist+ album+ disc+ track+``. Explicit sort orders override this default. .. _sort_album: sort_album ~~~~~~~~~~ Default sort order to use when fetching albums from the database. Defaults to ``albumartist+ album+``. Explicit sort orders override this default. .. _sort_case_insensitive: sort_case_insensitive ~~~~~~~~~~~~~~~~~~~~~ Either ``yes`` or ``no``, indicating whether the case should be ignored when sorting lexicographic fields. When set to ``no``, lower-case values will be placed after upper-case values (e.g., *Bar Qux foo*), while ``yes`` would result in the more expected *Bar foo Qux*. Default: ``yes``. .. _original_date: original_date ~~~~~~~~~~~~~ Either ``yes`` or ``no``, indicating whether matched albums should have their ``year``, ``month``, and ``day`` fields set to the release date of the *original* version of an album rather than the selected version of the release. That is, if this option is turned on, then ``year`` will always equal ``original_year`` and so on. Default: ``no``. .. _overwrite_null: overwrite_null ~~~~~~~~~~~~~~ This confusingly-named option indicates which fields have meaningful ``null`` values. If an album or track field is in the corresponding list, then an existing value for this field in an item in the database can be overwritten with ``null``. By default, however, ``null`` is interpreted as information about the field being unavailable, so it would not overwrite existing values. For example: :: overwrite_null: album: ["albumid"] track: ["title", "date"] .. _artist_credit: artist_credit ~~~~~~~~~~~~~ Either ``yes`` or ``no``, indicating whether matched tracks and albums should use the artist credit, rather than the artist. That is, if this option is turned on, then ``artist`` will contain the artist as credited on the release. .. _per_disc_numbering: per_disc_numbering ~~~~~~~~~~~~~~~~~~ A boolean controlling the track numbering style on multi-disc releases. By default (``per_disc_numbering: no``), tracks are numbered per-release, so the first track on the second disc has track number N+1 where N is the number of tracks on the first disc. If this ``per_disc_numbering`` is enabled, then the first (non-pregap) track on each disc always has track number 1. If you enable ``per_disc_numbering``, you will likely want to change your :ref:`path-format-config` also to include ``$disc`` before ``$track`` to make filenames sort correctly in album directories. For example, you might want to use a path format like this: :: paths: default: $albumartist/$album%aunique{}/$disc-$track $title When this option is off (the default), even "pregap" hidden tracks are numbered from one, not zero, so other track numbers may appear to be bumped up by one. When it is on, the pregap track for each disc can be numbered zero. .. _config-aunique: aunique ~~~~~~~ These options are used to generate a string that is guaranteed to be unique among all albums in the library who share the same set of keys. The defaults look like this: :: aunique: keys: albumartist album disambiguators: albumtype year label catalognum albumdisambig releasegroupdisambig bracket: '[]' See :ref:`aunique` for more details. .. _config-sunique: sunique ~~~~~~~ Like :ref:`config-aunique` above for albums, these options control the generation of a unique string to disambiguate *singletons* that share similar metadata. The defaults look like this: :: sunique: keys: artist title disambiguators: year trackdisambig bracket: '[]' See :ref:`sunique` for more details. .. _terminal_encoding: terminal_encoding ~~~~~~~~~~~~~~~~~ The text encoding, as `known to Python <https://docs.python.org/3/library/codecs.html#standard-encodings>`__, to use for messages printed to the standard output. It's also used to read messages from the standard input. By default, this is determined automatically from the locale environment variables. .. _clutter: clutter ~~~~~~~ When beets imports all the files in a directory, it tries to remove the directory if it's empty. A directory is considered empty if it only contains files whose names match the glob patterns in ``clutter``, which should be a list of strings. The default list consists of "Thumbs.DB" and ".DS_Store". The importer only removes recursively searched subdirectories---the top-level directory you specify on the command line is never deleted. .. _max_filename_length: max_filename_length ~~~~~~~~~~~~~~~~~~~ Set the maximum number of characters in a filename, after which names will be truncated. By default, beets tries to ask the filesystem for the correct maximum. .. _id3v23: id3v23 ~~~~~~ By default, beets writes MP3 tags using the ID3v2.4 standard, the latest version of ID3. Enable this option to instead use the older ID3v2.3 standard, which is preferred by certain older software such as Windows Media Player. .. _va_name: va_name ~~~~~~~ Sets the albumartist for various-artist compilations. Defaults to ``'Various Artists'`` (the MusicBrainz standard). Affects other sources, such as :doc:`/plugins/discogs`, too. .. _ui_options: UI Options ---------- The options that allow for customization of the visual appearance of the console interface. color ~~~~~ Either ``yes`` or ``no``; whether to use color in console output. Turn this off if your terminal doesn't support ANSI colors. .. _colors: colors ~~~~~~ The colors that are used throughout the user interface. These are only used if the ``color`` option is set to ``yes``. See the default configuration: .. code-block:: yaml ui: colors: text_success: ['bold', 'green'] text_warning: ['bold', 'yellow'] text_error: ['bold', 'red'] text_highlight: ['bold', 'red'] text_highlight_minor: ['white'] action_default: ['bold', 'cyan'] action: ['bold', 'cyan'] # New colors after UI overhaul text_faint: ['faint'] import_path: ['bold', 'blue'] import_path_items: ['bold', 'blue'] changed: ['yellow'] text_diff_added: ['bold', 'green'] text_diff_removed: ['bold', 'red'] action_description: ['white'] Available attributes: Foreground colors ``black``, ``red``, ``green``, ``yellow``, ``blue``, ``magenta``, ``cyan``, ``white``, ``bright_black``, ``bright_red``, ``bright_green``, ``bright_yellow``, ``bright_blue``, ``bright_magenta``, ``bright_cyan``, ``bright_white`` Background colors ``bg_black``, ``bg_red``, ``bg_green``, ``bg_yellow``, ``bg_blue``, ``bg_magenta``, ``bg_cyan``, ``bg_white``, ``bg_bright_black``, ``bg_bright_red``, ``bg_bright_green``, ``bg_bright_yellow``, ``bg_bright_blue``, ``bg_bright_magenta``, ``bg_bright_cyan``, ``bg_bright_white`` Text styles ``normal``, ``bold``, ``faint``, ``italic``, ``underline``, ``blink_slow``, ``blink_rapid``, ``inverse``, ``conceal``, ``crossed_out`` terminal_width ~~~~~~~~~~~~~~ Controls line wrapping on non-Unix systems. On Unix systems, the width of the terminal is detected automatically. If this fails, or on non-Unix systems, the specified value is used as a fallback. Defaults to ``80`` characters: .. code-block:: yaml ui: terminal_width: 80 length_diff_thresh ~~~~~~~~~~~~~~~~~~ Beets compares the length of the imported track with the length the metadata source provides. If any tracks differ by at least ``length_diff_thresh`` seconds, they will be colored with ``text_highlight``. Below this threshold, different track lengths are colored with ``text_highlight_minor``. ``length_diff_thresh`` does not impact which releases are selected in autotagger matching or distance score calculation (see :ref:`match-config`, ``distance_weights`` and :ref:`colors`): .. code-block:: yaml ui: length_diff_thresh: 10.0 import ~~~~~~ When importing, beets will read several options to configure the visuals of the import dialogue. There are two layouts controlling how horizontal space and line wrapping is dealt with: ``column`` and ``newline``. The indentation of the respective elements of the import UI can also be configured. For example setting ``2`` for ``match_header`` will indent the very first block of a proposed match by two characters in the terminal: .. code-block:: yaml ui: import: indentation: match_header: 2 match_details: 2 match_tracklist: 5 layout: column Importer Options ---------------- The options that control the :ref:`import-cmd` command are indented under the ``import:`` key. For example, you might have a section in your configuration file that looks like this: :: import: write: yes copy: yes resume: no These options are available in this section: .. _config-import-write: write ~~~~~ Either ``yes`` or ``no``, controlling whether metadata (e.g., ID3) tags are written to files when using ``beet import``. Defaults to ``yes``. The ``-w`` and ``-W`` command-line options override this setting. .. _config-import-copy: copy ~~~~ Either ``yes`` or ``no``, indicating whether to **copy** files into the library directory when using ``beet import``. Defaults to ``yes``. Can be overridden with the ``-c`` and ``-C`` command-line options. The option is ignored if ``move`` is enabled (i.e., beets can move or copy files but it doesn't make sense to do both). .. _config-import-move: move ~~~~ Either ``yes`` or ``no``, indicating whether to **move** files into the library directory when using ``beet import``. Defaults to ``no``. The effect is similar to the ``copy`` option but you end up with only one copy of the imported file. ("Moving" works even across filesystems; if necessary, beets will copy and then delete when a simple rename is impossible.) Moving files can be risky—it's a good idea to keep a backup in case beets doesn't do what you expect with your files. In the case of a ``move`` when importing an archive, the archive will be removed if all contents were successfully imported. This option *overrides* ``copy``, so enabling it will always move (and not copy) files. The ``-c`` switch to the ``beet import`` command, however, still takes precedence. .. _link: link ~~~~ Either ``yes`` or ``no``, indicating whether to use symbolic links instead of moving or copying files. (It conflicts with the ``move``, ``copy`` and ``hardlink`` options.) Defaults to ``no``. This option only works on platforms that support symbolic links: i.e., Unixes. It will fail on Windows. It's likely that you'll also want to set ``write`` to ``no`` if you use this option to preserve the metadata on the linked files. .. _hardlink: hardlink ~~~~~~~~ Either ``yes`` or ``no``, indicating whether to use hard links instead of moving, copying, or symlinking files. (It conflicts with the ``move``, ``copy``, and ``link`` options.) Defaults to ``no``. As with symbolic links (see :ref:`link`, above), this will not work on Windows and you will want to set ``write`` to ``no``. Otherwise, metadata on the original file will be modified. .. _reflink: reflink ~~~~~~~ Either ``yes``, ``no``, or ``auto``, indicating whether to use copy-on-write `file clones`_ (a.k.a. "reflinks") instead of copying or moving files. The ``auto`` option uses reflinks when possible and falls back to plain copying when necessary. Defaults to ``no``. This kind of clone is only available on certain filesystems: for example, btrfs and APFS. For more details on filesystem support, see the pyreflink_ documentation. Note that you need to install ``pyreflink``, either through ``python -m pip install beets[reflink]`` or ``python -m pip install reflink``. The option is ignored if ``move`` is enabled (i.e., beets can move or copy files but it doesn't make sense to do both). .. _file clones: https://en.wikipedia.org/wiki/Copy-on-write .. _pyreflink: https://reflink.readthedocs.io/en/latest/ resume ~~~~~~ Either ``yes``, ``no``, or ``ask``. Controls whether interrupted imports should be resumed. "Yes" means that imports are always resumed when possible; "no" means resuming is disabled entirely; "ask" (the default) means that the user should be prompted when resuming is possible. The ``-p`` and ``-P`` flags correspond to the "yes" and "no" settings and override this option. .. _incremental: incremental ~~~~~~~~~~~ Either ``yes`` or ``no``, controlling whether imported directories are recorded and whether these recorded directories are skipped. This corresponds to the ``-i`` flag to ``beet import``. .. _incremental_skip_later: incremental_skip_later ~~~~~~~~~~~~~~~~~~~~~~ Either ``yes`` or ``no``, controlling whether skipped directories are recorded in the incremental list. When set to ``yes``, skipped directories won't be recorded, and beets will try to import them again later. When set to ``no``, skipped directories will be recorded, and skipped later. Defaults to ``no``. .. _from_scratch: from_scratch ~~~~~~~~~~~~ Either ``yes`` or ``no`` (default), controlling whether existing metadata is discarded when a match is applied. This corresponds to the ``--from-scratch`` flag to ``beet import``. .. _quiet: quiet ~~~~~ Either ``yes`` or ``no`` (default), controlling whether to ask for a manual decision from the user when the importer is unsure how to proceed. This corresponds to the ``--quiet`` flag to ``beet import``. .. _quiet_fallback: quiet_fallback ~~~~~~~~~~~~~~ Either ``skip`` (default) or ``asis``, specifying what should happen in quiet mode (see the ``-q`` flag to ``import``, above) when there is no strong recommendation. .. _none_rec_action: none_rec_action ~~~~~~~~~~~~~~~ Either ``ask`` (default), ``asis`` or ``skip``. Specifies what should happen during an interactive import session when there is no recommendation. Useful when you are only interested in processing medium and strong recommendations interactively. timid ~~~~~ Either ``yes`` or ``no``, controlling whether the importer runs in *timid* mode, in which it asks for confirmation on every autotagging match, even the ones that seem very close. Defaults to ``no``. The ``-t`` command-line flag controls the same setting. .. _import_log: log ~~~ Specifies a filename where the importer's log should be kept. By default, no log is written. This can be overridden with the ``-l`` flag to ``import``. .. _default_action: default_action ~~~~~~~~~~~~~~ One of ``apply``, ``skip``, ``asis``, or ``none``, indicating which option should be the *default* when selecting an action for a given match. This is the action that will be taken when you type return without an option letter. The default is ``apply``. .. _languages: languages ~~~~~~~~~ A list of locale names to search for preferred aliases. For example, setting this to ``en`` uses the transliterated artist name "Pyotr Ilyich Tchaikovsky" instead of the Cyrillic script for the composer's name when tagging from MusicBrainz. You can use a space-separated list of language abbreviations, like ``en jp es``, to specify a preference order. Defaults to an empty list, meaning that no language is preferred. The alias is used for artist name, track title, release group title and album title. .. _ignored_alias_types: ignored_alias_types ~~~~~~~~~~~~~~~~~~~ A list of alias types to be ignored when importing new items. See the ``MusicBrainz Documentation`` for more information on aliases. .._MusicBrainz Documentation: https://musicbrainz.org/doc/Aliases .. _detail: detail ~~~~~~ Whether the importer UI should show detailed information about each match it finds. When enabled, this mode prints out the title of every track, regardless of whether it matches the original metadata. (The default behavior only shows changes.) Default: ``no``. .. _group_albums: group_albums ~~~~~~~~~~~~ By default, the beets importer groups tracks into albums based on the directories they reside in. This option instead uses files' metadata to partition albums. Enable this option if you have directories that contain tracks from many albums mixed together. The ``--group-albums`` or ``-g`` option to the :ref:`import-cmd` command is equivalent, and the *G* interactive option invokes the same workflow. Default: ``no``. .. _autotag: autotag ~~~~~~~ By default, the beets importer always attempts to autotag new music. If most of your collection consists of obscure music, you may be interested in disabling autotagging by setting this option to ``no``. (You can re-enable it with the ``-a`` flag to the :ref:`import-cmd` command.) Default: ``yes``. .. _duplicate_keys: duplicate_keys ~~~~~~~~~~~~~~ The fields used to find duplicates when importing. There are two sub-values here: ``album`` and ``item``. Each one is a list of field names; if an existing object (album or item) in the library matches the new object on all of these fields, the importer will consider it a duplicate. Default: :: album: albumartist album item: artist title For MusicBrainz-tagged libraries, adding ``mb_albumid`` to the album keys distinguishes separate releases that have the same album artist and title: .. code-block:: yaml album: albumartist album mb_albumid item: artist title All configured fields must match. Albums with different MusicBrainz release IDs will therefore not be considered duplicates. An album without a MusicBrainz release ID will also not match an otherwise identical album that has one. .. _duplicate_action: duplicate_action ~~~~~~~~~~~~~~~~ Either ``skip``, ``keep``, ``remove``, ``merge``, ``upgrade`` or ``ask``. Controls how duplicates are treated in import task. "skip" means that new item(album or track) will be skipped; "keep" means keep both old and new items; "remove" means remove old item; "merge" means merge into one album; "ask" means the user should be prompted for the action each time. The default is ``ask``. "upgrade" compares each newly-imported track against any existing duplicate with the same :ref:`duplicate_keys`: a track only replaces its old counterpart if it has a higher bitrate, and tracks with no old counterpart are always added. The rest of the existing album is left untouched, and the kept tracks are added to that same album rather than a new one. If the import matches more than one existing album (e.g. two differently-encoded copies of the same release already in the library), only the album it overlaps with the most is upgraded; every other candidate album is left completely untouched, since a track can only ever be added to one album. When ``duplicate_action`` is ``ask``, "upgrade" is one of the available interactive choices. .. _duplicate_verbose_prompt: duplicate_verbose_prompt ~~~~~~~~~~~~~~~~~~~~~~~~ Usually when duplicates are detected during import, information about the existing and the newly imported album is summarized. Enabling this option also lists details on individual tracks. The :ref:`format_item setting <format_item>` is applied, which would, considering the default, look like this: .. code-block:: console This item is already in the library! Old: 1 items, MP3, 320kbps, 5:56, 13.6 MiB Artist Name - Album Name - Third Track Title New: 2 items, MP3, 320kbps, 7:18, 17.1 MiB Artist Name - Album Name - First Track Title Artist Name - Album Name - Second Track Title [S]kip new, Merge all, Remove old, Keep all, Upgrade? Default: ``no``. .. _bell: bell ~~~~ Ring the terminal bell to get your attention when the importer needs your input. Default: ``no``. .. _set_fields: set_fields ~~~~~~~~~~ A dictionary indicating fields to set to values for newly imported music. Here's an example: .. code-block:: yaml set_fields: genres: To Listen collection: Unordered Other field/value pairs supplied via the ``--set`` option on the command-line override any settings here for fields with the same name. Values support the same template syntax as beets' :doc:`path formats <pathformat>`. Fields are set on both the album and each individual track of the album. Fields are persisted to the media files of each track. Default: ``{}`` (empty). .. _singleton_album_disambig: singleton_album_disambig ~~~~~~~~~~~~~~~~~~~~~~~~ During singleton imports and if the metadata source provides it, album names are appended to the disambiguation string of matching track candidates. For example: ``The Artist - The Title (Discogs, Index 3, Track B1, [The Album]``. This feature is currently supported by the :doc:`/plugins/discogs` and the :doc:`/plugins/spotify`. Default: ``yes``. .. _fix_ext_inplace: fix_ext_inplace ~~~~~~~~~~~~~~~ The extension of each file is checked at import. If a file has no extension and its binary matches a music format, beets will look for a file with the same name and matching extension in the same directory. For example, when importing an mp3 file named ``asdf``, beets look for ``asdf.mp3``. If found, that file will be imported instead. Otherwise, if ``fix_ext_inplace`` is ``yes``, then the file will be renamed to contain the extension. If ``fix_ext_inplace`` is ``no``, then the original will be left untouched and a copy with extension will be created in the same directory. This is only done if the user has ``ffprobe`` (bundled with FFmpeg) Default: ``no``. .. _remux_mp3_in_wav: remux_mp3_in_wav ~~~~~~~~~~~~~~~~ Some WAV files contain MP3 audio streams (``WAVE_FORMAT_MPEGLAYER3``) rather than the standard PCM format. When this option is enabled, beets will automatically extract the MP3 stream into a proper ``.mp3`` file during import, removing the WAV container. The original WAV file is deleted after successful extraction. Default: ``yes``. .. _match-config: Autotagger Matching Options --------------------------- You can configure some aspects of the logic beets uses when automatically matching MusicBrainz results under the ``match:`` section. To control how *tolerant* the autotagger is of differences, use the ``strong_rec_thresh`` option, which reflects the distance threshold below which beets will make a "strong recommendation" that the metadata be used. Strong recommendations are accepted automatically (except in "timid" mode), so you can use this to make beets ask your opinion more or less often. The threshold is a *distance* value between 0.0 and 1.0, so you can think of it as the opposite of a *similarity* value. For example, if you want to automatically accept any matches above 90% similarity, use: :: match: strong_rec_thresh: 0.10 The default strong recommendation threshold is 0.04. The ``medium_rec_thresh`` and ``rec_gap_thresh`` options work similarly. When a match is below the *medium* recommendation threshold or the distance between it and the next-best match is above the *gap* threshold, the importer will suggest that match but not automatically confirm it. Otherwise, you'll see a list of options to choose from. .. _distance-weights: distance_weights ~~~~~~~~~~~~~~~~ The ``distance_weights`` option allows you to customize how much each field contributes to the overall distance score when matching albums and tracks. Higher weights mean that differences in that field are penalized more heavily, making them more important in the matching decision. The defaults are: .. code-block:: yaml match: distance_weights: data_source: 2.0 artist: 3.0 album: 3.0 media: 1.0 mediums: 1.0 year: 1.0 country: 0.5 label: 0.5 catalognum: 0.5 albumdisambig: 0.5 album_id: 5.0 tracks: 2.0 missing_tracks: 0.9 unmatched_tracks: 0.6 track_title: 3.0 track_artist: 2.0 track_index: 1.0 track_length: 2.0 track_id: 5.0 medium: 1.0 For example, if you don't care as much about matching the exact release year, you can reduce its weight: .. code-block:: yaml match: distance_weights: year: 0.1 You only need to specify the fields you want to override; unspecified fields keep their default weights. .. _max_rec: max_rec ~~~~~~~ As mentioned above, autotagger matches have *recommendations* that control how the UI behaves for a certain quality of match. The recommendation for a certain match is based on the overall distance calculation. But you can also control the recommendation when a specific distance penalty is applied by defining *maximum* recommendations for each field: To define maxima, use keys under ``max_rec:`` in the ``match`` section. The defaults are "medium" for missing and unmatched tracks and "strong" (i.e., no maximum) for everything else: :: match: max_rec: missing_tracks: medium unmatched_tracks: medium If a recommendation is higher than the configured maximum and the indicated penalty is applied, the recommendation is downgraded. The setting for each field can be one of ``none``, ``low``, ``medium`` or ``strong``. When the maximum recommendation is ``strong``, no "downgrading" occurs. The available penalty names here are: - data_source - artist - album - media - mediums - year - country - label - catalognum - albumdisambig - album_id - tracks - missing_tracks - unmatched_tracks - track_title - track_artist - track_index - track_length - track_id .. _preferred: preferred ~~~~~~~~~ In addition to comparing the tagged metadata with the match metadata for similarity, you can also specify an ordered list of preferred countries and media types. A distance penalty will be applied if the country or media type from the match metadata doesn't match. The specified values are preferred in descending order (i.e., the first item will be most preferred). Each item may be a regular expression, and will be matched case insensitively. The number of media will be stripped when matching preferred media (e.g. "2x" in "2xCD"). You can also tell the autotagger to prefer matches that have a release year closest to the original year for an album. Here's an example: :: match: preferred: countries: ['US', 'GB|UK'] media: ['CD', 'Digital Media|File'] original_year: yes By default, none of these options are enabled. .. _ignored: ignored ~~~~~~~ You can completely avoid matches that have certain penalties applied by adding the penalty name to the ``ignored`` setting: :: match: ignored: missing_tracks unmatched_tracks The available penalties are the same as those for the :ref:`max_rec` setting. For example, setting ``ignored: missing_tracks`` will skip any album matches where your audio files are missing some of the tracks. The importer will not attempt to display these matches. It does not ignore the fact that the album is missing tracks, which would allow these matches to apply more easily. To do that, you'll want to adjust the penalty for missing tracks. .. _required: required ~~~~~~~~ You can avoid matches that lack certain required information. Add the tags you want to enforce to the ``required`` setting: :: match: required: year label catalognum country No tags are required by default. .. _ignored_media: ignored_media ~~~~~~~~~~~~~ A list of media (i.e., formats) in metadata databases to ignore when matching music. You can use this to ignore all media that usually contain video instead of audio, for example: :: match: ignored_media: ['Data CD', 'DVD', 'DVD-Video', 'Blu-ray', 'HD-DVD', 'VCD', 'SVCD', 'UMD', 'VHS'] No formats are ignored by default. .. _ignore_data_tracks: ignore_data_tracks ~~~~~~~~~~~~~~~~~~ By default, audio files contained in data tracks within a release are included in the album's tracklist. If you want them to be included, set it ``no``. Default: ``yes``. .. _ignore_video_tracks: ignore_video_tracks ~~~~~~~~~~~~~~~~~~~ By default, video tracks within a release will be ignored. If you want them to be included (for example if you would like to track the audio-only versions of the video tracks), set it to ``no``. Default: ``yes``. .. _path-format-config: Path Format Configuration ------------------------- You can also configure the directory hierarchy beets uses to store music. These settings appear under the ``paths:`` key. Each string is a template string that can refer to metadata fields like ``$artist`` or ``$title``. The filename extension is added automatically. At the moment, you can specify three special paths: ``default`` for most releases, ``comp`` for "various artist" releases with no dominant artist, and ``singleton`` for non-album tracks. The defaults look like this: :: paths: default: $albumartist/$album%aunique{}/$track $title singleton: Non-Album/$artist/$title comp: Compilations/$album%aunique{}/$track $title Note the use of ``$albumartist`` instead of ``$artist``; this ensures that albums will be well-organized. For more about these format strings, see :doc:`pathformat`. The ``aunique{}`` function ensures that identically-named albums are placed in different directories; see :ref:`aunique` for details. In addition to ``default``, ``comp``, and ``singleton``, you can condition path queries based on beets queries (see :doc:`/reference/query`). This means that a config file like this: :: paths: albumtype:soundtrack: Soundtracks/$album/$track $title will place soundtrack albums in a separate directory. The queries are tested in the order they appear in the configuration file, meaning that if an item matches multiple queries, beets will use the path format for the *first* matching query. Queries on multi-value fields, such as ``genres``, match each individual value, so an exact string query like ``genres:=Classical`` can match an item whose genres are ``Classical`` and ``Baroque`` without also matching ``Neoclassical``. Note that the special ``singleton`` and ``comp`` path format conditions are, in fact, just shorthand for the explicit queries ``singleton:true`` and ``comp:true``. In contrast, ``default`` is special and has no query equivalent: the ``default`` format is only used if no queries match. Configuration Location ---------------------- The beets configuration file is usually located in a standard location that depends on your OS, but there are a couple of ways you can tell beets where to look. Environment Variable ~~~~~~~~~~~~~~~~~~~~ First, you can set the ``BEETSDIR`` environment variable to a directory containing a ``config.yaml`` file. This replaces your configuration in the default location. This also affects where auxiliary files, like the library database, are stored by default (that's where relative paths are resolved to). This environment variable is useful if you need to manage multiple beets libraries with separate configurations. Command-Line Option ~~~~~~~~~~~~~~~~~~~ Alternatively, you can use the ``--config`` command-line option to indicate a YAML file containing options that will then be merged with your existing options (from ``BEETSDIR`` or the default locations). This is useful if you want to keep your configuration mostly the same but modify a few options as a batch. For example, you might have different strategies for importing files, each with a different set of importer options. Default Location ~~~~~~~~~~~~~~~~ In the absence of a ``BEETSDIR`` variable, beets searches a few places for your configuration, depending on the platform: - On Unix platforms, including OS X:``~/.config/beets`` and then ``$XDG_CONFIG_DIR/beets``, if the environment variable is set. - On OS X, we also search ``~/Library/Application Support/beets`` before the Unixy locations. - On Windows: ``~\AppData\Roaming\beets``, and then ``%APPDATA%\beets``, if the environment variable is set. Beets uses the first directory in your platform's list that contains ``config.yaml``. If no config file exists, the last path in the list is used. .. _config-example: Example ------- Here's an example file: :: directory: /var/mp3 import: copy: yes write: yes log: beetslog.txt art_filename: albumart plugins: bpd pluginpath: ~/beets/myplugins ui: color: yes paths: default: %first{$genres}/$albumartist/$album/$track $title singleton: Singletons/$artist - $title comp: %first{$genres}/$album/$track $title albumtype:soundtrack: Soundtracks/$album/$track $title .. only:: man See Also -------- ``https://beets.readthedocs.org/`` :manpage:`beet(1)` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/docs/reference/query.rst������������������������������������������������������0000664�0001750�0001750�00000032301�15253035401�020637� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.. _queries: Queries ======= Many of beets' :doc:`commands <cli>` are built around **query strings:** searches that select tracks and albums from your library. This page explains the query string syntax, which is meant to vaguely resemble the syntax used by Web search engines. .. _keywordquery: Keyword ------- This command: :: $ beet list love will show all tracks matching the query string ``love``. By default any unadorned word like this matches in a track's title, artist, album name, album artist, genre and comments. See below on how to search other fields. For example, this is what I might see when I run the command above: :: Against Me! - Reinventing Axl Rose - I Still Love You Julie Air - Love 2 - Do the Joy Bag Raiders - Turbo Love - Shooting Stars Bat for Lashes - Two Suns - Good Love ... .. _combiningqueries: Combining Keywords ------------------ Multiple keywords are implicitly joined with a Boolean "and." That is, if a query has two keywords, it only matches tracks that contain *both* keywords. For example, this command: :: $ beet ls magnetic tomorrow matches songs from the album "The House of Tomorrow" by The Magnetic Fields in my library. It *doesn't* match other songs by the Magnetic Fields, nor does it match "Tomorrowland" by Walter Meego---those songs only have *one* of the two keywords I specified. Keywords can also be joined with a Boolean "or" using a comma. For example, the command: :: $ beet ls magnetic tomorrow , beatles yesterday will match both "The House of Tomorrow" by the Magnetic Fields, as well as "Yesterday" by The Beatles. Note that the comma has to be followed by a space (e.g., ``foo,bar`` will be treated as a single keyword, *not* as an OR-query). .. _fieldsquery: Specific Fields --------------- Sometimes, a broad keyword match isn't enough. Beets supports a syntax that lets you query a specific field---only the artist, only the track title, and so on. Just say ``field:value``, where ``field`` is the name of the thing you're trying to match (such as ``artist``, ``album``, or ``title``) and ``value`` is the keyword you're searching for. For example, while this query: :: $ beet list dream matches a lot of songs in my library, this more-specific query: :: $ beet list artist:dream only matches songs by the artist The-Dream. One query I especially appreciate is one that matches albums by year: :: $ beet list -a year:2012 Recall that ``-a`` makes the ``list`` command show albums instead of individual tracks, so this command shows me all the releases I have from this year. For multi-valued tags (such as ``artists``, ``albumartists``, ``remixers``, ``lyricists``, ``composers``, or ``arrangers``), a regular expression search must be used to search for a single value within the multi-valued tag. Note that you can filter albums by querying tracks fields and vice versa: :: $ beet list -a title:love and vice versa: :: $ beet list art_path::love Phrases ------- You can query for strings with spaces in them by quoting or escaping them using your shell's argument syntax. For example, this command: :: $ beet list the rebel shows several tracks in my library, but these (equivalent) commands: :: $ beet list "the rebel" $ beet list the\ rebel only match the track "The Rebel" by Buck 65. Note that the quotes and backslashes are not part of beets' syntax; I'm just using the escaping functionality of my shell (bash or zsh, for instance) to pass ``the rebel`` as a single argument instead of two. .. _exact-match: Exact Matches ------------- While ordinary queries perform *substring* matches, beets can also match whole strings by adding either ``=`` (case-sensitive) or ``=~`` (ignore case) after the field name's colon and before the expression: :: $ beet list artist:air $ beet list artist:=~air $ beet list artist:=AIR The first query is a simple substring one that returns tracks by Air, AIR, and Air Supply. The second query returns tracks by Air and AIR, since both are a case-insensitive match for the entire expression, but does not return anything by Air Supply. The third query, which requires a case-sensitive exact match, returns tracks by AIR only. Exact matches may be performed on phrases as well: :: $ beet list artist:=~"dave matthews" $ beet list artist:="Dave Matthews" Both of these queries return tracks by Dave Matthews, but not by Dave Matthews Band. To search for exact matches across *all* fields, just prefix the expression with a single ``=`` or ``=~``: :: $ beet list =~crash $ beet list ="American Football" .. _regex: Regular Expressions ------------------- In addition to simple substring and exact matches, beets also supports regular expression matching for more advanced queries. To run a regex query, use an additional ``:`` between the field name and the expression: :: $ beet list "artist::Ann(a|ie)" That query finds songs by Anna Calvi and Annie but not Annuals. Similarly, this query prints the path to any file in my library that's missing a track title: :: $ beet list -p title::^$ To search *all* fields using a regular expression, just prefix the expression with a single ``:``, like so: :: $ beet list ":Ho[pm]eless" Regular expressions are case-sensitive and build on `Python's built-in implementation <https://docs.python.org/3/library/re.html>`__. See Python's documentation for specifics on regex syntax. Most command-line shells will try to interpret common characters in regular expressions, such as ``()[]|``. To type those characters, you'll need to escape them (e.g., with backslashes or quotation marks, depending on your shell). .. _numericquery: Numeric Range Queries --------------------- For numeric fields, such as year, bitrate, and track, you can query using one-or two-sided intervals. That is, you can find music that falls within a *range* of values. To use ranges, write a query that has two dots (``..``) at the beginning, middle, or end of a string of numbers. Dots in the beginning let you specify a maximum (e.g., ``..7``); dots at the end mean a minimum (``4..``); dots in the middle mean a range (``4..7``). For example, this command finds all your albums that were released in the '90s: :: $ beet list -a year:1990..1999 and this command finds MP3 files with bitrates of 128k or lower: :: $ beet list format:MP3 bitrate:..128000 The ``length`` field also lets you use a "M:SS" format. For example, this query finds tracks that are less than four and a half minutes in length: :: $ beet list length:..4:30 .. _datequery: Date and Date Range Queries --------------------------- Date-valued fields, such as *added* and *mtime*, have a special query syntax that lets you specify years, months, and days as well as ranges between dates. Dates are written separated by hyphens, like ``year-month-day``, but the month and day are optional. If you leave out the day, for example, you will get matches for the whole month. Date *intervals*, like the numeric intervals described above, are separated by two dots (``..``). You can specify a start, an end, or both. An interval written back to front, such as ``2010..2008``, means the same as ``2008..2010``. Here is an example that finds all the albums added in 2008: :: $ beet ls -a 'added:2008' Find all items added in the years 2008, 2009 and 2010: :: $ beet ls 'added:2008..2010' Find all items added before the year 2010: :: $ beet ls 'added:..2009' Find all items added on or after 2008-12-01 but before 2009-10-12: :: $ beet ls 'added:2008-12..2009-10-11' Find all items with a file modification time between 2008-12-01 and 2008-12-03: :: $ beet ls 'mtime:2008-12-01..2008-12-02' You can also add an optional time value to date queries, specifying hours, minutes, and seconds. Times are separated from dates by a space, an uppercase 'T' or a lowercase 't', for example: ``2008-12-01T23:59:59``. If you specify a time, then the date must contain a year, month, and day. The minutes and seconds are optional. Here is an example that finds all items added on 2008-12-01 at or after 22:00 but before 23:00: :: $ beet ls 'added:2008-12-01T22' To find all items added on or after 2008-12-01 at 22:45: :: $ beet ls 'added:2008-12-01T22:45..' To find all items added on 2008-12-01, at or after 22:45:20 but before 22:45:41: :: $ beet ls 'added:2008-12-01T22:45:20..2008-12-01T22:45:40' Here are example of the three ways to separate dates from times. All of these queries do the same thing: :: $ beet ls 'added:2008-12-01T22:45:20' $ beet ls 'added:2008-12-01t22:45:20' $ beet ls 'added:2008-12-01 22:45:20' You can also use *relative* dates. For example, ``-3w`` means three weeks ago, and ``+4d`` means four days in the future. A relative date has three parts: - Either ``+`` or ``-``, to indicate the past or the future. The sign is optional; if you leave this off, it defaults to the future. - A number. - A letter indicating the unit: ``d``, ``w``, ``m`` or ``y``, meaning days, weeks, months or years. (A "month" is always 30 days and a "year" is always 365 days.) Here's an example that finds all the albums added since last week: :: $ beet ls -a 'added:-1w..' And here's an example that lists items added in a two-week period starting four weeks ago: :: $ beet ls 'added:-6w..-4w' .. _not_query: Query Term Negation ------------------- Query terms can also be negated, acting like a Boolean "not," by prefixing them with ``-`` or ``^``. This has the effect of returning all the items that do **not** match the query term. For example, this command: :: $ beet list ^love matches all the songs in the library that do not have "love" in any of their fields. Negation can be combined with the rest of the query mechanisms, so you can negate specific fields, regular expressions, etc. For example, this command: :: $ beet list -a artist:dylan ^year:1980..1989 "^album::the(y)?" matches all the albums with an artist containing "dylan", but excluding those released in the eighties and those that have "the" or "they" on the title. The syntax supports both ``^`` and ``-`` as synonyms because the latter indicates flags on the command line. To use a minus sign in a command-line query, use a double dash ``--`` to separate the options from the query: :: $ beet list -a -- artist:dylan -year:1980..1990 "-album::the(y)?" .. _pathquery: Path Queries ------------ Sometimes it's useful to find all the items in your library that are (recursively) inside a certain directory. Use the ``path:`` field to do this: :: $ beet list path:/my/music/directory $ beet list path:Artist/Album $ beet list path:Artist/Album/track.mp3 In fact, beets automatically recognizes any query term containing a path separator (``/`` on POSIX systems) as a path query if that path exists, so this command is equivalent as long as ``/my/music/directory`` exist: :: $ beet list /my/music/directory The ``path:`` field accepts either an absolute path under the configured music directory or a path relative to the library root. Note that this only matches items that are *already in your library*, so a path query won't necessarily find *all* the audio files in a directory---just the ones you've already added to your beets library. Path queries are case sensitive if the queried path is on a case-sensitive filesystem. Cover Art Queries ----------------- You can query items by whether they have embedded cover art using the ``has_cover_art`` field. This is useful for finding tracks that are missing artwork without needing external tools. To find all tracks with embedded cover art: .. code-block: shell $ beet list has_cover_art:true To find all tracks without embedded cover art: .. code-block: shell $ beet list has_cover_art:false This query checks the actual file for embedded images, so no re-importing or external tagging needed. .. _query-sort: Sort Order ---------- Queries can specify a sort order. Use the name of the ``field`` you want to sort on, followed by a ``+`` or ``-`` sign to indicate ascending or descending sort. For example, this command: :: $ beet list -a year+ will list all albums in chronological order. You can also specify several sort orders, which will be used in the same order as they appear in your query: :: $ beet list -a genre+ year+ This command will sort all albums by genre and, in each genre, in chronological order. The ``artist`` and ``albumartist`` keys are special: they attempt to use their corresponding ``artist_sort`` and ``albumartist_sort`` fields for sorting transparently (but fall back to the ordinary fields when those are empty). Lexicographic sorts are case insensitive by default, resulting in the following sort order: ``Bar foo Qux``. This behavior can be changed with the :ref:`sort_case_insensitive` configuration option. Case sensitive sort will result in lower-case values being placed after upper-case values, e.g., ``Bar Qux foo``. Note that when sorting by fields that are not present on all items (such as flexible fields, or those defined by plugins) in *ascending* order, the items that lack that particular field will be listed at the *beginning* of the list. You can set the default sorting behavior with the :ref:`sort_item` and :ref:`sort_album` configuration options. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/docs/reference/pathformat.rst�������������������������������������������������0000664�0001750�0001750�00000033117�15253035401�021645� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Path Formats ============ The ``paths:`` section of the config file (see :doc:`config`) lets you specify the directory and file naming scheme for your music library. Templates substitute symbols like ``$title`` (any field value prefixed by ``$``) with the appropriate value from the track's metadata. Beets adds the filename extension automatically. For example, consider this path format string: ``$albumartist/$album/$track $title`` Here are some paths this format will generate: - ``Yeah Yeah Yeahs/It's Blitz!/01 Zero.mp3`` - ``Spank Rock/YoYoYoYoYo/11 Competition.mp3`` - ``The Magnetic Fields/Realism/01 You Must Be Out of Your Mind.mp3`` Because ``$`` is used to delineate a field reference, you can use ``$$`` to emit a dollars sign. As with `Python template strings`_, ``${title}`` is equivalent to ``$title``; you can use this if you need to separate a field name from the text that follows it. .. _python template strings: https://docs.python.org/3/library/string.html#template-strings-strings A Note About Artists -------------------- Note that in path formats, you almost certainly want to use ``$albumartist`` and not ``$artist``. The latter refers to the "track artist" when it is present, which means that albums that have tracks from different artists on them (like `Stop Making Sense`_, for example) will be placed into different folders! Continuing with the Stop Making Sense example, you'll end up with most of the tracks in a "Talking Heads" directory and one in a "Tom Tom Club" directory. You probably don't want that! So use ``$albumartist``. .. _stop making sense: https://musicbrainz.org/release/798dcaab-0f1a-4f02-a9cb-61d5b0ddfd36 As a convenience, however, beets allows ``$albumartist`` to fall back to the value for ``$artist`` and vice-versa if one tag is present but the other is not. .. _template-functions: Template Functions ------------------ Beets path formats also support *function calls*, which can be used to transform text and perform logical manipulations. The syntax for function calls is like this: ``%func{arg,arg}``. For example, the ``upper`` function makes its argument upper-case, so ``%upper{beets rocks}`` will be replaced with ``BEETS ROCKS``. You can, of course, nest function calls and place variable references in function arguments, so ``%upper{$artist}`` becomes the upper-case version of the track's artists. These functions are built in to beets: - ``%lower{text}``: Convert ``text`` to lowercase. - ``%upper{text}``: Convert ``text`` to UPPERCASE. - ``%capitalize{text}``: Make the first letter of ``text`` UPPERCASE and the rest lowercase. - ``%title{text}``: Convert ``text`` to Title Case. - ``%left{text,n}``: Return the first ``n`` characters of ``text``. - ``%right{text,n}``: Return the last ``n`` characters of ``text``. - ``%if{condition,text}`` or ``%if{condition,truetext,falsetext}``: If ``condition`` is not empty, and not one of the values ``0`` or ``false`` (case insensitive), then returns the second argument. Otherwise, returns the third argument if specified (or nothing if ``falsetext`` is left off). - ``%asciify{text}``: Convert non-ASCII characters to their ASCII equivalents. For example, "café" becomes "cafe". Uses the mapping provided by the `unidecode module`_. See the :ref:`asciify-paths` configuration option. - ``%aunique{identifiers,disambiguators,brackets}``: Provides a unique string to disambiguate similar albums in the database. See :ref:`aunique`, below. - ``%sunique{identifiers,disambiguators,brackets}``: Similarly, a unique string to disambiguate similar singletons in the database. See :ref:`sunique`, below. - ``%time{date_time,format}``: Return the date and time in any format accepted by strftime_. For example, to get the year some music was added to your library, use ``%time{$added,%Y}``. - ``%first{text,count,skip,sep,join}``: Extract a subset of items from a delimited string. Splits ``text`` by ``sep``, skips the first ``skip`` items, then returns the next ``count`` items joined by ``join``. This is especially useful for multi-valued fields like ``artists``, ``genres``, ``remixers``, ``lyricists``, ``composers``, or ``arrangers`` where you may only want the first value or a limited number of values in a path. Defaults: .. Comically, you need to follow |semicolon_space| with some punctuation to make sure it gets rendered correctly as '; ' in the docs. - **count**: 1, - **skip**: 0, - **sep**: |semicolon_space|, - **join**: |semicolon_space|. Examples: :: %first{$genres} → returns the first genre %first{$genres,2} → returns the first two genres, joined by "; " %first{$genres,2,1} → skips the first genre, returns the next two %first{$genres,2,0, , -> } → splits by space, joins with " -> " - ``%ifdef{field}``, ``%ifdef{field,truetext}`` or ``%ifdef{field,truetext,falsetext}``: Checks if an flexible attribute ``field`` is defined. If it exists, then return ``truetext`` or ``field`` (default). Otherwise, returns ``falsetext``. The ``field`` should be entered without ``$``. Note that this doesn't work with built-in :ref:`itemfields`, as they are always defined. .. _strftime: https://docs.python.org/3/library/time.html#time.strftime .. _unidecode module: https://pypi.org/project/Unidecode Plugins can extend beets with more template functions (see :ref:`templ_plugins`). .. _aunique: Album Disambiguation -------------------- Occasionally, bands release two albums with the same name (c.f. Crystal Castles, Weezer, and any situation where a single has the same name as an album or EP). Beets ships with special support, in the form of the ``%aunique{}`` template function, to avoid placing two identically-named albums in the same directory on disk. The ``aunique`` function detects situations where two albums have some identical fields and emits text from additional fields to disambiguate the albums. For example, if you have both Crystal Castles albums in your library, ``%aunique{}`` will expand to "[2008]" for one album and "[2010]" for the other. The function detects that you have two albums with the same artist and title but that they have different release years. For full flexibility, the ``%aunique`` function takes three arguments. The first two are whitespace-separated lists of album field names: a set of *identifiers* and a set of *disambiguators*. The third argument is a pair of characters used to surround the disambiguator. Any group of albums with identical values for all the identifiers will be considered "duplicates". Then, the function tries each disambiguator field, looking for one that distinguishes each of the duplicate albums from each other. The first such field is used as the result for ``%aunique``. If no field suffices, an arbitrary number is used to distinguish the two albums. The default identifiers are ``albumartist album`` and the default disambiguators are ``albumtype year label catalognum albumdisambig releasegroupdisambig``. So you can get reasonable disambiguation behavior if you just use ``%aunique{}`` with no parameters in your path forms (as in the default path formats), but you can customize the disambiguation if, for example, you include the year by default in path formats. The default characters used as brackets are ``[]``. To change this, provide a third argument to the ``%aunique`` function consisting of two characters: the left and right brackets. Or, to turn off bracketing entirely, leave argument blank. One caveat: When you import an album that is named identically to one already in your library, the *first* album—the one already in your library— will not consider itself a duplicate at import time. This means that ``%aunique{}`` will expand to nothing for this album and no disambiguation string will be used at its import time. Only the second album will receive a disambiguation string. If you want to add the disambiguation string to both albums, just run ``beet move`` (possibly restricted by a query) to update the paths for the albums. .. _sunique: Singleton Disambiguation ------------------------ It is also possible to have singleton tracks with the same name and the same artist. Beets provides the ``%sunique{}`` template to avoid giving these tracks the same file path. It has the same arguments as the :ref:`%aunique <aunique>` template, but the default values are different. The default identifiers are ``artist title`` and the default disambiguators are ``year trackdisambig``. Syntax Details -------------- The characters ``$``, ``%``, ``{``, ``}``, and ``,`` are "special" in the path template syntax. This means that, for example, if you want a ``%`` character to appear in your paths, you'll need to be careful that you don't accidentally write a function call. To escape any of these characters (except ``{``, and ``,`` outside a function argument), prefix it with a ``$``. For example, ``$$`` becomes ``$``; ``$%`` becomes ``%``, etc. The only exceptions are: - ``${``, which is ambiguous with the variable reference syntax (like ``${title}``). To insert a ``{`` alone, it's always sufficient to just type ``{``. You do, however need to use ``$`` to escape a closing brace ``$}``. - commas are used as argument separators in function calls. Inside of a function's argument, use ``$,`` to get a literal ``,`` character. Outside of any function argument, escaping is not necessary: ``,`` by itself will produce ``,`` in the output. If a value or function is undefined, the syntax is simply left unreplaced. For example, if you write ``$foo`` in a path template, this will yield ``$foo`` in the resulting paths because "foo" is not a valid field name. The same is true of syntax errors like unclosed ``{}`` pairs; if you ever see template syntax constructs leaking into your paths, check your template for errors. If an error occurs in the Python code that implements a function, the function call will be expanded to a string that describes the exception so you can debug your template. For example, the second parameter to ``%left`` must be an integer; if you write ``%left{foo,bar}``, this will be expanded to something like ``<ValueError: invalid literal for int()>``. .. _itemfields: Available Values ---------------- Here's a list of the different values available to path formats. The current list can be found definitively by running the command ``beet fields``. Note that plugins can add new (or replace existing) template values (see :ref:`templ_plugins`). Ordinary metadata: - title - artist - artist_sort: The "sort name" of the track artist (e.g., "Beatles, The" or "White, Jack"). - artist_credit: The track-specific `artist credit`_ name, which may be a variation of the artist's "canonical" name. - artists: The track artists as a multi-valued field. - album - albumartist: The artist for the entire album, which may be different from the artists for the individual tracks. - albumartists: The album artists as a multi-valued field. - albumartist_sort - albumartist_credit - genre - genres: The track genres as a multi-valued field. - arrangers: The track arrangers as a multi-valued field. - composers: The track composers as a multi-valued field. - lyricists: The track lyricists as a multi-valued field. - remixers: The track remixers as a multi-valued field. - grouping - subtitle - year, month, day: The release date of the specific release. - original_year, original_month, original_day: The release date of the original version of the album. - track - tracktotal - disc - disctotal - lyrics - comments - bpm - comp: Compilation flag. - albumtype: The MusicBrainz album type; the MusicBrainz wiki has a `list of type names`_. - label - asin - catalognum - script - language - country - albumstatus - media - albumdisambig - disctitle - encoder .. _artist credit: https://wiki.musicbrainz.org/Artist_Credit .. _list of type names: https://musicbrainz.org/doc/Release_Group/Type Audio information: - length (in seconds) - bitrate (in kilobits per second, with units: e.g., "192kbps") - bitrate_mode (e.g., "CBR", "VBR" or "ABR", only available for the MP3 format) - encoder_info (e.g., "LAME 3.97.0", only available for some formats) - encoder_settings (e.g., "-V2", only available for the MP3 format) - format (e.g., "MP3" or "FLAC") - channels - bitdepth (only available for some formats) - samplerate (in kilohertz, with units: e.g., "48kHz") MusicBrainz and fingerprint information: - mb_trackid - mb_releasetrackid - mb_albumid - mb_artistid - mb_albumartistid - mb_releasegroupid - acoustid_fingerprint - acoustid_id Library metadata: - mtime: The modification time of the audio file. - added: The date and time that the music was added to your library. - path: The item's filename. .. _templ_plugins: Template functions and values provided by plugins ------------------------------------------------- Beets plugins can provide additional fields and functions to templates. See the :doc:`/plugins/index` page for a full list of plugins. Some plugin-provided constructs include: - ``$missing`` by :doc:`/plugins/missing`: The number of missing tracks per album. - ``$album_artist_no_feat`` by :doc:`/plugins/ftintitle`: The album artist without any featured artists - ``%bucket{text}`` by :doc:`/plugins/bucket`: Substitute a string by the range it belongs to. - ``%the{text}`` by :doc:`/plugins/the`: Moves English articles to ends of strings. - ``%titlecase{text}`` by :doc:`/plugins/titlecase`: Format text according to title case guidelines. The :doc:`/plugins/inline` lets you define template fields in your beets configuration file using Python snippets. And for more advanced processing, you can go all-in and write a dedicated plugin to register your own fields and functions (see :ref:`basic-plugin-setup`). �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.pre-commit-config.yaml�������������������������������������������������������0000664�0001750�0001750�00000000707�15253035401�020340� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: - repo: local hooks: - id: format name: Format Python files entry: poe format language: system files: '.*.py' pass_filenames: true - id: format-docs name: Format docs entry: poe format-docs language: system files: '.*.rst' pass_filenames: true ���������������������������������������������������������beetbox-beets-00724b7/.git-blame-ignore-revs��������������������������������������������������������0000664�0001750�0001750�00000027437�15253035401�020170� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# 2014 # flake8-cleanliness in missing e21c04e9125a28ae0452374acf03d93315eb4381 # 2016 # Removed unicode_literals from library, logging and mediafile 43572f50b0eb3522239d94149d91223e67d9a009 # Removed unicode_literals from plugins 53d2c8d9db87be4d4750ad879bf46176537be73f # reformat flake8 errors 1db46dfeb6607c164afb247d8da82443677795c1 # 2021 # pyupgrade root e26276658052947e9464d9726b703335304c7c13 # pyupgrade beets dir 6d1316f463cb7c9390f85bf35b220e250a35004a # pyupgrade autotag dir f8b8938fd8bbe91898d0982552bc75d35703d3ef # pyupgrade dbcore dir d288f872903c79a7ee7c5a7c9cc690809441196e # pyupgrade ui directory 432fa557258d9ff01e23ed750f9a86a96239599e # pyupgrade util dir af102c3e2f1c7a49e99839e2825906fe01780eec # fix unused import and flake8 910354a6c617ed5aa643cff666205b43e1557373 # pyupgrade beetsplug and tests 1ec87a3bdd737abe46c6e614051bf9e314db4619 # Updates docstrings in library.py. 8c5ced3ee11a353546034189736c6001115135a4 # Fixes inconsistencies in ending quote placements for single-line docstrings. bbd32639b4c469fe3d6668f1e3bb17d8ba7a70ce # Fixes linting errors by removing trailing whitespaces. acf576c455e59e8197359d4517f8c0a5a9f362bb # Alters docstrings in library.py to be imperative-style. 2f42c8b1c019a90448d33d940b609c18ba644cbc # 2022 # Reformat flake8 config comments abc3dfbf429b179fac25bd1dff72d577cd4d04c7 # 2023 # Apply formatting tools to all files a6e5201ff3fad4c69bf24d17bace2ef744b9f51b # 2024 # Replace assertTrue 0ecc345143cf89fabe74bb2e95eedfa1114857a3 # Replace assertFalse cb82917fe0d5476c74bb946f91ea0d9a9f019c9b # Replace assertIsNone 5d4911e905d3a89793332eb851035e6529c0725e # Replace assertIsNotNone 2616bcc950e592745713f28db0192293410ed3e3 # Replace assertIn 11e948121cde969f9ea27caa545a6508145572fb # Replace assertNotIn 6631b6aef6da3e09d3531de6df7995dd5396398f # Replace assertEqual 9a05d27acfef3788d10dd0a8db72a6c8c15dfbe9 # Replace assertNotEqual f9359df0d15ea8ee8e3c80bc198e779f185160cb # Replace assertIsInstance eda0ef11d67f482fe50bbe581685b8b6a284afb9 # Replace assertLess and assertLessEqual 6a3380bcb5e803e825bd9485fcc4b70d352947eb # Replace assertGreater and assertGreaterEqual 46bdb84b464ffec3f0ce88d53467391be7b7046f # Replace assertCountEqual fdb8c28271e8b22d458330598a524067ca37026e # Replace assertListEqual fcc4d8481df295019945ac7973906f960c58c9fb # Use f-string syntax 4b69b493d2630b723684f259ee9e7e07c480e8ee # Reformat the codebase 85a17ee5039628a6f3cdcb7a03d7d1bd530fbe89 # Fix lint issues f36bc497c8c8f89004f3f6879908d3f0b25123e1 # Remove some lint exclusions and fix the issues 5f78d1b82b2292d5ce0c99623ba0ec444b80d24c # Use PEP585 lowercase collections typing annotations 51f9dd229e64f5106d69f87906a94e75604f346b # Remove unnecessary quotes from types fbfdfd54446fab6782ef0629da303f14f0a2ecdf # Replace Union types by PEP604 pipe character 7ef1b61070ed4ed79c4720d019968baf38e38050 # Update deprecated imports 161b0522bbf7f4984173fee4128416b05f6cc5f3 # Move imports required for typing under the TYPE_CHECKING block 5c81f94cf7ced476673d0fa948cc7ecda00bae99 # 2025 # Fix formatting c490ac5810b70f3cf5fd8649669838e8fdb19f4d # Importer restructure 9147577b2b19f43ca827e9650261a86fb0450cef # Renamed all `action` occurrences with `Action`. 68acaa6470a04474a2aefe9b1de71ae7fa10b861 # Move functionality under MusicBrainz plugin 529aaac7dced71266c6d69866748a7d044ec20ff # musicbrainz: reorder methods 5dc6f45110b99f0cc8dbb94251f9b1f6d69583fa # Copy paste query, types from library to dbcore 1a045c91668c771686f4c871c84f1680af2e944b # Library restructure (split library.py into multiple modules) 0ad4e19d4f870db757373f44d12ff3be2441363a # Split library file into different files inside library folder. 98377ab5f6fc1829d79211b376bfd8d82bafaf33 # Use pathlib.Path in test_smartplaylist.py d017270196dc8e0e2a4051afa5d05213946cbbbc # Replace assertIsFile ca4fa6ba10807f4a48a428d23e45c023c15dfa7d # Replace assertIsDir 43b8cce063b1a1ef079266f362272307fb328d73 # Replace assertFileTag and assertNoFileTag c6b5b3bed31704f7fe8632a6aef1a2348028348f # Replace assertAlbumImport 3c8179a762c4387f9c40a12e3b9e560ff1c194ec # Replace assertCount 72caf0d2cdc8fcefe1c252bdb0ac9b11b90cc649 # Docs: fix linting issues 769dcdc88a1263638ae25944ba6b2be3e8933666 # Reformat all docs using docstrfmt ab5acaabb3cd24c482adb7fa4800c89fd6a2f08d # Replace format calls with f-strings 4a361bd501e85de12c91c2474c423559ca672852 # Replace percent formatting 9352a79e4108bd67f7e40b1e944c01e0a7353272 # Replace string concatenation (' + ') 1c16b2b3087e9c3635d68d41c9541c4319d0bdbe # Do not use backslashes to deal with long strings 2fccf64efe82851861e195b521b14680b480a42a # Do not use explicit indices for logging args when not needed d93ddf8dd43e4f9ed072a03829e287c78d2570a2 # Moved dev docs 07549ed896d9649562d40b75cd30702e6fa6e975 # Moved plugin docs Further Reading chapter 33f1a5d0bef8ca08be79ee7a0d02a018d502680d # Moved art.py utility module from beets into beetsplug 28aee0fde463f1e18dfdba1994e2bdb80833722f # Refactor `ui/commands.py` into multiple modules 59c93e70139f70e9fd1c6f3c1bceb005945bec33 # Moved ui.commands._utils into ui.commands.utils 25ae330044abf04045e3f378f72bbaed739fb30d # Refactor test_ui_command.py into multiple modules a59e41a88365e414db3282658d2aa456e0b3468a # pyupgrade Python 3.10 301637a1609831947cb5dd90270ed46c24b1ab1b # Fix changelog formatting 658b184c59388635787b447983ecd3a575f4fe56 # Configure future-annotations ac7f3d9da95c2d0a32e5c908ea68480518a1582d # Configure ruff for py310 c46069654628040316dea9db85d01b263db3ba9e # Enable RUF rules 4749599913a42e02e66b37db9190de11d6be2cdf # Address RUF012 bc71ec308eb938df1d349f6857634ddf2a82e339 # 2026 # Move changelog note under Unreleased section 1fe5bad4b27d2845aad16f0afae91fe389f299fb # Replace http URLs with https 3d0d032987c4c2e9550529fd25e79581b06ade73 # Fix broken URLs 441c8383873d72d4bb0387cdf1863c0fe9e11098 # Fix redirect URLs ae3a2e5729e3c0a5acbd8967ba2f11f4c53acd09 # Format docs 192217da5d70621089b06b06fff3dbcbeb4c0c4d # Add a changelog note b3f558584910ab4fc6aa185ec4a4c8554001ba24 # Fix references to color utils a6fcb7ba0f237530ff394a423a7cbe2ac4853c91 # Fix diff references 1d54f2bf66506e7a45ce5e962106897e3c98f67a # Fix layout references ffb43290066c78cb72603b7e2a0a1c90056361dd # lastgenre: Move fetching to client module b4beee8ff3754b001e7504c05a2b838bfa689022 # autotag: use explicit imports b8def07121431421118ff7d569f8187aae0520f2 # sort: Update imports d4fd36a03384b0f71144932833d9c633c1f9545f # sort: Update dotted sort references 0cd20798aa585f162433423f767c047b7474a70e # Reformat using skip-magic-trailing-comma adfb73b66dba0fc799880af176ef6f9ac0a7ee68 # Refactor test_library 6493d4dd018e08eb5d16d5381ebff47deea98bb1 # Import everything from parent beets.autotag 29580d2f00eb02f1ce77ebe3e1435804f7252ba1 # Move Match classes to beets.autotag.match fd46e5b7738a3e11ef01e6fa8dc6fb8e0c7c82ec # Add setup fixture to TestHelper 7bad226c33c2d48b5102cff213c67f16eeb09a7b # Fix mbcollection tests 544ea3af5d85df187e080f407d3aaf84eac4ee63 # Fix ftintitle tests ca8544d4bcab503e1e4c2cd6688655c8211aa7a1 # Fix autobpm tests 5804a21620098e8da78b1f4a5f85063033586632 # Enable and fix flake8-pie 3a419c6a347803fc962f018f5ad027b5399ab3ae # Enable and fix flake8-return d0dc5f86a626765c86cdadc348595429f4c6e6ef # Enable and fix flake8-builtins b7974ace83ab193b6417bdcecaf68a742bf5a1a8 # Preserve importer config views c9ad80dad2528af67cdb76c35d7ba5e4824b7600 # Type _reduce_and_log c070b29e14cd06419e129b76a6d42a82fe51e190 # Add missing types to importer e4baceae1fa03dfd6db9e0bab88ddd2812963ad3 # Add missing types to beets.util.pipeline f0105bef73053098f8755376c88f38cc90d9b23f # Rip out util tests from test_files b1ae461723316b738f301406198382913207e100 # Rip out queryparse tests away from test_dbcore 88202493adb769e667f64a96a3ec0270f46ca60e # Define DB fixtures in a shared place 816cddbfd5d0976a31e9d0788db0944c62ad16db # Move test modules under folders that they belong to 900543baca4cf5fa4dbe52dbe748f98a0371d0ed # Move DummyIMBackend to fixtures aef9c64cb07c8f828d0dd6e69a5485abf2c43396 # typing: add types to beets.util 94ef7d8d1f37d87268abed6a4bd5df054912092f # typing: make path utils more flexible re path types 1418a80e0531fba1e01d0ad2a4decdefaed6b365 # typing: add types to beets.test.helper 29c887db5bff1cfc4c6ea60505636742fa41cccf # typing: type beets.dbcore.db 8d03803fcf1b18385e477cb9273553e2431447ce # typing: type beets.dbcore.sort ca8e9f69a8a0254aa767dc86f6d808d02f6af05d # typing: type beets.dbcore.query b1701c2e12b2de8e5462affe46ecc6816a5fc508 # typing: type beets.dbcore.types ea3d6af6169d33be009b86bf5607baae7cf9652a # Fix #6177, remove derived types, refactor coalesce tracks 9efe87101ce03706660129633e03147a222765cf # typing: type beets.library.exceptions fcee48fb0a11003afab1f4eb7334dca1e4842606 # typing: type beets.library.queries c6b87e869e44bd53fccc9603b682351c96612583 # dbcore: rename Database._fetch to Database.get_results 856087258b3466f09d557a054e4b7cc4cdc25638 # typing: type beets.library.library f167dc29e41439e342c04c073758102b2a2e1af8 # typing: add return types to beets.library.models 8949562ef8f4e83ef281674c6125b041991d3d26 # typing: type models in beets.library.models 9b375d0b2d2dc9388892f1b901aae67ab0ad8290 # typing: type the rest of beets.library.models 9022cb5ed7fddf60c1156dc3ca7e3a540dc8f7f2 # Replace ImporterMixin.import_dir attribute with ImporterMixin.import_path 7970a90214fcd64ab5fef1c71b7bf1413ad6ce86 # Replace TestHelper.libdir attribute with TestHelper.lib_path dc2826fa4b32b625eb4ac9d71934176edde2443e # Replace PathsMixin.temp_dir attribute with PathsMixin.temp_dir_path 2e9ace7b20e776ad10127b2f6ac76791e2a19704 # Rename PathsMixin.temp_dir_path to PathsMixin.temp_path for consistency d24c0d341ec6074c343cd8054083fe358da8fa14 # Fix yoda typedefs 5dcc35112d17976a11ffc468cf436bc3e2342e54 # Replace item.path with item.filepath in tests 04c2304879d088ea9be1fad475caf022608a3145 # Use pathlib.Path wherever possible in tests 951e32a852b48f87e3dd2ccf71753ee8f7ac2e34 # Remove syspath b2f52ac12443c102712b735e456fd07a6525786b # Return Path from TestHelper.create_mediafile_fixture bb66b0c378e9bf7d97622a1582d93c4dfcf20fdd # Move AttrDict under beets.util ea334bd977ee8ed0cdbd627b7e9564dd08dd43f7 # typing: type handlers and listeners explicitly 88627e062b452e936bf0e7e90554cd56e3713288 # typing: Define events in a separate module, import explicitly e9021e17e9f14af8b4805ce1ec7f32843ada7970 # typing: Import events module instead dcc1fd0e4a3e7137d126f224d8f5d9911291652e # typing: add types to event handlers 5039c8f6cff474bec54b2106dd7c7d0cd39878f2 # typing: make dbcore.db.Results a Sequence 9adcb601f86b8758cb179ac5d39ca4857846cb27 # typing: add types to embedart 26713de0d64b8412ac922d0402929504f6f3c6c7 # typing: add types to beetsplug._utils.art 6acef1d5864716300f2c4add4e19cc6e737cce46 # typing: add types to beets.ui.import_ 2a9786aad7bc8114276e1fda2a3d141abf2608f3 # typing: add types to beets.util.functemplate d8fc064e9c3b428ee6aad5f50d34dc66aba742f2 # typing: remove redundant types f37306b0cc17f17291ea5010178f190a95b29fd5 # Prefer imports from modules that provide import aliases 27900f58fbeba06483b77c677045ad1df8e9af45 # typing: rename AnyLibModel -> AlbumOrItem 33a01fe0b37942a38c8b88d0fc8167edd02ca81b # typing: add types to command handlers 14eabc60600ff3c8ef1908100ae7abd3aa998bc4 # typing: add missing core annotations 029de94b206bd64aecc24f24bf011413b86d78e7 # typing: add annotations to bpd plugin 1ae87783858f53b62ccdc4f9400e035ef03f843a # typing: add annotations to API and export plugins ee4d6eef36269fbf99e0f566487ab21069be279f # typing: add annotations to metadata source plugins 21e045795d2478a7f45a81bbc095ccf3aa69d59f # typing: add annotations to mpdstats 4f0ac15b99cc240a6b611d2b70f29f1e576d6418 # typing: add annotations to thumbnails 6b4f8fa25b744adf05a3e9199e470d663f297502 # typing: add types to duplicates plugin 8e4fa56acb73216f36769090b322088ff2ed5364 # typing: add missing types to plugins 11d41aee7d3253ae702d1519a1b8f78df4596132 # typing: various consistency fixes 5c3695da262ec64e52ec8057302fe2d852b62afa ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.gitignore��������������������������������������������������������������������0000664�0001750�0001750�00000002236�15253035401�016046� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# general hidden files/directories .DS_Store .idea # file patterns *~ # Project Specific patterns man # The rest is from https://www.gitignore.io/api/python ### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64 parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache coverage.xml *,cover .hypothesis/ .reports # Flask stuff: instance/ .webassets-cache # Sphinx documentation docs/_build/ # PyBuilder target/ # pyenv .python-version # dotenv .env # virtualenv env/ venv/ .venv/ ENV/ # Spyder project settings .spyderproject # Rope project settings .ropeproject # PyDev and Eclipse project settings /.project /.pydevproject /.settings .vscode # pyright pyrightconfig.json # Pyrefly pyrefly.toml ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/uv.lock�����������������������������������������������������������������������0000664�0001750�0001750�00003006432�15253035401�015367� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������version = 1 revision = 3 requires-python = ">=3.10, <3.15" resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", "python_full_version < '3.11'", ] [[package]] name = "accessible-pygments" version = "0.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pygments" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, ] [[package]] name = "alabaster" version = "1.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, ] [[package]] name = "anyio" version = "4.14.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, ] [[package]] name = "apeye" version = "1.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "apeye-core" }, { name = "domdf-python-tools" }, { name = "platformdirs" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4f/6b/cc65e31843d7bfda8313a9dc0c77a21e8580b782adca53c7cb3e511fe023/apeye-1.4.1.tar.gz", hash = "sha256:14ea542fad689e3bfdbda2189a354a4908e90aee4bf84c15ab75d68453d76a36", size = 99219, upload-time = "2023-08-14T15:32:41.381Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/89/7b/2d63664777b3e831ac1b1d8df5bbf0b7c8bee48e57115896080890527b1b/apeye-1.4.1-py3-none-any.whl", hash = "sha256:44e58a9104ec189bf42e76b3a7fe91e2b2879d96d48e9a77e5e32ff699c9204e", size = 107989, upload-time = "2023-08-14T15:32:40.064Z" }, ] [[package]] name = "apeye-core" version = "1.1.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "domdf-python-tools" }, { name = "idna" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e5/4c/4f108cfd06923bd897bf992a6ecb6fb122646ee7af94d7f9a64abd071d4c/apeye_core-1.1.5.tar.gz", hash = "sha256:5de72ed3d00cc9b20fea55e54b7ab8f5ef8500eb33a5368bc162a5585e238a55", size = 96511, upload-time = "2024-01-30T17:45:48.727Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/77/9f/fa9971d2a0c6fef64c87ba362a493a4f230eff4ea8dfb9f4c7cbdf71892e/apeye_core-1.1.5-py3-none-any.whl", hash = "sha256:dc27a93f8c9e246b3b238c5ea51edf6115ab2618ef029b9f2d9a190ec8228fbf", size = 99286, upload-time = "2024-01-30T17:45:46.764Z" }, ] [[package]] name = "appdirs" version = "1.4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/d8/05696357e0311f5b5c316d7b95f46c669dd9c15aaeecbb48c7d0aeb88c40/appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", size = 13470, upload-time = "2020-05-11T07:59:51.037Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128", size = 9566, upload-time = "2020-05-11T07:59:49.499Z" }, ] [[package]] name = "ast-serialize" version = "0.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/58/ad/0d70a3a2d6e01968d985415259e8ec7ad3f777903f9b1c1f3c8c44642c60/ast_serialize-0.6.0.tar.gz", hash = "sha256:aadd3ffcf4858c9726bf3515f7b199c7eadbe504f96028e4a87172c0da65a8fe", size = 61489, upload-time = "2026-06-30T20:02:55.555Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3f/12/3e5f575f156555547c250a8b0d1347517a3a20fc7f4492e9703a69d4f45e/ast_serialize-0.6.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:a7520b672827885bafeae7501f684d14d47d17e5f45256f9df547686cca52264", size = 1177640, upload-time = "2026-06-30T20:02:06.708Z" }, { url = "https://files.pythonhosted.org/packages/a2/a4/921a9e27951627983b0f368859ea00f8330a551dc0bf4c2fdcb11855a98b/ast_serialize-0.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a14191beec7e0c078d2fc1f6edc0aee88bcd4db9f18e1bc9f8052b559c22dddc", size = 1168111, upload-time = "2026-06-30T20:02:08.366Z" }, { url = "https://files.pythonhosted.org/packages/00/69/950cf404de7b8782cf95e5c1237e25e2aa46177b287f39f9eeddf481fd6f/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32ef62ec34cf6be20ad77d4799556638fbdf187f3ae10698dfb20ef9f2c89516", size = 1227656, upload-time = "2026-06-30T20:02:09.843Z" }, { url = "https://files.pythonhosted.org/packages/4c/a8/46f8f6a6479d9d2273980957bb091a506c55f5b95d3c029ee58518a78407/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13b7769970a39983b0adf2f38917b1cd3b8946f76df045756c3d741bc689f089", size = 1227706, upload-time = "2026-06-30T20:02:11.367Z" }, { url = "https://files.pythonhosted.org/packages/b7/b9/9ac415bda0a40e49eab8fea3b2741c19c98bb84d57d62c4cfc6230eb67be/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f7a408601bb3edaefb3bc67a4c01f5235e3253653b6a5729a2ee2382b35341c", size = 1431705, upload-time = "2026-06-30T20:02:12.737Z" }, { url = "https://files.pythonhosted.org/packages/e5/06/8807115d441444879f7561b5eede5ac18fc80392f11826d61ccf31f503b1/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8670bfa51208a2c0c8d138928e40e998fab158f9200d53bb80c088b5b8eda7b8", size = 1249533, upload-time = "2026-06-30T20:02:14.571Z" }, { url = "https://files.pythonhosted.org/packages/3e/c0/c2ba82ef9618650357d9421a1fdb27ffec862a7f57e8e2de82a3ccd11e12/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4826809eb8597a8cd59fd924b6d7c285b8969a1e0007e2cb652cab62376270f", size = 1252619, upload-time = "2026-06-30T20:02:16.219Z" }, { url = "https://files.pythonhosted.org/packages/0f/a7/fa31d52dd4102cede29fb9634e98d214129b2783b4f95528c6dc6a8f6587/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:577a6c189068686869f5f1ddc38363f3ae1808a4753b577266f9202071a7bb66", size = 1242983, upload-time = "2026-06-30T20:02:17.813Z" }, { url = "https://files.pythonhosted.org/packages/b1/20/ddf742b5ad3c4bafd3466f2265037cfd99bc1b9a5ee46a5d58c90d523242/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:085de7f62dc9cc247eb01e965a362707d1d90b1d89a82c5bf78301a60a3c417b", size = 1296148, upload-time = "2026-06-30T20:02:19.146Z" }, { url = "https://files.pythonhosted.org/packages/24/cb/9f6f217cce8b3b632c5568b478d195a35e79dce4dbe309438cb89ba6ea4f/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9f8a8b78b13173de6a9ec22111d9be674874cd5bdccda04f14ae5ebc2bef403a", size = 1403826, upload-time = "2026-06-30T20:02:20.696Z" }, { url = "https://files.pythonhosted.org/packages/2d/f8/9d16d4f0107a183924425cc0e7618d8bf76f96b45afa9ff19f924ed1ad57/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f2ff3baffc3a29c1f15bc9098aa0c09763410262d5e6cef42116f7356c184554", size = 1502943, upload-time = "2026-06-30T20:02:22.034Z" }, { url = "https://files.pythonhosted.org/packages/80/dd/bbc1c38756350dddf7e24acae1c9482ef42051c267417e019aecc1ed4075/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0067b25fce104eaae5b88383de9ab803faeb671831e14ca698b771b356e2600f", size = 1497632, upload-time = "2026-06-30T20:02:23.517Z" }, { url = "https://files.pythonhosted.org/packages/42/7e/9daffefcf5b97e6bb4c3e0b3c024c1aee9722f23d3cf7cd2ff80d6fb4a40/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c617417f9cbb0cb144f6283c3cbe0d2e0f01beaf9f608f662b21191058a626ec", size = 1448858, upload-time = "2026-06-30T20:02:24.889Z" }, { url = "https://files.pythonhosted.org/packages/e5/1f/f9baaab81a677ea0af7d2458cac2f94ebcc85958f8a3c15ba9d9e5dab653/ast_serialize-0.6.0-cp314-cp314t-win32.whl", hash = "sha256:5337cb256dcea3df9288205213d1601581536526b8f4da44b6974f1180f3252a", size = 1052600, upload-time = "2026-06-30T20:02:26.263Z" }, { url = "https://files.pythonhosted.org/packages/9e/1f/41b535866519512d8cf6669cb2cff7823b7672bb6279c0333b4ff89d7d9f/ast_serialize-0.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2d947e45cafc4b09bd7528917fa84c517654a43de173c79785574b7b3068ac24", size = 1095570, upload-time = "2026-06-30T20:02:27.639Z" }, { url = "https://files.pythonhosted.org/packages/50/64/e472fe3e3a2d33d874b987e8518aedf24562919e3b6161a4fa1797e89c0f/ast_serialize-0.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6e15ec740436e1a0d62de848641abe5f3a2f89a7f94907d534795ac91bbacf14", size = 1067267, upload-time = "2026-06-30T20:02:28.949Z" }, { url = "https://files.pythonhosted.org/packages/52/19/ac8348ae8711c9b5ae834634f635780cab62a0f5e6f988882e048b89c2ae/ast_serialize-0.6.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:093cb8bb91b720d8523580498d031791bb1bbaa048599c3d21085d380e11a596", size = 1185367, upload-time = "2026-06-30T20:02:30.427Z" }, { url = "https://files.pythonhosted.org/packages/c1/f6/ec7ec652c51db77c2f61d8573338e13e4704303265ccc658cb4031d9f354/ast_serialize-0.6.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e61580a69faf47e3689795367ed211f2a10fd741478cc0f36a0f128793360aad", size = 1178657, upload-time = "2026-06-30T20:02:31.964Z" }, { url = "https://files.pythonhosted.org/packages/6f/02/613a7534a41d0122f37d1e0c64aa8ac78bfb831f8c92f6db057a311abb3c/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305802f2ce2a7c4e87835078ea85c58b586ddda8095b92fe2ead9364ae19c80a", size = 1238620, upload-time = "2026-06-30T20:02:33.664Z" }, { url = "https://files.pythonhosted.org/packages/4d/21/087957bba486242afc52f49b2d9e21c9dad00289356cf9efe67084015a9d/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c7b8b8f0c42f752ea00b2b7d7c090b3f80d9c1c5c75cadf16423790a0cc74081", size = 1236075, upload-time = "2026-06-30T20:02:34.936Z" }, { url = "https://files.pythonhosted.org/packages/82/04/78128bbb170071c2c72a210a181f1c00e11cc1cec60a8beef747b07f9201/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd5b91b9e6f2356ace3a556963b0cd783b395fbbb0bb17b4defc283415466e77", size = 1441348, upload-time = "2026-06-30T20:02:36.245Z" }, { url = "https://files.pythonhosted.org/packages/64/64/62fb99d6faf199b4c3e5b08a07136e9a0d7664bb249c6de3670e5b63e9b6/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d6ef91590258ada18909b9caea344dac4de2013906b035473cd674a43f4b790", size = 1258580, upload-time = "2026-06-30T20:02:37.53Z" }, { url = "https://files.pythonhosted.org/packages/ca/87/b4d6c38e0ccd5e85dc54cecdf933a152c60b28fe5d993a6d8a72fa6d5896/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcbed41e9386059fc0261d602445ede0976c2ecec2939688bcbcb9ed0b6f28b7", size = 1261693, upload-time = "2026-06-30T20:02:39.123Z" }, { url = "https://files.pythonhosted.org/packages/0e/4b/3676ca2191f39bafb75f93f99b2f429ec464586158fece2165f3572805dc/ast_serialize-0.6.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:cdc4e6f930b9090c2f92c9036ad12ffb8e6e44d4a5ba06f1458a05d60f203f7b", size = 1252517, upload-time = "2026-06-30T20:02:40.511Z" }, { url = "https://files.pythonhosted.org/packages/f3/58/494ef8c4b4acb2f4a265ac934caf45f792a08fe27d6b853de35ad991941a/ast_serialize-0.6.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:897ac47b5637be41c0c07061c8a912fafa967ef1dc73fa115e4bfa70882a093b", size = 1304843, upload-time = "2026-06-30T20:02:41.961Z" }, { url = "https://files.pythonhosted.org/packages/b1/f2/13736d920ab3d49bbee80ef1a277dd7b7aaf3b3545efd9d2a8114fe05525/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c4af9a1386166e40ed01464991806f89038a2d89782576c7774876fa77034e32", size = 1413698, upload-time = "2026-06-30T20:02:44.179Z" }, { url = "https://files.pythonhosted.org/packages/a8/5a/e046f3899e2acba4677d7427b76431443a1aa1a0e583dfb05b55b69d55cf/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:c901adbd750029b9ac4ad3d6aa56853e0ad4875119fbf52b7b8298afc223828b", size = 1512209, upload-time = "2026-06-30T20:02:45.584Z" }, { url = "https://files.pythonhosted.org/packages/cc/c7/e42aaca7bb2d22a7c06d5a8c7930086c5a334e93d716e6fa5e6647a4515f/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae22a366b752ab4496191525b78b097b5b72d531752e3c1dd7e383a8f2c8a1a", size = 1508464, upload-time = "2026-06-30T20:02:46.942Z" }, { url = "https://files.pythonhosted.org/packages/95/93/5524a3dc6c3f593de3228ed9cbef73afa047625b7000ec21b7f58e6eb4d4/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4ed29121da8b3fdc291002801a1de0f76248fa07dce89157a5f277842cf6126e", size = 1457164, upload-time = "2026-06-30T20:02:48.294Z" }, { url = "https://files.pythonhosted.org/packages/4f/c0/36a6ffb4d653cf621427b4c4928671f53ad800c453474de2b82564a44ad9/ast_serialize-0.6.0-cp39-abi3-pyemscripten_2026_0_wasm32.whl", hash = "sha256:b1dac4e09d341c1300ba69cdcbe62867b32a8c75d90db9bf4d083bec3b039f0b", size = 863014, upload-time = "2026-06-30T20:02:49.742Z" }, { url = "https://files.pythonhosted.org/packages/09/c7/7d5ad8b49e1278e1c2a1e0274bd7850560b3f09313aa00c13bc8d5544792/ast_serialize-0.6.0-cp39-abi3-win32.whl", hash = "sha256:82c312a7844d2fdeb4d5c48bd3d215bf940dafd4704e1a9bcf252a99010a99b1", size = 1063165, upload-time = "2026-06-30T20:02:50.98Z" }, { url = "https://files.pythonhosted.org/packages/47/ae/6710c14ecb276031cf10249f6adf5a59e2d3fdb3b5183bd59f70524067ee/ast_serialize-0.6.0-cp39-abi3-win_amd64.whl", hash = "sha256:113b58346f9ceb664352032770caca817d4a3c86f611c6088e6ef65ddaa70f0e", size = 1101444, upload-time = "2026-06-30T20:02:52.554Z" }, { url = "https://files.pythonhosted.org/packages/66/40/c53deb2cd0c9b0fb636d24d9f40924cf2e65028e6b20b10cd5c1eeb2c730/ast_serialize-0.6.0-cp39-abi3-win_arm64.whl", hash = "sha256:ccd132fe8db56f61fe743b1f644d01b8d65b83248a8da506f3132bda86d6ed5e", size = 1072965, upload-time = "2026-06-30T20:02:54.097Z" }, ] [[package]] name = "audioop-lts" version = "0.2.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/38/53/946db57842a50b2da2e0c1e34bd37f36f5aadba1a929a3971c5d7841dbca/audioop_lts-0.2.2.tar.gz", hash = "sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0", size = 30686, upload-time = "2025-08-05T16:43:17.409Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/de/d4/94d277ca941de5a507b07f0b592f199c22454eeaec8f008a286b3fbbacd6/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800", size = 46523, upload-time = "2025-08-05T16:42:20.836Z" }, { url = "https://files.pythonhosted.org/packages/f8/5a/656d1c2da4b555920ce4177167bfeb8623d98765594af59702c8873f60ec/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303", size = 27455, upload-time = "2025-08-05T16:42:22.283Z" }, { url = "https://files.pythonhosted.org/packages/1b/83/ea581e364ce7b0d41456fb79d6ee0ad482beda61faf0cab20cbd4c63a541/audioop_lts-0.2.2-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75", size = 26997, upload-time = "2025-08-05T16:42:23.849Z" }, { url = "https://files.pythonhosted.org/packages/b8/3b/e8964210b5e216e5041593b7d33e97ee65967f17c282e8510d19c666dab4/audioop_lts-0.2.2-cp313-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d", size = 85844, upload-time = "2025-08-05T16:42:25.208Z" }, { url = "https://files.pythonhosted.org/packages/c7/2e/0a1c52faf10d51def20531a59ce4c706cb7952323b11709e10de324d6493/audioop_lts-0.2.2-cp313-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b", size = 85056, upload-time = "2025-08-05T16:42:26.559Z" }, { url = "https://files.pythonhosted.org/packages/75/e8/cd95eef479656cb75ab05dfece8c1f8c395d17a7c651d88f8e6e291a63ab/audioop_lts-0.2.2-cp313-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8", size = 93892, upload-time = "2025-08-05T16:42:27.902Z" }, { url = "https://files.pythonhosted.org/packages/5c/1e/a0c42570b74f83efa5cca34905b3eef03f7ab09fe5637015df538a7f3345/audioop_lts-0.2.2-cp313-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc", size = 96660, upload-time = "2025-08-05T16:42:28.9Z" }, { url = "https://files.pythonhosted.org/packages/50/d5/8a0ae607ca07dbb34027bac8db805498ee7bfecc05fd2c148cc1ed7646e7/audioop_lts-0.2.2-cp313-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3", size = 79143, upload-time = "2025-08-05T16:42:29.929Z" }, { url = "https://files.pythonhosted.org/packages/12/17/0d28c46179e7910bfb0bb62760ccb33edb5de973052cb2230b662c14ca2e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6", size = 84313, upload-time = "2025-08-05T16:42:30.949Z" }, { url = "https://files.pythonhosted.org/packages/84/ba/bd5d3806641564f2024e97ca98ea8f8811d4e01d9b9f9831474bc9e14f9e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a", size = 93044, upload-time = "2025-08-05T16:42:31.959Z" }, { url = "https://files.pythonhosted.org/packages/f9/5e/435ce8d5642f1f7679540d1e73c1c42d933331c0976eb397d1717d7f01a3/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623", size = 78766, upload-time = "2025-08-05T16:42:33.302Z" }, { url = "https://files.pythonhosted.org/packages/ae/3b/b909e76b606cbfd53875693ec8c156e93e15a1366a012f0b7e4fb52d3c34/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7", size = 87640, upload-time = "2025-08-05T16:42:34.854Z" }, { url = "https://files.pythonhosted.org/packages/30/e7/8f1603b4572d79b775f2140d7952f200f5e6c62904585d08a01f0a70393a/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449", size = 86052, upload-time = "2025-08-05T16:42:35.839Z" }, { url = "https://files.pythonhosted.org/packages/b5/96/c37846df657ccdda62ba1ae2b6534fa90e2e1b1742ca8dcf8ebd38c53801/audioop_lts-0.2.2-cp313-abi3-win32.whl", hash = "sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636", size = 26185, upload-time = "2025-08-05T16:42:37.04Z" }, { url = "https://files.pythonhosted.org/packages/34/a5/9d78fdb5b844a83da8a71226c7bdae7cc638861085fff7a1d707cb4823fa/audioop_lts-0.2.2-cp313-abi3-win_amd64.whl", hash = "sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e", size = 30503, upload-time = "2025-08-05T16:42:38.427Z" }, { url = "https://files.pythonhosted.org/packages/34/25/20d8fde083123e90c61b51afb547bb0ea7e77bab50d98c0ab243d02a0e43/audioop_lts-0.2.2-cp313-abi3-win_arm64.whl", hash = "sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f", size = 24173, upload-time = "2025-08-05T16:42:39.704Z" }, { url = "https://files.pythonhosted.org/packages/58/a7/0a764f77b5c4ac58dc13c01a580f5d32ae8c74c92020b961556a43e26d02/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:73f80bf4cd5d2ca7814da30a120de1f9408ee0619cc75da87d0641273d202a09", size = 47096, upload-time = "2025-08-05T16:42:40.684Z" }, { url = "https://files.pythonhosted.org/packages/aa/ed/ebebedde1a18848b085ad0fa54b66ceb95f1f94a3fc04f1cd1b5ccb0ed42/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:106753a83a25ee4d6f473f2be6b0966fc1c9af7e0017192f5531a3e7463dce58", size = 27748, upload-time = "2025-08-05T16:42:41.992Z" }, { url = "https://files.pythonhosted.org/packages/cb/6e/11ca8c21af79f15dbb1c7f8017952ee8c810c438ce4e2b25638dfef2b02c/audioop_lts-0.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fbdd522624141e40948ab3e8cdae6e04c748d78710e9f0f8d4dae2750831de19", size = 27329, upload-time = "2025-08-05T16:42:42.987Z" }, { url = "https://files.pythonhosted.org/packages/84/52/0022f93d56d85eec5da6b9da6a958a1ef09e80c39f2cc0a590c6af81dcbb/audioop_lts-0.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:143fad0311e8209ece30a8dbddab3b65ab419cbe8c0dde6e8828da25999be911", size = 92407, upload-time = "2025-08-05T16:42:44.336Z" }, { url = "https://files.pythonhosted.org/packages/87/1d/48a889855e67be8718adbc7a01f3c01d5743c325453a5e81cf3717664aad/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfbbc74ec68a0fd08cfec1f4b5e8cca3d3cd7de5501b01c4b5d209995033cde9", size = 91811, upload-time = "2025-08-05T16:42:45.325Z" }, { url = "https://files.pythonhosted.org/packages/98/a6/94b7213190e8077547ffae75e13ed05edc488653c85aa5c41472c297d295/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfcac6aa6f42397471e4943e0feb2244549db5c5d01efcd02725b96af417f3fe", size = 100470, upload-time = "2025-08-05T16:42:46.468Z" }, { url = "https://files.pythonhosted.org/packages/e9/e9/78450d7cb921ede0cfc33426d3a8023a3bda755883c95c868ee36db8d48d/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:752d76472d9804ac60f0078c79cdae8b956f293177acd2316cd1e15149aee132", size = 103878, upload-time = "2025-08-05T16:42:47.576Z" }, { url = "https://files.pythonhosted.org/packages/4f/e2/cd5439aad4f3e34ae1ee852025dc6aa8f67a82b97641e390bf7bd9891d3e/audioop_lts-0.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:83c381767e2cc10e93e40281a04852facc4cd9334550e0f392f72d1c0a9c5753", size = 84867, upload-time = "2025-08-05T16:42:49.003Z" }, { url = "https://files.pythonhosted.org/packages/68/4b/9d853e9076c43ebba0d411e8d2aa19061083349ac695a7d082540bad64d0/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c0022283e9556e0f3643b7c3c03f05063ca72b3063291834cca43234f20c60bb", size = 90001, upload-time = "2025-08-05T16:42:50.038Z" }, { url = "https://files.pythonhosted.org/packages/58/26/4bae7f9d2f116ed5593989d0e521d679b0d583973d203384679323d8fa85/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a2d4f1513d63c795e82948e1305f31a6d530626e5f9f2605408b300ae6095093", size = 99046, upload-time = "2025-08-05T16:42:51.111Z" }, { url = "https://files.pythonhosted.org/packages/b2/67/a9f4fb3e250dda9e9046f8866e9fa7d52664f8985e445c6b4ad6dfb55641/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c9c8e68d8b4a56fda8c025e538e639f8c5953f5073886b596c93ec9b620055e7", size = 84788, upload-time = "2025-08-05T16:42:52.198Z" }, { url = "https://files.pythonhosted.org/packages/70/f7/3de86562db0121956148bcb0fe5b506615e3bcf6e63c4357a612b910765a/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:96f19de485a2925314f5020e85911fb447ff5fbef56e8c7c6927851b95533a1c", size = 94472, upload-time = "2025-08-05T16:42:53.59Z" }, { url = "https://files.pythonhosted.org/packages/f1/32/fd772bf9078ae1001207d2df1eef3da05bea611a87dd0e8217989b2848fa/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e541c3ef484852ef36545f66209444c48b28661e864ccadb29daddb6a4b8e5f5", size = 92279, upload-time = "2025-08-05T16:42:54.632Z" }, { url = "https://files.pythonhosted.org/packages/4f/41/affea7181592ab0ab560044632571a38edaf9130b84928177823fbf3176a/audioop_lts-0.2.2-cp313-cp313t-win32.whl", hash = "sha256:d5e73fa573e273e4f2e5ff96f9043858a5e9311e94ffefd88a3186a910c70917", size = 26568, upload-time = "2025-08-05T16:42:55.627Z" }, { url = "https://files.pythonhosted.org/packages/28/2b/0372842877016641db8fc54d5c88596b542eec2f8f6c20a36fb6612bf9ee/audioop_lts-0.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9191d68659eda01e448188f60364c7763a7ca6653ed3f87ebb165822153a8547", size = 30942, upload-time = "2025-08-05T16:42:56.674Z" }, { url = "https://files.pythonhosted.org/packages/ee/ca/baf2b9cc7e96c179bb4a54f30fcd83e6ecb340031bde68f486403f943768/audioop_lts-0.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c174e322bb5783c099aaf87faeb240c8d210686b04bd61dfd05a8e5a83d88969", size = 24603, upload-time = "2025-08-05T16:42:57.571Z" }, { url = "https://files.pythonhosted.org/packages/5c/73/413b5a2804091e2c7d5def1d618e4837f1cb82464e230f827226278556b7/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f9ee9b52f5f857fbaf9d605a360884f034c92c1c23021fb90b2e39b8e64bede6", size = 47104, upload-time = "2025-08-05T16:42:58.518Z" }, { url = "https://files.pythonhosted.org/packages/ae/8c/daa3308dc6593944410c2c68306a5e217f5c05b70a12e70228e7dd42dc5c/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:49ee1a41738a23e98d98b937a0638357a2477bc99e61b0f768a8f654f45d9b7a", size = 27754, upload-time = "2025-08-05T16:43:00.132Z" }, { url = "https://files.pythonhosted.org/packages/4e/86/c2e0f627168fcf61781a8f72cab06b228fe1da4b9fa4ab39cfb791b5836b/audioop_lts-0.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b00be98ccd0fc123dcfad31d50030d25fcf31488cde9e61692029cd7394733b", size = 27332, upload-time = "2025-08-05T16:43:01.666Z" }, { url = "https://files.pythonhosted.org/packages/c7/bd/35dce665255434f54e5307de39e31912a6f902d4572da7c37582809de14f/audioop_lts-0.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6d2e0f9f7a69403e388894d4ca5ada5c47230716a03f2847cfc7bd1ecb589d6", size = 92396, upload-time = "2025-08-05T16:43:02.991Z" }, { url = "https://files.pythonhosted.org/packages/2d/d2/deeb9f51def1437b3afa35aeb729d577c04bcd89394cb56f9239a9f50b6f/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b0b8a03ef474f56d1a842af1a2e01398b8f7654009823c6d9e0ecff4d5cfbf", size = 91811, upload-time = "2025-08-05T16:43:04.096Z" }, { url = "https://files.pythonhosted.org/packages/76/3b/09f8b35b227cee28cc8231e296a82759ed80c1a08e349811d69773c48426/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b267b70747d82125f1a021506565bdc5609a2b24bcb4773c16d79d2bb260bbd", size = 100483, upload-time = "2025-08-05T16:43:05.085Z" }, { url = "https://files.pythonhosted.org/packages/0b/15/05b48a935cf3b130c248bfdbdea71ce6437f5394ee8533e0edd7cfd93d5e/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0337d658f9b81f4cd0fdb1f47635070cc084871a3d4646d9de74fdf4e7c3d24a", size = 103885, upload-time = "2025-08-05T16:43:06.197Z" }, { url = "https://files.pythonhosted.org/packages/83/80/186b7fce6d35b68d3d739f228dc31d60b3412105854edb975aa155a58339/audioop_lts-0.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:167d3b62586faef8b6b2275c3218796b12621a60e43f7e9d5845d627b9c9b80e", size = 84899, upload-time = "2025-08-05T16:43:07.291Z" }, { url = "https://files.pythonhosted.org/packages/49/89/c78cc5ac6cb5828f17514fb12966e299c850bc885e80f8ad94e38d450886/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0d9385e96f9f6da847f4d571ce3cb15b5091140edf3db97276872647ce37efd7", size = 89998, upload-time = "2025-08-05T16:43:08.335Z" }, { url = "https://files.pythonhosted.org/packages/4c/4b/6401888d0c010e586c2ca50fce4c903d70a6bb55928b16cfbdfd957a13da/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:48159d96962674eccdca9a3df280e864e8ac75e40a577cc97c5c42667ffabfc5", size = 99046, upload-time = "2025-08-05T16:43:09.367Z" }, { url = "https://files.pythonhosted.org/packages/de/f8/c874ca9bb447dae0e2ef2e231f6c4c2b0c39e31ae684d2420b0f9e97ee68/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fefe5868cd082db1186f2837d64cfbfa78b548ea0d0543e9b28935ccce81ce9", size = 84843, upload-time = "2025-08-05T16:43:10.749Z" }, { url = "https://files.pythonhosted.org/packages/3e/c0/0323e66f3daebc13fd46b36b30c3be47e3fc4257eae44f1e77eb828c703f/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:58cf54380c3884fb49fdd37dfb7a772632b6701d28edd3e2904743c5e1773602", size = 94490, upload-time = "2025-08-05T16:43:12.131Z" }, { url = "https://files.pythonhosted.org/packages/98/6b/acc7734ac02d95ab791c10c3f17ffa3584ccb9ac5c18fd771c638ed6d1f5/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:088327f00488cdeed296edd9215ca159f3a5a5034741465789cad403fcf4bec0", size = 92297, upload-time = "2025-08-05T16:43:13.139Z" }, { url = "https://files.pythonhosted.org/packages/13/c3/c3dc3f564ce6877ecd2a05f8d751b9b27a8c320c2533a98b0c86349778d0/audioop_lts-0.2.2-cp314-cp314t-win32.whl", hash = "sha256:068aa17a38b4e0e7de771c62c60bbca2455924b67a8814f3b0dee92b5820c0b3", size = 27331, upload-time = "2025-08-05T16:43:14.19Z" }, { url = "https://files.pythonhosted.org/packages/72/bb/b4608537e9ffcb86449091939d52d24a055216a36a8bf66b936af8c3e7ac/audioop_lts-0.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a5bf613e96f49712073de86f20dbdd4014ca18efd4d34ed18c75bd808337851b", size = 31697, upload-time = "2025-08-05T16:43:15.193Z" }, { url = "https://files.pythonhosted.org/packages/f6/22/91616fe707a5c5510de2cac9b046a30defe7007ba8a0c04f9c08f27df312/audioop_lts-0.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:b492c3b040153e68b9fdaff5913305aaaba5bb433d8a7f73d5cf6a64ed3cc1dd", size = 25206, upload-time = "2025-08-05T16:43:16.444Z" }, ] [[package]] name = "audioread" version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "standard-aifc", marker = "python_full_version >= '3.13'" }, { name = "standard-sunau", marker = "python_full_version >= '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/4a/874ecf9b472f998130c2b5e145dcdb9f6131e84786111489103b66772143/audioread-3.1.0.tar.gz", hash = "sha256:1c4ab2f2972764c896a8ac61ac53e261c8d29f0c6ccd652f84e18f08a4cab190", size = 20082, upload-time = "2025-10-26T19:44:13.484Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/16/fbe8e1e185a45042f7cd3a282def5bb8d95bb69ab9e9ef6a5368aa17e426/audioread-3.1.0-py3-none-any.whl", hash = "sha256:b30d1df6c5d3de5dcef0fb0e256f6ea17bdcf5f979408df0297d8a408e2971b4", size = 23143, upload-time = "2025-10-26T19:44:12.016Z" }, ] [[package]] name = "autodocsumm" version = "0.2.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/46/b7/f28dea12fae1d1ad1e706f5cf6d16e8d735f305ebee86fd9390e099bd27d/autodocsumm-0.2.15.tar.gz", hash = "sha256:eaf431e7a5a39e41a215311173c8b95e83859059df1ccf3b79c64bf3d5582b3c", size = 46674, upload-time = "2026-03-26T20:44:07.074Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ca/3d/4357a0f685c0a2ae7132ac91905bec565e64f9ba63b079f7ec5da46e3597/autodocsumm-0.2.15-py3-none-any.whl", hash = "sha256:dbe6fabcaeae4540748ea9b3443eb76c2692e063d44f004f67c424610a5aca9a", size = 14852, upload-time = "2026-03-26T20:44:05.273Z" }, ] [[package]] name = "babel" version = "2.18.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, ] [[package]] name = "backports-zstd" version = "1.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8e/b5/5a873da082bd08acd6a497f7aae224e94a7c27fa8f24488089cc50a16c84/backports_zstd-1.6.0.tar.gz", hash = "sha256:80a7859ffe70bf239d7a2ce15293bdeb5b4280ff7dc326ffab312b0e254dbb24", size = 1000009, upload-time = "2026-06-14T10:50:58.555Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6b/8d/3f8e7a0fd319b3c0dbf0c4f751336309bb50a873b9185c2f5d228ff0d21b/backports_zstd-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:73000459db113a658c4fb0510100ef0e79137b5828bf957b7709aacae4eb1b87", size = 437068, upload-time = "2026-06-14T10:49:05.528Z" }, { url = "https://files.pythonhosted.org/packages/db/14/4700047713a60131efcb3977a9892fab60bc9dd6634272550b8f1c5a427d/backports_zstd-1.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6e78d5e28f812b39f92397806ecddd4a6f3bf35531a8c039a1f187abc931af8", size = 363456, upload-time = "2026-06-14T10:49:07.154Z" }, { url = "https://files.pythonhosted.org/packages/c4/34/92de2f1bd5ee29b24302c871b9f3c19155bf9478cd3af5a0dfd70fa2f483/backports_zstd-1.6.0-cp310-cp310-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:32f04d54ec1fdf3aa648b24a10b1c9234ed2046cc4af7a8850cbc236c05d42f3", size = 507392, upload-time = "2026-06-14T10:49:08.63Z" }, { url = "https://files.pythonhosted.org/packages/5a/95/ed5b8b026c6df1a59681a73396f63cfd10e17ccfbc6315974745a8b7d834/backports_zstd-1.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83415af3c64550a56cc20b4cce59bbaa81f21d28466d7adf98feff011ecbc66d", size = 476957, upload-time = "2026-06-14T10:49:09.894Z" }, { url = "https://files.pythonhosted.org/packages/5a/47/1a82ede48d9df99c8245cb38622cd1a9b388b34f89e1cb7b6650913b493d/backports_zstd-1.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a3c17e6a267d13de9cbf14bf2ebfa87e03d26692456fc67d2dbed9da4f479b18", size = 582618, upload-time = "2026-06-14T10:49:11.097Z" }, { url = "https://files.pythonhosted.org/packages/6b/70/441ed36e230b0f66d7d49382c58249b540139c5b1aa096ace1ff00bd7873/backports_zstd-1.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:75578c71644b031118ce938855a53530708db7f4af6e83e2f8840d5a1de990f8", size = 642278, upload-time = "2026-06-14T10:49:12.545Z" }, { url = "https://files.pythonhosted.org/packages/58/a3/8f5737bdb02576577a018c10a4c345a5b4b2e63cc3811baeecc054f71c00/backports_zstd-1.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a4ae7ed5a6d813450cc2d818284ea3db9721edcef50a56aae42ea06feec38c6e", size = 492492, upload-time = "2026-06-14T10:49:14.037Z" }, { url = "https://files.pythonhosted.org/packages/e1/a9/c086507f535c2466a25bf83a876666c9ccde07b17ce81680217ac17355fe/backports_zstd-1.6.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5e9a8370c8ed873083d5de956d6b2e60adbad31e52d7a11111c96ef01d1910ae", size = 566440, upload-time = "2026-06-14T10:49:15.483Z" }, { url = "https://files.pythonhosted.org/packages/89/bb/778aaccb58c4d2fba3482438c0d33c6a3a413710ecdb2ee8559ff28632fc/backports_zstd-1.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c2d1ccfe088e8279d605011a3575619a74526c261be357695b3258c0f636115a", size = 482894, upload-time = "2026-06-14T10:49:16.982Z" }, { url = "https://files.pythonhosted.org/packages/3a/88/87ad188ce971c15bce933e13c4dc2939e741a9cb06a8bd692ef8614c3ed4/backports_zstd-1.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e73a550dbeb84e8fa50f8385f7735e9a4735b465851ef617d02f80ab10e44e7e", size = 510822, upload-time = "2026-06-14T10:49:18.274Z" }, { url = "https://files.pythonhosted.org/packages/6e/8c/01714884a14b836abfdb1d80339acbb39515b0e92e615c4b65caf0eec257/backports_zstd-1.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:84f92e5a60a78c72ccda79d0417d311a1f6da18f446423ed411726d545bf7b56", size = 586941, upload-time = "2026-06-14T10:49:19.563Z" }, { url = "https://files.pythonhosted.org/packages/63/43/e2cb44bbe3f7485d6ad8493211f0c8fffdb7e02fb94203fd968751d9fad7/backports_zstd-1.6.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0eb4281f402b94d397b7482f6d9efd04c28274e4ed6eb57eb1f87bdd091a6a87", size = 564255, upload-time = "2026-06-14T10:49:20.968Z" }, { url = "https://files.pythonhosted.org/packages/36/eb/eb0f00f6f7778db3710f757d77f5699c325548037dd975b52b186394125e/backports_zstd-1.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d6b9b06323e3ba947c0003b2d70e02f33c90c36bc6262a92eb8201afc4a1aa08", size = 632836, upload-time = "2026-06-14T10:49:22.177Z" }, { url = "https://files.pythonhosted.org/packages/ac/b8/5434897431de92e79ebfb2c02e1ab3cd228e92853b7ff981b2cffcce7355/backports_zstd-1.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8872a0e9f1af975966b5be6af7eebd3dc4046f15e470b719316516dc3d137cd6", size = 496501, upload-time = "2026-06-14T10:49:23.444Z" }, { url = "https://files.pythonhosted.org/packages/db/76/754939c3914e9724e20a50b75b17fdc27aeb24d697eb61c3e93438a42920/backports_zstd-1.6.0-cp310-cp310-win32.whl", hash = "sha256:c14fa5dc39a804f1b92d63506f450eca5c59647a18d197d1a564b89dac1be1ce", size = 291527, upload-time = "2026-06-14T10:49:24.568Z" }, { url = "https://files.pythonhosted.org/packages/84/f1/adcebdc2caa2e3d3d496ac2501f0ada49ad2942ee36e5f88a944bca9ca92/backports_zstd-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:8219d6fceae6b39535c4ac323dba0923d10f781d59962ff3504e693fdcafa92c", size = 329024, upload-time = "2026-06-14T10:49:25.773Z" }, { url = "https://files.pythonhosted.org/packages/74/10/12edc0b401a08aba157b9d331748ac0f0e9890af0a58a9c72425063d1450/backports_zstd-1.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:b7bc9a0b66097f03820a54316d2fdd0beb38859cf98f10d63e94c55450ed8920", size = 291597, upload-time = "2026-06-14T10:49:27.156Z" }, { url = "https://files.pythonhosted.org/packages/c5/90/428dd82228b1b6d62d5a1bf312c29e6c125af6a182fcfd82768ca179dcc7/backports_zstd-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4fc41b2df5529cad5ceb230319e82728096d4b353ce8d4df68a2ec37e291bb8", size = 437067, upload-time = "2026-06-14T10:49:28.335Z" }, { url = "https://files.pythonhosted.org/packages/ef/48/768edf21fe33bae8d874470b1be136681d4d32eb820a32e1c98262ebe39b/backports_zstd-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:83391ef5935cc0f329b1abca414ae20ffe40d335fc21a4b5e664f08a74317d5f", size = 363454, upload-time = "2026-06-14T10:49:29.784Z" }, { url = "https://files.pythonhosted.org/packages/29/8a/d462c2e5071eb573378f0d26760f6590613086fdf59c2d3c66bdfffb9f41/backports_zstd-1.6.0-cp311-cp311-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:7d3f64c503af7b60115b97c16feaf75bd191ef2c978d5c0c7725a6682bef63c5", size = 507393, upload-time = "2026-06-14T10:49:31.077Z" }, { url = "https://files.pythonhosted.org/packages/b9/cb/af58363b0dd0b497282ecef1fa99789b03cc1885a01a41394cad42ceeff6/backports_zstd-1.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0308990ffc998df3c7ed35276bde049728b5c3956203cae40d80893576a41459", size = 476957, upload-time = "2026-06-14T10:49:32.53Z" }, { url = "https://files.pythonhosted.org/packages/e4/fd/5fbdf2275cefae95c4b3509f6db2dc372d0587ebafea342d28781d51d932/backports_zstd-1.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8c298785e2fadeab82342040f2d9ce764ce500e6da6a6d99a2de514e63580b5a", size = 582618, upload-time = "2026-06-14T10:49:33.723Z" }, { url = "https://files.pythonhosted.org/packages/99/6f/7dd45c53c907ea67f635c3900b58bb3347c01dc2ded441402028aae0ef9c/backports_zstd-1.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae106fe16e36efc60ab098d02478d30aa0e31e1420eb4ecf0116459253bc6361", size = 642279, upload-time = "2026-06-14T10:49:34.938Z" }, { url = "https://files.pythonhosted.org/packages/4d/25/a9e37dd035027565fa0b7e367da50e88a6ab26e7fd413269aa118e25258b/backports_zstd-1.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7293fefe15f0e5852bdb4ad1e0e26f3cbd4d3e61c19f751ecc4ff34bc1eb237d", size = 492486, upload-time = "2026-06-14T10:49:36.06Z" }, { url = "https://files.pythonhosted.org/packages/a1/52/659686bf8f7c53ea279e1c44038504b82a6901cee2f5ae83c30bbf581301/backports_zstd-1.6.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ece8e7288db5b827ef8c64b2f78519f1a173a8991a625978fce02eccd7654fe9", size = 566440, upload-time = "2026-06-14T10:49:37.536Z" }, { url = "https://files.pythonhosted.org/packages/d9/1a/c7ea5a0ff607a1a6066bb7c7cb65ae20e2f85da6adc69ab77fd8943e180c/backports_zstd-1.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:28eef3881164f3c23ce58ed59e4684103bdd279583eb2d299858c9e9b72fde9a", size = 482899, upload-time = "2026-06-14T10:49:38.805Z" }, { url = "https://files.pythonhosted.org/packages/83/48/bd2b91100ee4fe6bb4d816e3659cbbb0cda5dd32760d2379c54d1752ec25/backports_zstd-1.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:481a1e9bd8f419fdc625307aa20234687f99368c75df511ef589693c5fea4c6f", size = 510826, upload-time = "2026-06-14T10:49:40.062Z" }, { url = "https://files.pythonhosted.org/packages/25/fe/fa28509d7ce2ad59404e7ce738a2fd858e12dfd9a896629f10330222a7fb/backports_zstd-1.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3b6713371f8987a1178df93cb36f29eef191f224021e2d656b2f11ce60d26816", size = 586941, upload-time = "2026-06-14T10:49:41.305Z" }, { url = "https://files.pythonhosted.org/packages/45/28/757daf2399aa71bb37f9f7f48b42ab03fc51c340eccfad2fec92a23f6aa3/backports_zstd-1.6.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:b0ddbcd2866b8ff1a2836e4b0e4d44788f5b992d83fac75a38cda8f9a2bee079", size = 564261, upload-time = "2026-06-14T10:49:42.49Z" }, { url = "https://files.pythonhosted.org/packages/4e/53/9b9db30cb2c148a69c40ad7647aa787338041f3dc81c5b22113286e590e9/backports_zstd-1.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2914abea516704bdafb2090acd3f15b5f9debecfabd15b8dd8285b2ad3b92209", size = 632869, upload-time = "2026-06-14T10:49:43.981Z" }, { url = "https://files.pythonhosted.org/packages/81/a4/1692fbb88af8aaf900a53619fcc95c9e45d9ff162223a47fd672a9893c8d/backports_zstd-1.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dd085eafa2aac6f883afd28210a3231f717f25409a1e44a39bb7b04c8c5b5646", size = 496496, upload-time = "2026-06-14T10:49:45.118Z" }, { url = "https://files.pythonhosted.org/packages/93/42/c5a66c47320bd12ce84a7341330ea582d67069bdb70214bca0b6bf394cfd/backports_zstd-1.6.0-cp311-cp311-win32.whl", hash = "sha256:b81b4cf3d6e0ad7ac92bef248f49fafc954262c5fb0f7e19d6aac497e5a856b2", size = 291613, upload-time = "2026-06-14T10:49:46.473Z" }, { url = "https://files.pythonhosted.org/packages/2a/f2/f22c19b4cdde429805ff5ac8dd77a95569a7c4cb8991741b2ff0d538f220/backports_zstd-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:10b61850c4112952e05aa6e6cce8c9a5936fbeadb321e154216705cc76a14afa", size = 329078, upload-time = "2026-06-14T10:49:47.71Z" }, { url = "https://files.pythonhosted.org/packages/ef/dc/e902a3f1eb92c4907b5f47f90cb3c2734ee315c4ff67179fc111343b45ba/backports_zstd-1.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:068ef3d8c18815a2e3a752f766313e19910e7c50939b956923748d9c04ebcb1b", size = 291727, upload-time = "2026-06-14T10:49:48.929Z" }, { url = "https://files.pythonhosted.org/packages/1e/bb/009af3a9532d4cc66d5385391c512210fae32ab2442605f26aca1d8d2957/backports_zstd-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0466b14723f3b7697669c00ee66fe16e30e25636b286b0a923fa86fa3d8a753c", size = 437407, upload-time = "2026-06-14T10:49:50.155Z" }, { url = "https://files.pythonhosted.org/packages/0c/76/f7c02efde81ebb9993586f9e435d2fd1191a6f806f640e4eeb8d004493ed/backports_zstd-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d146926e997d2d3de8212bdcbf4985344a2622ca3bec458d8908000a84fd883", size = 363519, upload-time = "2026-06-14T10:49:51.383Z" }, { url = "https://files.pythonhosted.org/packages/2e/5e/0cf66f12472fe3e082cc4134395a7e0b8746cfb30aabd74251ce8fafa9a7/backports_zstd-1.6.0-cp312-cp312-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:460fd6b3f338c659507ae36cfd6b58ac9942a2ff233c5cf574416dfec0451a84", size = 507756, upload-time = "2026-06-14T10:49:52.497Z" }, { url = "https://files.pythonhosted.org/packages/03/95/7ed25c90369360f96f8bfa961540845e063377c32a43b775201af66a588c/backports_zstd-1.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c2b1f4a640c51130caa92cef5bf72bd3c3dbbcfbf814c37403aa0601b1811b0", size = 477578, upload-time = "2026-06-14T10:49:53.887Z" }, { url = "https://files.pythonhosted.org/packages/e3/75/f16b1d3e33ca396525847c81d96e3de7bc74d2c6f9ca2ddee76b0c450697/backports_zstd-1.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:beb43e9885202c8d4f3762319ed4d5e98e197622afbff8439fbbdd81d08938b9", size = 583029, upload-time = "2026-06-14T10:49:55.132Z" }, { url = "https://files.pythonhosted.org/packages/e1/2b/a17b111b631e1c79a0e570881c1a266c661b936585afa395435a458b1991/backports_zstd-1.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fbb746522ebfc11155f1cd688e2c48ef3d74125e38b63eabdaab068a055c3e88", size = 641741, upload-time = "2026-06-14T10:49:56.42Z" }, { url = "https://files.pythonhosted.org/packages/6b/b2/d17b2722c636d64b4e77ddc68d8d0625719d39f94021be8719a218af4c0a/backports_zstd-1.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a99710fbb225d459d66def4dc2bb2cd4a9a0bdc8b799fc0621cfdd863be9c93", size = 495554, upload-time = "2026-06-14T10:49:57.652Z" }, { url = "https://files.pythonhosted.org/packages/63/12/2853e8b6c03f03795b6548ea61f82cc104d4f7ff2523a04bc69f46984663/backports_zstd-1.6.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f69365ee2b836939137de024a302395a1cb8654fb6dc5ffef6381105259c8f87", size = 570027, upload-time = "2026-06-14T10:49:59.003Z" }, { url = "https://files.pythonhosted.org/packages/18/aa/83f37b81f3b8c6ea035bf260ec374648bd59372894c02323dc9de3cbdf77/backports_zstd-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:66cf8038893c7708ec345ffb3ac63c775d10f430f323ac2f0334fdb6a397c57c", size = 483594, upload-time = "2026-06-14T10:50:00.49Z" }, { url = "https://files.pythonhosted.org/packages/f5/6a/d77f8cd2ff642d3b3652c1ccab5b6583114dbf10f8cb0143531357c83998/backports_zstd-1.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e514c71ca72f3b56bd8fbda1a6a5b7d1100a2764b42a3c74a38841f25f9b00ab", size = 511206, upload-time = "2026-06-14T10:50:01.86Z" }, { url = "https://files.pythonhosted.org/packages/56/b2/99a60fe4d1aac8053769d2463271d5df37a7c11c387072fdbb0b16aed7f7/backports_zstd-1.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7741e44f7938ec94f9a52678c8d19b7bc548522ffdc39c9e4481af8db545fa9a", size = 587416, upload-time = "2026-06-14T10:50:03.236Z" }, { url = "https://files.pythonhosted.org/packages/ec/1e/a9c003fe4d14bd4bf671598d4c7dcc1cef51e3513d9d7111ba1d07b6f07b/backports_zstd-1.6.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:97e8a9674652496c7612b528085dd5a296c052a2edc466ca1bfb7b0b27820413", size = 567615, upload-time = "2026-06-14T10:50:04.524Z" }, { url = "https://files.pythonhosted.org/packages/ec/b9/955bd604f692c550c7cb66d00bd7691ead5c86df8ebd23d7254eeaa90789/backports_zstd-1.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:23a793f2fed4dbf0517319759a2cded0b0dd8e8d3797fe30badd5693e320c175", size = 632269, upload-time = "2026-06-14T10:50:05.86Z" }, { url = "https://files.pythonhosted.org/packages/18/d7/9f61f612f8a4193484c78a1f26db82a50141234189885113ef0085a8a961/backports_zstd-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b951113113ed4b8d173418a4f155c14b739dace626b3fa3f82be1831958d39e4", size = 500066, upload-time = "2026-06-14T10:50:07.446Z" }, { url = "https://files.pythonhosted.org/packages/81/a3/19fb8c48d94139481c5ccaf2fb54c31b543fa635fd7bd7399aadd15752ac/backports_zstd-1.6.0-cp312-cp312-win32.whl", hash = "sha256:6430b34a2ae6fcc604672f4f913102563473d9a015bdca1ce8c95041cc1f2677", size = 291825, upload-time = "2026-06-14T10:50:08.762Z" }, { url = "https://files.pythonhosted.org/packages/58/38/40ba081c6c71f0f22c64d3d54b912ad75a4e6812caa1397cbb15b5693b12/backports_zstd-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:08793876172551a930ce4d65c712cd516184d1a97070d4a1193e05bf0cf7040d", size = 329201, upload-time = "2026-06-14T10:50:09.979Z" }, { url = "https://files.pythonhosted.org/packages/2b/6c/f7116dd2edc6f960545f0d8616939eae3a20031b3b6669697d4f9fd83b2e/backports_zstd-1.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:03b7c59c71f7a597e2bcb3f8368371e9a660a1bdf1c37afc1f1ad1496a013c19", size = 291901, upload-time = "2026-06-14T10:50:11.198Z" }, { url = "https://files.pythonhosted.org/packages/38/06/c430537d59c55d49bcd15ecf4b1aa965453219caad810a4f2b484816f4be/backports_zstd-1.6.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:2ace939e4d620e119423606f2d3d7115f8707733bf57f279ad9a9383f875986f", size = 400327, upload-time = "2026-06-14T10:50:12.446Z" }, { url = "https://files.pythonhosted.org/packages/36/48/2f8323bb0e3ebba88b54877a2979afeb83983fb2ca572f09ad61aae2d3a0/backports_zstd-1.6.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:4c68a9ed2df0cca51d774c521e68a34d2e3d9ebfc687ef8096adfd4f345b551d", size = 454276, upload-time = "2026-06-14T10:50:13.667Z" }, { url = "https://files.pythonhosted.org/packages/7c/39/87a665244a65f5b87a06b848c29a8cce07e91d59c5988ee2a32c0293a21c/backports_zstd-1.6.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:30576f49b82328ec8af16c11100efe52ca88526f71bbe100ef6b4e707dc13bf2", size = 357457, upload-time = "2026-06-14T10:50:14.906Z" }, { url = "https://files.pythonhosted.org/packages/7f/8b/854d4a47bb8b7a48bfb2ed381c7b03a70efb4fc49f0e4a1509b38a2e1727/backports_zstd-1.6.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b4bddfcfb6679215d6f4dc5f79a1f9301af339480d70527a14b57a1f2e6b6cbf", size = 366139, upload-time = "2026-06-14T10:50:16.399Z" }, { url = "https://files.pythonhosted.org/packages/8f/de/c3af43eb8df6f2581e157e18a3e0121eadb826055b2fde3f91ec188689cb/backports_zstd-1.6.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:65048ed08c5124f05ff9f355ab9703014bb2dbe7f8d9948ce193685b1775f442", size = 446683, upload-time = "2026-06-14T10:50:17.633Z" }, { url = "https://files.pythonhosted.org/packages/5c/39/87cf3d883d386c10ac52f5322604fb9afdd204229f4c47d4a820a839b8ff/backports_zstd-1.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5918fc6b31437208721276964323933cd86077b8d5b469c59c1b3fd2c8220a05", size = 436869, upload-time = "2026-06-14T10:50:19.113Z" }, { url = "https://files.pythonhosted.org/packages/5e/b6/9479e6f0f18824ad38e8d7dd85161ab0842a198be669421232925bb30960/backports_zstd-1.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4b6c8b02ab0ccb2431bb7bc238be91d158b308915e7b07937388e540466fe7e7", size = 363090, upload-time = "2026-06-14T10:50:20.302Z" }, { url = "https://files.pythonhosted.org/packages/d9/74/a5e98fe108e17c91d9bc590a19e77f5d47d579e34d3f5bc098a949d6c27c/backports_zstd-1.6.0-cp313-cp313-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:711e6b98f8924e8b4a61ff97ab6321f33de024e1ed6a32f5123763aeda8459be", size = 507070, upload-time = "2026-06-14T10:50:21.536Z" }, { url = "https://files.pythonhosted.org/packages/69/f5/392bb7dce7363b77bc5403060f418fad438b9cfdd3edd10d65cee7d8fd11/backports_zstd-1.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ba9ac10fc393e5123a08802e0e895a107cb4a66b9973d2844dbd8a343111e59", size = 477200, upload-time = "2026-06-14T10:50:22.91Z" }, { url = "https://files.pythonhosted.org/packages/e4/4d/dfb665806ba4f74bc48071d32006843b53568c4a17ff627a3061de5eaa09/backports_zstd-1.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f723219335387d7546412d8141e0303590600949b4184a1391a0c6a3c756058", size = 582724, upload-time = "2026-06-14T10:50:24.28Z" }, { url = "https://files.pythonhosted.org/packages/57/b2/beeca7393a8310debd82ee2f0ce5c1801e8d7cb673f7f226f4a0866ca238/backports_zstd-1.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:64b94d7a836568926a3309ff510c7f8261b881b341fd4992cabf4f0998878f8a", size = 643493, upload-time = "2026-06-14T10:50:25.736Z" }, { url = "https://files.pythonhosted.org/packages/38/26/ce90e9eed6f25aaa4a4fa305a2aaf2d2ad81fd69de8eb248ddd91c80d1e0/backports_zstd-1.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e39258a09b1c7ca70b5e94a5c5ccfe4700b4250b8077cfeab31d0f79565d4c9b", size = 492190, upload-time = "2026-06-14T10:50:27.205Z" }, { url = "https://files.pythonhosted.org/packages/17/9b/37b9b146df1f5452419a96071a7017cbac212ec9b137d7a88ca46dc2aa9e/backports_zstd-1.6.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:15b1aae0f64cd742df4bba1d989d0a09a6ec619202543fdba684640454541fd3", size = 567432, upload-time = "2026-06-14T10:50:28.386Z" }, { url = "https://files.pythonhosted.org/packages/06/66/81b30991be83237529f36335ac3682bce26409064b906ac6122874575196/backports_zstd-1.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:25b5ddc789480072551af571a746e9500356b2aff0499861cf2ca07ea7431e68", size = 483021, upload-time = "2026-06-14T10:50:29.654Z" }, { url = "https://files.pythonhosted.org/packages/49/2a/792c65dcc1e45eb0c1bdc012ee94b84867186bfe27a860d0813bd216f03b/backports_zstd-1.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a13cfa3410a75e4cb87abdb669aaf79da861cb79299159054ff8f77b9671bc40", size = 510596, upload-time = "2026-06-14T10:50:31.657Z" }, { url = "https://files.pythonhosted.org/packages/1d/22/01b92a600505620e4cb5f20429e181f30458b7207ca8b52ca5ca6068c35f/backports_zstd-1.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2ddab55a5f54dec8acfad68ef70f1c704fd21919990ddc238afbd6f496e61c6a", size = 587143, upload-time = "2026-06-14T10:50:32.868Z" }, { url = "https://files.pythonhosted.org/packages/d8/60/4672f5110b9eb01388cc6225a739e3a5fcd749a63a9c4c1450a04fa27113/backports_zstd-1.6.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fa305a84087e10d7a85e8a8a3dcba8cdbda4868f2180173b264b7b488fd37c55", size = 565238, upload-time = "2026-06-14T10:50:34.173Z" }, { url = "https://files.pythonhosted.org/packages/5c/3b/19928d60ea7d25820bf12ef88de74534ca85b56ff7cf13c1b0e74e3a3d7c/backports_zstd-1.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:df27b57d214a3124fbe4e933ef5a903d4567f154260d9aece8c797a987f2a205", size = 633970, upload-time = "2026-06-14T10:50:35.506Z" }, { url = "https://files.pythonhosted.org/packages/df/97/c4cecb3e0ff53563ef9819f0395d919ceaae9c5147392ac23bac7afdb20f/backports_zstd-1.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:28fecd73459d74910ae1987ab84b7bef690d3dd860948430dd5555108b006daf", size = 496539, upload-time = "2026-06-14T10:50:37.015Z" }, { url = "https://files.pythonhosted.org/packages/eb/f4/46b2f29d2938a80e56e61a19f11ab093f531a9f8cd0ec8eeaac1246bcd99/backports_zstd-1.6.0-cp313-cp313-win32.whl", hash = "sha256:3e689af303df287142770abe3a48bbefd24dab4a09da5807d0e1fa8c75bab026", size = 291451, upload-time = "2026-06-14T10:50:38.518Z" }, { url = "https://files.pythonhosted.org/packages/d1/ad/b529f92166da61f496621345f95d2dc583c8ca5ac553c084a4ef6c12cd71/backports_zstd-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:b067b1ef9c8e41fb0882c828aa37829938b5c0dab067eca72b23fc24c563b9da", size = 329023, upload-time = "2026-06-14T10:50:39.742Z" }, { url = "https://files.pythonhosted.org/packages/30/d8/6be904d20345fbebec583ca83676e01f30c76118b283eb666d8ec8291ca1/backports_zstd-1.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:a838296f5b84c920172fb579cac894d255c1fc25457c7234613ddcfa385e49b7", size = 291636, upload-time = "2026-06-14T10:50:41.004Z" }, { url = "https://files.pythonhosted.org/packages/f7/52/9ed88f528b9484f3847f07b9d1d014b496e048d391b4bc04cb0117bd71a5/backports_zstd-1.6.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6c73ae37dbf9207727ac095dedef864c05d836eaec962a47b3b64eaadaf1c6b6", size = 411126, upload-time = "2026-06-14T10:50:42.253Z" }, { url = "https://files.pythonhosted.org/packages/fe/26/bf8093d117cb6c36202ee7a2127f672c7b0c81f0c104ce28124534b75efa/backports_zstd-1.6.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:839faf90a7eb525a401978dc925df8c44bd12526e8ba1529b9f8a7106e729637", size = 340643, upload-time = "2026-06-14T10:50:43.571Z" }, { url = "https://files.pythonhosted.org/packages/17/10/55f0860ed359d290e0eadd410da47ae720a1acf0d8362149e22acbe63223/backports_zstd-1.6.0-pp310-pypy310_pp73-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f8f5c1c7c69a4b00889e52d9304a918a5b49010f9645768eb5fd0ad404f790ba", size = 421696, upload-time = "2026-06-14T10:50:44.915Z" }, { url = "https://files.pythonhosted.org/packages/7c/3e/8dd9cc6f3e697e4721e53d6b9ca8c95c9d51ad2e759e7fcee6885e5b71db/backports_zstd-1.6.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e80bceebc9b58e959bede9b26cafe15b5b9526f3533a6dd06330c5da73cb9329", size = 395239, upload-time = "2026-06-14T10:50:46.186Z" }, { url = "https://files.pythonhosted.org/packages/fb/bb/ab92f8599749cb6063416dd9f46e084004c4e8db68e2eb768283012a6d27/backports_zstd-1.6.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:79284c1dd702f4f24ed1a36e51555c907dd237b6c0d829595978f4089a2aeea9", size = 415202, upload-time = "2026-06-14T10:50:47.726Z" }, { url = "https://files.pythonhosted.org/packages/2c/f4/dd3ef995f6b22e23da145ac3ecc91e1f1fc4cb572b7f95e6b2b11de16782/backports_zstd-1.6.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1e20b3ecd0a711be82e964aca28554eabbc31ee69a20e5e7b8fd42268af46212", size = 315722, upload-time = "2026-06-14T10:50:49Z" }, { url = "https://files.pythonhosted.org/packages/e8/09/898fe2f8196fa7ab825f5fed786c68581fdac7d23a8e20baa0cc01cb2f0b/backports_zstd-1.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:aeef8563b82ed4af328f98e5041c1b4800d86f68f857ffd1577d4d47dc9aa6cd", size = 411023, upload-time = "2026-06-14T10:50:50.286Z" }, { url = "https://files.pythonhosted.org/packages/6e/ad/6ad9af1596ab5f284bb53954be41396e13d23c81cdfe3d945402e8ee0215/backports_zstd-1.6.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9cb75e33131946fabd6319061df3b8b1d588fe0963183280e9b5f49f7772fc09", size = 340554, upload-time = "2026-06-14T10:50:51.523Z" }, { url = "https://files.pythonhosted.org/packages/f0/00/f083d7c8a4ee5d0bb21b4d3144e76de9f655ca4dd0bffcb95baa5bc47a62/backports_zstd-1.6.0-pp311-pypy311_pp73-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:ef132cfb638e9a86bd5dc07fb4e1cb895bc55bce6bb5e759366e8b160d0747e2", size = 421694, upload-time = "2026-06-14T10:50:52.917Z" }, { url = "https://files.pythonhosted.org/packages/41/d7/693b20f3ccae2e05d166f98fe55b1657451170b72c804ed9f6b98df520be/backports_zstd-1.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab70eace272d6f122b121c057e436709b50a28abf30d97aab28433c08f4a4095", size = 395237, upload-time = "2026-06-14T10:50:54.448Z" }, { url = "https://files.pythonhosted.org/packages/53/a1/484e0f9ec994bd2285d6747e7c8028350f1a177e9210bc57637898042d3b/backports_zstd-1.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17efb3d11137de5166dd51eedab9c36ad633402acba386eee8d715213ea47e49", size = 415201, upload-time = "2026-06-14T10:50:55.854Z" }, { url = "https://files.pythonhosted.org/packages/3c/56/70860ece85cd49b564305cbc22bf6c4183975427ff6dfe2097e855f5dd5e/backports_zstd-1.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:994167ff6551b9c1ce226e0aab16295b98c94507b5701aa60d2c32b7d50796b1", size = 315721, upload-time = "2026-06-14T10:50:57.074Z" }, ] [[package]] name = "beautifulsoup4" version = "4.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/65/318323f98dbee45d42dff61d8f047181bc6f2268a9068cfad035a46be5af/beautifulsoup4-4.15.0.tar.gz", hash = "sha256:288e3ca7d54b06f2ac191970bc275c1939cb46d450b255bf6718b04aa37ab4f7", size = 632571, upload-time = "2026-06-07T16:44:20.453Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/88/c6/92fcd42f1ba33e1184263f25bfabf3d27c383410470f169e4b8163bf9c17/beautifulsoup4-4.15.0-py3-none-any.whl", hash = "sha256:d6f88de62e1d4e38ecb1077eb9724cd0eff29d2a08ca16a401e9b9e93f117cf9", size = 109924, upload-time = "2026-06-07T16:44:21.566Z" }, ] [[package]] name = "beets" version = "2.14.1" source = { editable = "." } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "confuse" }, { name = "jellyfish" }, { name = "lap" }, { name = "mediafile" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "packaging" }, { name = "platformdirs" }, { name = "pyyaml" }, { name = "requests" }, { name = "requests-ratelimiter" }, { name = "typing-extensions" }, { name = "unidecode" }, ] [package.optional-dependencies] absubmit = [ { name = "requests" }, ] aura = [ { name = "flask" }, { name = "flask-cors" }, { name = "pillow" }, ] autobpm = [ { name = "librosa" }, { name = "numba" }, { name = "resampy" }, ] beatport = [ { name = "requests-oauthlib" }, ] bpd = [ { name = "pygobject", marker = "sys_platform != 'win32'" }, ] chroma = [ { name = "pyacoustid" }, ] discogs = [ { name = "python3-discogs-client" }, ] embedart = [ { name = "pillow" }, ] embyupdate = [ { name = "requests" }, ] fetchart = [ { name = "beautifulsoup4" }, { name = "langdetect" }, { name = "pillow" }, { name = "requests" }, ] import = [ { name = "py7zr" }, { name = "rarfile" }, ] kodiupdate = [ { name = "requests" }, ] lastgenre = [ { name = "pylast" }, ] lastimport = [ { name = "pylast" }, ] lyrics = [ { name = "beautifulsoup4" }, { name = "langdetect" }, { name = "requests" }, ] metasync = [ { name = "dbus-python", marker = "sys_platform != 'win32'" }, ] mpdstats = [ { name = "python-mpd2" }, ] plexupdate = [ { name = "requests" }, ] reflink = [ { name = "reflink" }, ] replaygain = [ { name = "pygobject", marker = "sys_platform != 'win32'" }, ] scrub = [ { name = "mutagen" }, ] sonosupdate = [ { name = "soco" }, ] thumbnails = [ { name = "pillow" }, { name = "pyxdg" }, ] tidal = [ { name = "requests-oauthlib" }, ] titlecase = [ { name = "titlecase" }, ] web = [ { name = "flask" }, { name = "flask-cors" }, ] [package.dev-dependencies] dev = [ { name = "beautifulsoup4" }, { name = "codecov" }, { name = "docstrfmt" }, { name = "docutils" }, { name = "flask" }, { name = "langdetect" }, { name = "mypy" }, { name = "py7zr" }, { name = "pydata-sphinx-theme", version = "0.19.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "pydata-sphinx-theme", version = "0.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "pylast" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-factoryboy" }, { name = "pytest-flask" }, { name = "python-mpd2" }, { name = "python3-discogs-client" }, { name = "pyxdg" }, { name = "rarfile" }, { name = "requests-mock" }, { name = "requests-oauthlib" }, { name = "responses" }, { name = "ruff" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-copybutton" }, { name = "sphinx-design", version = "0.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx-design", version = "0.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-lint" }, { name = "sphinx-toolbox" }, { name = "titlecase" }, { name = "types-beautifulsoup4" }, { name = "types-docutils" }, { name = "types-flask-cors" }, { name = "types-pillow" }, { name = "types-pyyaml" }, { name = "types-requests" }, { name = "types-urllib3" }, ] docs = [ { name = "docutils" }, { name = "pydata-sphinx-theme", version = "0.19.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "pydata-sphinx-theme", version = "0.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-copybutton" }, { name = "sphinx-design", version = "0.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx-design", version = "0.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-lint" }, { name = "sphinx-toolbox" }, { name = "titlecase" }, ] lint = [ { name = "docstrfmt" }, { name = "ruff" }, { name = "sphinx-lint" }, ] release = [ { name = "click" }, { name = "tomli" }, ] test = [ { name = "beautifulsoup4" }, { name = "codecov" }, { name = "flask" }, { name = "langdetect" }, { name = "py7zr" }, { name = "pylast" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-factoryboy" }, { name = "pytest-flask" }, { name = "python-mpd2" }, { name = "python3-discogs-client" }, { name = "pyxdg" }, { name = "rarfile" }, { name = "requests-mock" }, { name = "requests-oauthlib" }, { name = "responses" }, { name = "titlecase" }, ] typing = [ { name = "mypy" }, { name = "types-beautifulsoup4" }, { name = "types-docutils" }, { name = "types-flask-cors" }, { name = "types-pillow" }, { name = "types-pyyaml" }, { name = "types-requests" }, { name = "types-urllib3" }, ] [package.metadata] requires-dist = [ { name = "beautifulsoup4", marker = "extra == 'fetchart'" }, { name = "beautifulsoup4", marker = "extra == 'lyrics'" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "confuse", specifier = ">=2.2.0" }, { name = "dbus-python", marker = "sys_platform != 'win32' and extra == 'metasync'" }, { name = "flask", marker = "extra == 'aura'" }, { name = "flask", marker = "extra == 'web'" }, { name = "flask-cors", marker = "extra == 'aura'" }, { name = "flask-cors", marker = "extra == 'web'" }, { name = "jellyfish" }, { name = "langdetect", marker = "extra == 'fetchart'" }, { name = "langdetect", marker = "extra == 'lyrics'" }, { name = "lap", specifier = ">=0.5.12" }, { name = "librosa", marker = "extra == 'autobpm'", specifier = ">=0.11" }, { name = "mediafile", specifier = ">=0.17.0" }, { name = "mutagen", marker = "extra == 'scrub'", specifier = ">=1.33" }, { name = "numba", marker = "extra == 'autobpm'", specifier = ">=0.65.1" }, { name = "numpy", marker = "python_full_version < '3.13'", specifier = ">=2.0.2" }, { name = "numpy", marker = "python_full_version >= '3.13'", specifier = ">=2.3.5" }, { name = "packaging", specifier = ">=24.0" }, { name = "pillow", marker = "extra == 'aura'" }, { name = "pillow", marker = "extra == 'embedart'" }, { name = "pillow", marker = "extra == 'fetchart'" }, { name = "pillow", marker = "extra == 'thumbnails'" }, { name = "platformdirs", specifier = ">=3.5.0" }, { name = "py7zr", marker = "extra == 'import'" }, { name = "pyacoustid", marker = "extra == 'chroma'", specifier = ">=1.3.1,<2" }, { name = "pygobject", marker = "sys_platform != 'win32' and extra == 'bpd'" }, { name = "pygobject", marker = "sys_platform != 'win32' and extra == 'replaygain'" }, { name = "pylast", marker = "extra == 'lastgenre'" }, { name = "pylast", marker = "extra == 'lastimport'" }, { name = "python-mpd2", marker = "extra == 'mpdstats'", specifier = ">=0.4.2" }, { name = "python3-discogs-client", marker = "extra == 'discogs'", specifier = ">=2.3.15" }, { name = "pyxdg", marker = "extra == 'thumbnails'" }, { name = "pyyaml" }, { name = "rarfile", marker = "extra == 'import'" }, { name = "reflink", marker = "extra == 'reflink'" }, { name = "requests", specifier = ">=2.32.5" }, { name = "requests", marker = "extra == 'absubmit'" }, { name = "requests", marker = "extra == 'embyupdate'" }, { name = "requests", marker = "extra == 'fetchart'" }, { name = "requests", marker = "extra == 'kodiupdate'" }, { name = "requests", marker = "extra == 'lyrics'" }, { name = "requests", marker = "extra == 'plexupdate'" }, { name = "requests-oauthlib", marker = "extra == 'beatport'", specifier = ">=0.6.1" }, { name = "requests-oauthlib", marker = "extra == 'tidal'", specifier = ">=0.6.1" }, { name = "requests-ratelimiter", specifier = ">=0.7.0" }, { name = "resampy", marker = "extra == 'autobpm'", specifier = ">=0.4.3" }, { name = "soco", marker = "extra == 'sonosupdate'" }, { name = "titlecase", marker = "extra == 'titlecase'" }, { name = "typing-extensions" }, { name = "unidecode", specifier = ">=1.3.6" }, ] provides-extras = ["absubmit", "aura", "autobpm", "beatport", "bpd", "chroma", "discogs", "embedart", "embyupdate", "fetchart", "import", "kodiupdate", "lastgenre", "lastimport", "lyrics", "metasync", "mpdstats", "plexupdate", "reflink", "replaygain", "scrub", "sonosupdate", "tidal", "titlecase", "thumbnails", "web"] [package.metadata.requires-dev] dev = [ { name = "beautifulsoup4" }, { name = "codecov", specifier = ">=2.1.13" }, { name = "docstrfmt", specifier = ">=2.0.2" }, { name = "docutils", specifier = ">=0.20.1" }, { name = "flask" }, { name = "langdetect" }, { name = "mypy" }, { name = "py7zr" }, { name = "pydata-sphinx-theme" }, { name = "pylast" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-factoryboy", specifier = ">=2.8.1" }, { name = "pytest-flask" }, { name = "python-mpd2" }, { name = "python3-discogs-client", specifier = ">=2.3.15" }, { name = "pyxdg" }, { name = "rarfile" }, { name = "requests-mock", specifier = ">=1.12.1" }, { name = "requests-oauthlib" }, { name = "responses", specifier = ">=0.3.0" }, { name = "ruff", specifier = ">=0.13.0" }, { name = "sphinx", specifier = "<9" }, { name = "sphinx-copybutton", specifier = ">=0.5.2" }, { name = "sphinx-design", specifier = ">=0.6.1" }, { name = "sphinx-lint", specifier = ">=1.0.0" }, { name = "sphinx-toolbox", specifier = ">=4.1.0" }, { name = "titlecase", specifier = ">=2.4.1,<3" }, { name = "types-beautifulsoup4" }, { name = "types-docutils", specifier = ">=0.22.2.20251006" }, { name = "types-flask-cors" }, { name = "types-pillow" }, { name = "types-pyyaml" }, { name = "types-requests" }, { name = "types-urllib3" }, ] docs = [ { name = "docutils", specifier = ">=0.20.1" }, { name = "pydata-sphinx-theme" }, { name = "sphinx", specifier = "<9" }, { name = "sphinx-copybutton", specifier = ">=0.5.2" }, { name = "sphinx-design", specifier = ">=0.6.1" }, { name = "sphinx-lint", specifier = ">=1.0.0" }, { name = "sphinx-toolbox", specifier = ">=4.1.0" }, { name = "titlecase", specifier = ">=2.4.1,<3" }, ] lint = [ { name = "docstrfmt", specifier = ">=2.0.2" }, { name = "ruff", specifier = ">=0.13.0" }, { name = "sphinx-lint", specifier = ">=1.0.0" }, ] release = [ { name = "click", specifier = ">=8.1.7" }, { name = "tomli", specifier = ">=2.0.1" }, ] test = [ { name = "beautifulsoup4" }, { name = "codecov", specifier = ">=2.1.13" }, { name = "flask" }, { name = "langdetect" }, { name = "py7zr" }, { name = "pylast" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-factoryboy", specifier = ">=2.8.1" }, { name = "pytest-flask" }, { name = "python-mpd2" }, { name = "python3-discogs-client", specifier = ">=2.3.15" }, { name = "pyxdg" }, { name = "rarfile" }, { name = "requests-mock", specifier = ">=1.12.1" }, { name = "requests-oauthlib" }, { name = "responses", specifier = ">=0.3.0" }, { name = "titlecase", specifier = ">=2.4.1,<3" }, ] typing = [ { name = "mypy" }, { name = "types-beautifulsoup4" }, { name = "types-docutils", specifier = ">=0.22.2.20251006" }, { name = "types-flask-cors" }, { name = "types-pillow" }, { name = "types-pyyaml" }, { name = "types-requests" }, { name = "types-urllib3" }, ] [[package]] name = "black" version = "26.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, { name = "packaging" }, { name = "pathspec" }, { name = "platformdirs" }, { name = "pytokens" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c0/37/5628dd55bf2b34257fc7603f0fe97c40e3aaf24265f416a9c85c95ca1436/black-26.5.1.tar.gz", hash = "sha256:dd321f668053961824bcc1be1cc1df748b2d7e4fa28086b08331e577b0100a73", size = 679439, upload-time = "2026-05-18T16:53:36.107Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/be/84/b3f55026206a9e8820a91503308075ca48eadc515e436731ca01dbe043b3/black-26.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9942db8888e06943c5dde66ca0037dcff82a2a4ec1ad0ada9e0d2ee9d9823893", size = 1987719, upload-time = "2026-05-18T17:05:02.757Z" }, { url = "https://files.pythonhosted.org/packages/c6/34/7db312c5e5783d6e76cffd9d5ac8972a32badae4c6e3288dac0eed8d3bed/black-26.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:89c93167a74d3a75dfaa38a5c7cca015537d5820dd7f17d63267d674a61cae90", size = 1810083, upload-time = "2026-05-18T17:05:04.302Z" }, { url = "https://files.pythonhosted.org/packages/33/e2/e0101e73c2c8727634e2efcb35e2b34bd23ad70dfa673789f5773a591b21/black-26.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f2cd76d069cc54c71f10360744ba8983fbb616903b4304a85b734915c8e1b4", size = 1860633, upload-time = "2026-05-18T17:05:06.391Z" }, { url = "https://files.pythonhosted.org/packages/b0/4c/e15c0c5b23cf3651035fe5addcce90e283af3548a3f91bb03d81b83106ab/black-26.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:87ed5c6f450580a2f6790bc7cbfb016dfc73bc750249762268a3695361315eef", size = 1477886, upload-time = "2026-05-18T17:05:07.96Z" }, { url = "https://files.pythonhosted.org/packages/9f/3f/59d43ade98d2ce5c8dc34a4e46cbecd177e6d55d7d4092969c6003ccc655/black-26.5.1-cp310-cp310-win_arm64.whl", hash = "sha256:58b4bd92cf88aacf83d88479c8f9caee044b1ec55f2451a337354a7ea2590a22", size = 1277111, upload-time = "2026-05-18T17:05:09.473Z" }, { url = "https://files.pythonhosted.org/packages/4b/96/3c3e09f09f44a37aac36b178a279cd19aa7001bd796187a7b162a294c81f/black-26.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96ae2c733b2aabdd9986e2c5df628ff3473676cd1c5faded1ff496cf6d74083c", size = 1970639, upload-time = "2026-05-18T17:05:11.461Z" }, { url = "https://files.pythonhosted.org/packages/83/ea/5ad117b9ee3ecd933c712bcbae610006e5b7cc9f41c526cd7ed3b6c4124c/black-26.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0e48b87e03bf109288e55cfceadcfa15ff5470aca2851a851950ed2926f450d7", size = 1792130, upload-time = "2026-05-18T17:05:12.983Z" }, { url = "https://files.pythonhosted.org/packages/06/3a/7c448bc623fcdfa96672531beb5a616ea5e64f6975955254d7731ffb0ad9/black-26.5.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5119fa92ae61f786e8c3662fd60aece1d0a2dd5cca5d0c79417a95e7a4272a59", size = 1846134, upload-time = "2026-05-18T17:05:14.506Z" }, { url = "https://files.pythonhosted.org/packages/a1/5b/0b39b3a5917f0657ac014ad2edb58c139553a478adfe7f817abf1622ff6e/black-26.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:30d3c14661f2792e9142cce3eeeb1cbc175b3eb5f733be0c8eeb99651e52b0c3", size = 1478883, upload-time = "2026-05-18T17:05:16.542Z" }, { url = "https://files.pythonhosted.org/packages/4c/48/dc222692e0f95030db1bbfb6c857e76858bad09058221ea7aae815255327/black-26.5.1-cp311-cp311-win_arm64.whl", hash = "sha256:1ef92b76f7733f282fd096ea406200b5a286c42947412b0eaff3a74e3616cefe", size = 1277776, upload-time = "2026-05-18T17:05:18.029Z" }, { url = "https://files.pythonhosted.org/packages/24/99/7744b906703228264ef73bdd534df88ec1ef3de45c4e78f6d31b9e32d0c9/black-26.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4ad6fa01f941920f54f2bbb35f3df7673428a0ef98a0b0840c2eaef3b110efa8", size = 2012518, upload-time = "2026-05-18T17:05:20.108Z" }, { url = "https://files.pythonhosted.org/packages/b7/c0/c5a3b1636dfd09c42534f2b3cf33506814f6d3e066fb0879ffa16c1ae860/black-26.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3915f256e75a2d7cf88d8953d37f780455dc586cc72dee059c528fe77f581217", size = 1816016, upload-time = "2026-05-18T17:05:21.84Z" }, { url = "https://files.pythonhosted.org/packages/1f/0e/36044316b65ca471d3bb6d3703fd06fb50c6b727c3562f6a5a3153634f88/black-26.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d98d4137277c75dfb898ec8d846c4fd68ba1e9cf77f95e2865c203dc18f4c3d", size = 1884150, upload-time = "2026-05-18T17:05:23.546Z" }, { url = "https://files.pythonhosted.org/packages/b3/33/dafc5808c2af43672912111d7c3354af1615f7e2be3bed7a878461abbe4d/black-26.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:a1dca32d9f1784af512a13410ec204c6f7f0aa9797a111c42e1c03449821c264", size = 1486825, upload-time = "2026-05-18T17:05:25.004Z" }, { url = "https://files.pythonhosted.org/packages/82/14/b965ee6ad2a311f28bdbf692def3ee9848d2ae289dab28b27657fcee3e78/black-26.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:1037d5ac7b7b310b2632ad867ec8d0e4c4819dcdb0b820f63135da746a24e418", size = 1288646, upload-time = "2026-05-18T17:05:26.477Z" }, { url = "https://files.pythonhosted.org/packages/3f/5c/c384363980e11e25ca6b93205949bb331fbf35f4e0dbec376dfa6326cec8/black-26.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b36cf2ddf5566e205f6535f782a62194a184d33e175b64ae8c40b1737522be3", size = 2009020, upload-time = "2026-05-18T17:05:28.132Z" }, { url = "https://files.pythonhosted.org/packages/0b/df/9f31c5e0babbfed77d505fc5d120beb98b21b33feaeded3924ea941fe360/black-26.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f7ea64ebfa01b50f693508fc39f875e264446d3b097088f84f203b9d09618a0", size = 1813335, upload-time = "2026-05-18T17:05:31.266Z" }, { url = "https://files.pythonhosted.org/packages/fb/24/8e7b9a2fa61b0afd82209efe937557d180a1fa055bd7f6161eb9defc3719/black-26.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecb3e624844c798144e9bd986954e0adc81d8911a1f30f375e1252fe26e8c294", size = 1881614, upload-time = "2026-05-18T17:05:32.718Z" }, { url = "https://files.pythonhosted.org/packages/49/ad/b4e0d9365ba8ac34f6bbab62a4b1b2dd5d618fac3fa1b8db968c844201b5/black-26.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:e1a26503279b6b310669fb0b219c39e4820b77e8189fe80f522bb511f247db0a", size = 1488925, upload-time = "2026-05-18T17:05:34.259Z" }, { url = "https://files.pythonhosted.org/packages/a1/4b/652b859bf5df88a751c30451b09338f7fd26a77d1271c666992f836b7711/black-26.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c34b25da232ead53a6f335b76dbea124f4d152ad568b9080d6f944bc2b34b52", size = 1289883, upload-time = "2026-05-18T17:05:36.019Z" }, { url = "https://files.pythonhosted.org/packages/a6/16/a8da8eb208c51c7f4ce74609a45d0dcc6d8a2141e45e81ee5289d1bb0d59/black-26.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e88976690a64b0af98312ca958415849cb42423423c5f2ee74af4b49a97a2168", size = 2004800, upload-time = "2026-05-18T17:05:38.182Z" }, { url = "https://files.pythonhosted.org/packages/11/8a/a479296a19e383b70a725882a6cf3d786540601ff03cabbaaf1cce864c5a/black-26.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32d5ea7f6c8bdfa6e648326ebca1f02b0764e2a029edc6f8dce2627e19d468c3", size = 1815576, upload-time = "2026-05-18T17:05:40.309Z" }, { url = "https://files.pythonhosted.org/packages/81/6b/cfaf3d39f25132c156a068f6b805576c9103a84086019507c70e1911ee7d/black-26.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea8d16dc41655aa113cd64665e7219446cd7e4ff2248d7178eaa905190c86b18", size = 1877927, upload-time = "2026-05-18T17:05:42.463Z" }, { url = "https://files.pythonhosted.org/packages/66/76/302e313964bcff7e28df329d39f84f5270095730d85ff0acc260610a0d82/black-26.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:577f21094ea469ef92ec1adaf2c9441a226d2144d01a5be2fa823cecf6543e50", size = 1511860, upload-time = "2026-05-18T17:05:43.943Z" }, { url = "https://files.pythonhosted.org/packages/27/4e/a3827e35e0e567f9f9ee59e2a0ab979267dca98718f25547ca8c6733afd4/black-26.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:ed1a20af114c301a0269bf01163d51dbef72737fd65f850001e7cbe7f3c7abae", size = 1316632, upload-time = "2026-05-18T17:05:45.521Z" }, { url = "https://files.pythonhosted.org/packages/94/51/f975cae76d44274cc2868dc9040ac5d58d464784610234455b4e7b19c6ef/black-26.5.1-py3-none-any.whl", hash = "sha256:4ed7f7da04046d2e488437170797d3b4a4ad83906683bcb7dfc68b673bbce5e2", size = 213693, upload-time = "2026-05-18T16:53:33.964Z" }, ] [[package]] name = "blinker" version = "1.9.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, ] [[package]] name = "brotli" version = "1.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/64/10/a090475284fc4a71aed40a96f32e44a7fe5bda39687353dd977720b211b6/brotli-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3b90b767916ac44e93a8e28ce6adf8d551e43affb512f2377c732d486ac6514e", size = 863089, upload-time = "2025-11-05T18:38:01.181Z" }, { url = "https://files.pythonhosted.org/packages/03/41/17416630e46c07ac21e378c3464815dd2e120b441e641bc516ac32cc51d2/brotli-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6be67c19e0b0c56365c6a76e393b932fb0e78b3b56b711d180dd7013cb1fd984", size = 445442, upload-time = "2025-11-05T18:38:02.434Z" }, { url = "https://files.pythonhosted.org/packages/24/31/90cc06584deb5d4fcafc0985e37741fc6b9717926a78674bbb3ce018957e/brotli-1.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0bbd5b5ccd157ae7913750476d48099aaf507a79841c0d04a9db4415b14842de", size = 1532658, upload-time = "2025-11-05T18:38:03.588Z" }, { url = "https://files.pythonhosted.org/packages/62/17/33bf0c83bcbc96756dfd712201d87342732fad70bb3472c27e833a44a4f9/brotli-1.2.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3f3c908bcc404c90c77d5a073e55271a0a498f4e0756e48127c35d91cf155947", size = 1631241, upload-time = "2025-11-05T18:38:04.582Z" }, { url = "https://files.pythonhosted.org/packages/48/10/f47854a1917b62efe29bc98ac18e5d4f71df03f629184575b862ef2e743b/brotli-1.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1b557b29782a643420e08d75aea889462a4a8796e9a6cf5621ab05a3f7da8ef2", size = 1424307, upload-time = "2025-11-05T18:38:05.587Z" }, { url = "https://files.pythonhosted.org/packages/e4/b7/f88eb461719259c17483484ea8456925ee057897f8e64487d76e24e5e38d/brotli-1.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81da1b229b1889f25adadc929aeb9dbc4e922bd18561b65b08dd9343cfccca84", size = 1488208, upload-time = "2025-11-05T18:38:06.613Z" }, { url = "https://files.pythonhosted.org/packages/26/59/41bbcb983a0c48b0b8004203e74706c6b6e99a04f3c7ca6f4f41f364db50/brotli-1.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ff09cd8c5eec3b9d02d2408db41be150d8891c5566addce57513bf546e3d6c6d", size = 1597574, upload-time = "2025-11-05T18:38:07.838Z" }, { url = "https://files.pythonhosted.org/packages/8e/e6/8c89c3bdabbe802febb4c5c6ca224a395e97913b5df0dff11b54f23c1788/brotli-1.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a1778532b978d2536e79c05dac2d8cd857f6c55cd0c95ace5b03740824e0e2f1", size = 1492109, upload-time = "2025-11-05T18:38:08.816Z" }, { url = "https://files.pythonhosted.org/packages/ed/9a/4b19d4310b2dbd545c0c33f176b0528fa68c3cd0754e34b2f2bcf56548ae/brotli-1.2.0-cp310-cp310-win32.whl", hash = "sha256:b232029d100d393ae3c603c8ffd7e3fe6f798c5e28ddca5feabb8e8fdb732997", size = 334461, upload-time = "2025-11-05T18:38:10.729Z" }, { url = "https://files.pythonhosted.org/packages/ac/39/70981d9f47705e3c2b95c0847dfa3e7a37aa3b7c6030aedc4873081ed005/brotli-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:ef87b8ab2704da227e83a246356a2b179ef826f550f794b2c52cddb4efbd0196", size = 369035, upload-time = "2025-11-05T18:38:11.827Z" }, { url = "https://files.pythonhosted.org/packages/7a/ef/f285668811a9e1ddb47a18cb0b437d5fc2760d537a2fe8a57875ad6f8448/brotli-1.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:15b33fe93cedc4caaff8a0bd1eb7e3dab1c61bb22a0bf5bdfdfd97cd7da79744", size = 863110, upload-time = "2025-11-05T18:38:12.978Z" }, { url = "https://files.pythonhosted.org/packages/50/62/a3b77593587010c789a9d6eaa527c79e0848b7b860402cc64bc0bc28a86c/brotli-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:898be2be399c221d2671d29eed26b6b2713a02c2119168ed914e7d00ceadb56f", size = 445438, upload-time = "2025-11-05T18:38:14.208Z" }, { url = "https://files.pythonhosted.org/packages/cd/e1/7fadd47f40ce5549dc44493877db40292277db373da5053aff181656e16e/brotli-1.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:350c8348f0e76fff0a0fd6c26755d2653863279d086d3aa2c290a6a7251135dd", size = 1534420, upload-time = "2025-11-05T18:38:15.111Z" }, { url = "https://files.pythonhosted.org/packages/12/8b/1ed2f64054a5a008a4ccd2f271dbba7a5fb1a3067a99f5ceadedd4c1d5a7/brotli-1.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1ad3fda65ae0d93fec742a128d72e145c9c7a99ee2fcd667785d99eb25a7fe", size = 1632619, upload-time = "2025-11-05T18:38:16.094Z" }, { url = "https://files.pythonhosted.org/packages/89/5a/7071a621eb2d052d64efd5da2ef55ecdac7c3b0c6e4f9d519e9c66d987ef/brotli-1.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:40d918bce2b427a0c4ba189df7a006ac0c7277c180aee4617d99e9ccaaf59e6a", size = 1426014, upload-time = "2025-11-05T18:38:17.177Z" }, { url = "https://files.pythonhosted.org/packages/26/6d/0971a8ea435af5156acaaccec1a505f981c9c80227633851f2810abd252a/brotli-1.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2a7f1d03727130fc875448b65b127a9ec5d06d19d0148e7554384229706f9d1b", size = 1489661, upload-time = "2025-11-05T18:38:18.41Z" }, { url = "https://files.pythonhosted.org/packages/f3/75/c1baca8b4ec6c96a03ef8230fab2a785e35297632f402ebb1e78a1e39116/brotli-1.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9c79f57faa25d97900bfb119480806d783fba83cd09ee0b33c17623935b05fa3", size = 1599150, upload-time = "2025-11-05T18:38:19.792Z" }, { url = "https://files.pythonhosted.org/packages/0d/1a/23fcfee1c324fd48a63d7ebf4bac3a4115bdb1b00e600f80f727d850b1ae/brotli-1.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:844a8ceb8483fefafc412f85c14f2aae2fb69567bf2a0de53cdb88b73e7c43ae", size = 1493505, upload-time = "2025-11-05T18:38:20.913Z" }, { url = "https://files.pythonhosted.org/packages/36/e5/12904bbd36afeef53d45a84881a4810ae8810ad7e328a971ebbfd760a0b3/brotli-1.2.0-cp311-cp311-win32.whl", hash = "sha256:aa47441fa3026543513139cb8926a92a8e305ee9c71a6209ef7a97d91640ea03", size = 334451, upload-time = "2025-11-05T18:38:21.94Z" }, { url = "https://files.pythonhosted.org/packages/02/8b/ecb5761b989629a4758c394b9301607a5880de61ee2ee5fe104b87149ebc/brotli-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:022426c9e99fd65d9475dce5c195526f04bb8be8907607e27e747893f6ee3e24", size = 369035, upload-time = "2025-11-05T18:38:22.941Z" }, { url = "https://files.pythonhosted.org/packages/11/ee/b0a11ab2315c69bb9b45a2aaed022499c9c24a205c3a49c3513b541a7967/brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84", size = 861543, upload-time = "2025-11-05T18:38:24.183Z" }, { url = "https://files.pythonhosted.org/packages/e1/2f/29c1459513cd35828e25531ebfcbf3e92a5e49f560b1777a9af7203eb46e/brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b", size = 444288, upload-time = "2025-11-05T18:38:25.139Z" }, { url = "https://files.pythonhosted.org/packages/3d/6f/feba03130d5fceadfa3a1bb102cb14650798c848b1df2a808356f939bb16/brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d", size = 1528071, upload-time = "2025-11-05T18:38:26.081Z" }, { url = "https://files.pythonhosted.org/packages/2b/38/f3abb554eee089bd15471057ba85f47e53a44a462cfce265d9bf7088eb09/brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca", size = 1626913, upload-time = "2025-11-05T18:38:27.284Z" }, { url = "https://files.pythonhosted.org/packages/03/a7/03aa61fbc3c5cbf99b44d158665f9b0dd3d8059be16c460208d9e385c837/brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f", size = 1419762, upload-time = "2025-11-05T18:38:28.295Z" }, { url = "https://files.pythonhosted.org/packages/21/1b/0374a89ee27d152a5069c356c96b93afd1b94eae83f1e004b57eb6ce2f10/brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28", size = 1484494, upload-time = "2025-11-05T18:38:29.29Z" }, { url = "https://files.pythonhosted.org/packages/cf/57/69d4fe84a67aef4f524dcd075c6eee868d7850e85bf01d778a857d8dbe0a/brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7", size = 1593302, upload-time = "2025-11-05T18:38:30.639Z" }, { url = "https://files.pythonhosted.org/packages/d5/3b/39e13ce78a8e9a621c5df3aeb5fd181fcc8caba8c48a194cd629771f6828/brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036", size = 1487913, upload-time = "2025-11-05T18:38:31.618Z" }, { url = "https://files.pythonhosted.org/packages/62/28/4d00cb9bd76a6357a66fcd54b4b6d70288385584063f4b07884c1e7286ac/brotli-1.2.0-cp312-cp312-win32.whl", hash = "sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161", size = 334362, upload-time = "2025-11-05T18:38:32.939Z" }, { url = "https://files.pythonhosted.org/packages/1c/4e/bc1dcac9498859d5e353c9b153627a3752868a9d5f05ce8dedd81a2354ab/brotli-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44", size = 369115, upload-time = "2025-11-05T18:38:33.765Z" }, { url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523, upload-time = "2025-11-05T18:38:34.67Z" }, { url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289, upload-time = "2025-11-05T18:38:35.6Z" }, { url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076, upload-time = "2025-11-05T18:38:36.639Z" }, { url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880, upload-time = "2025-11-05T18:38:37.623Z" }, { url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737, upload-time = "2025-11-05T18:38:38.729Z" }, { url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440, upload-time = "2025-11-05T18:38:39.916Z" }, { url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313, upload-time = "2025-11-05T18:38:41.24Z" }, { url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945, upload-time = "2025-11-05T18:38:42.277Z" }, { url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368, upload-time = "2025-11-05T18:38:43.345Z" }, { url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116, upload-time = "2025-11-05T18:38:44.609Z" }, { url = "https://files.pythonhosted.org/packages/17/e1/298c2ddf786bb7347a1cd71d63a347a79e5712a7c0cba9e3c3458ebd976f/brotli-1.2.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6c12dad5cd04530323e723787ff762bac749a7b256a5bece32b2243dd5c27b21", size = 863080, upload-time = "2025-11-05T18:38:45.503Z" }, { url = "https://files.pythonhosted.org/packages/84/0c/aac98e286ba66868b2b3b50338ffbd85a35c7122e9531a73a37a29763d38/brotli-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3219bd9e69868e57183316ee19c84e03e8f8b5a1d1f2667e1aa8c2f91cb061ac", size = 445453, upload-time = "2025-11-05T18:38:46.433Z" }, { url = "https://files.pythonhosted.org/packages/ec/f1/0ca1f3f99ae300372635ab3fe2f7a79fa335fee3d874fa7f9e68575e0e62/brotli-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:963a08f3bebd8b75ac57661045402da15991468a621f014be54e50f53a58d19e", size = 1528168, upload-time = "2025-11-05T18:38:47.371Z" }, { url = "https://files.pythonhosted.org/packages/d6/a6/2ebfc8f766d46df8d3e65b880a2e220732395e6d7dc312c1e1244b0f074a/brotli-1.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9322b9f8656782414b37e6af884146869d46ab85158201d82bab9abbcb971dc7", size = 1627098, upload-time = "2025-11-05T18:38:48.385Z" }, { url = "https://files.pythonhosted.org/packages/f3/2f/0976d5b097ff8a22163b10617f76b2557f15f0f39d6a0fe1f02b1a53e92b/brotli-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cf9cba6f5b78a2071ec6fb1e7bd39acf35071d90a81231d67e92d637776a6a63", size = 1419861, upload-time = "2025-11-05T18:38:49.372Z" }, { url = "https://files.pythonhosted.org/packages/9c/97/d76df7176a2ce7616ff94c1fb72d307c9a30d2189fe877f3dd99af00ea5a/brotli-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7547369c4392b47d30a3467fe8c3330b4f2e0f7730e45e3103d7d636678a808b", size = 1484594, upload-time = "2025-11-05T18:38:50.655Z" }, { url = "https://files.pythonhosted.org/packages/d3/93/14cf0b1216f43df5609f5b272050b0abd219e0b54ea80b47cef9867b45e7/brotli-1.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361", size = 1593455, upload-time = "2025-11-05T18:38:51.624Z" }, { url = "https://files.pythonhosted.org/packages/b3/73/3183c9e41ca755713bdf2cc1d0810df742c09484e2e1ddd693bee53877c1/brotli-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2d085ded05278d1c7f65560aae97b3160aeb2ea2c0b3e26204856beccb60888", size = 1488164, upload-time = "2025-11-05T18:38:53.079Z" }, { url = "https://files.pythonhosted.org/packages/64/6a/0c78d8f3a582859236482fd9fa86a65a60328a00983006bcf6d83b7b2253/brotli-1.2.0-cp314-cp314-win32.whl", hash = "sha256:832c115a020e463c2f67664560449a7bea26b0c1fdd690352addad6d0a08714d", size = 339280, upload-time = "2025-11-05T18:38:54.02Z" }, { url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639, upload-time = "2025-11-05T18:38:55.67Z" }, ] [[package]] name = "brotlicffi" version = "1.2.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8a/b6/017dc5f852ed9b8735af77774509271acbf1de02d238377667145fcee01d/brotlicffi-1.2.0.1.tar.gz", hash = "sha256:c20d5c596278307ad06414a6d95a892377ea274a5c6b790c2548c009385d621c", size = 478156, upload-time = "2026-03-05T19:54:11.547Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/f9/dfa56316837fa798eac19358351e974de8e1e2ca9475af4cb90293cd6576/brotlicffi-1.2.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c85e65913cf2b79c57a3fdd05b98d9731d9255dc0cb696b09376cc091b9cddd", size = 433046, upload-time = "2026-03-05T19:53:46.209Z" }, { url = "https://files.pythonhosted.org/packages/4a/f5/f8f492158c76b0d940388801f04f747028971ad5774287bded5f1e53f08d/brotlicffi-1.2.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:535f2d05d0273408abc13fc0eebb467afac17b0ad85090c8913690d40207dac5", size = 1541126, upload-time = "2026-03-05T19:53:48.248Z" }, { url = "https://files.pythonhosted.org/packages/3b/e1/ff87af10ac419600c63e9287a0649c673673ae6b4f2bcf48e96cb2f89f60/brotlicffi-1.2.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce17eb798ca59ecec67a9bb3fd7a4304e120d1cd02953ce522d959b9a84d58ac", size = 1541983, upload-time = "2026-03-05T19:53:50.317Z" }, { url = "https://files.pythonhosted.org/packages/47/c0/80ecd9bd45776109fab14040e478bf63e456967c9ddee2353d8330ed8de1/brotlicffi-1.2.0.1-cp314-cp314t-win32.whl", hash = "sha256:3c9544f83cb715d95d7eab3af4adbbef8b2093ad6382288a83b3a25feb1a57ec", size = 349047, upload-time = "2026-03-05T19:53:52.215Z" }, { url = "https://files.pythonhosted.org/packages/ab/98/13e5b250236a281b6cd9e92a01ee1ae231029fa78faee932ef3766e1cb24/brotlicffi-1.2.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:625f8115d32ae9c0740d01ea51518437c3fbaa3e78d41cb18459f6f7ac326000", size = 385652, upload-time = "2026-03-05T19:53:53.892Z" }, { url = "https://files.pythonhosted.org/packages/9a/9f/b98dcd4af47994cee97aebac866996a006a2e5fc1fd1e2b82a8ad95cf09c/brotlicffi-1.2.0.1-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:91ba5f0ccc040f6ff8f7efaf839f797723d03ed46acb8ae9408f99ffd2572cf4", size = 432608, upload-time = "2026-03-05T19:53:56.736Z" }, { url = "https://files.pythonhosted.org/packages/b1/7a/ac4ee56595a061e3718a6d1ea7e921f4df156894acffb28ed88a1fd52022/brotlicffi-1.2.0.1-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be9a670c6811af30a4bd42d7116dc5895d3b41beaa8ed8a89050447a0181f5ce", size = 1534257, upload-time = "2026-03-05T19:53:58.667Z" }, { url = "https://files.pythonhosted.org/packages/99/39/e7410db7f6f56de57744ea52a115084ceb2735f4d44973f349bb92136586/brotlicffi-1.2.0.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3314a3476f59e5443f9f72a6dff16edc0c3463c9b318feaef04ae3e4683f5a", size = 1536838, upload-time = "2026-03-05T19:54:00.705Z" }, { url = "https://files.pythonhosted.org/packages/a6/75/6e7977d1935fc3fbb201cbd619be8f2c7aea25d40a096967132854b34708/brotlicffi-1.2.0.1-cp38-abi3-win32.whl", hash = "sha256:82ea52e2b5d3145b6c406ebd3efb0d55db718b7ad996bd70c62cec0439de1187", size = 343337, upload-time = "2026-03-05T19:54:02.446Z" }, { url = "https://files.pythonhosted.org/packages/d8/ef/e7e485ce5e4ba3843a0a92feb767c7b6098fd6e65ce752918074d175ae71/brotlicffi-1.2.0.1-cp38-abi3-win_amd64.whl", hash = "sha256:da2e82a08e7778b8bc539d27ca03cdd684113e81394bfaaad8d0dfc6a17ddede", size = 379026, upload-time = "2026-03-05T19:54:04.322Z" }, { url = "https://files.pythonhosted.org/packages/7f/53/6262c2256513e6f530d81642477cb19367270922063eaa2d7b781d8c723d/brotlicffi-1.2.0.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e015af99584c6db1490a69a210c765953e473e63adc2d891ac3062a737c9e851", size = 402265, upload-time = "2026-03-05T19:54:05.858Z" }, { url = "https://files.pythonhosted.org/packages/1f/d9/d5340b43cf5fbe7fe5a083d237e5338cc1caa73bea523be1c5e452c26290/brotlicffi-1.2.0.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:37cb587d32bf7168e2218c455e22e409ad1f3157c6c71945879a311f3e6b6abf", size = 406710, upload-time = "2026-03-05T19:54:07.272Z" }, { url = "https://files.pythonhosted.org/packages/a3/82/dbced4c1e0792efdf23fd90ff6d2a320c64ff4dfef7aacc85c04fde9ddd2/brotlicffi-1.2.0.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d6ba65dd528892b4d9960beba2ae011a753620bcfc66cf6fa3cee18d7b0baa4", size = 402787, upload-time = "2026-03-05T19:54:08.73Z" }, { url = "https://files.pythonhosted.org/packages/ef/6f/534205ba7590c9a8716a614f270c5c2ec419b5b7079b3f9cd31b7b5580de/brotlicffi-1.2.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2a5575653b0672638ba039b82fda56854934d7a6a24d4b8b5033f73ab43cbc1", size = 375108, upload-time = "2026-03-05T19:54:10.079Z" }, ] [[package]] name = "cachecontrol" version = "0.14.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "msgpack" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2d/f6/c972b32d80760fb79d6b9eeb0b3010a46b89c0b23cf6329417ff7886cd22/cachecontrol-0.14.4.tar.gz", hash = "sha256:e6220afafa4c22a47dd0badb319f84475d79108100d04e26e8542ef7d3ab05a1", size = 16150, upload-time = "2025-11-14T04:32:13.138Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/79/c45f2d53efe6ada1110cf6f9fca095e4ff47a0454444aefdde6ac4789179/cachecontrol-0.14.4-py3-none-any.whl", hash = "sha256:b7ac014ff72ee199b5f8af1de29d60239954f223e948196fa3d84adaffc71d2b", size = 22247, upload-time = "2025-11-14T04:32:11.733Z" }, ] [package.optional-dependencies] filecache = [ { name = "filelock" }, ] [[package]] name = "certifi" version = "2026.7.22" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, ] [[package]] name = "cffi" version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/57/5f/ff100cae70ebe9d8df1c01a00e510e45d9adb5c1fdda84791b199141de97/cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9", size = 531036, upload-time = "2026-07-06T21:34:30.382Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c0/e9/6d7724983b3d5a0908dbf74f64038ade77c18646ff6636ec7894fd392ce1/cffi-2.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:b65f590ef2a44640f9a05dbb548a429b4ade77913ce683ac8b1480777658a6c0", size = 183837, upload-time = "2026-07-06T21:32:09.655Z" }, { url = "https://files.pythonhosted.org/packages/69/aa/24580a278de21fd7322635556334d9b535f1cbc00b0a3919447cdf464c65/cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164bff1657b2a74f0b6d54e11c9b375bc97b931f2ca9c43fcf875838da1570dd", size = 184226, upload-time = "2026-07-06T21:32:11.196Z" }, { url = "https://files.pythonhosted.org/packages/88/a9/02cae418ec4beb282ace11958d9d4737793439d561fadc7e6d56f2e2b354/cffi-2.1.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:c941bb58d5a6e1c3892d86e42927ed6c180302f07e6d395d08c416e594b98b46", size = 211107, upload-time = "2026-07-06T21:32:12.328Z" }, { url = "https://files.pythonhosted.org/packages/3b/30/c806937ed5e4c2c7ac30d9d6b76b5dc57ff8b75d83800d9bb11a8253cf2a/cffi-2.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a016194dbe13d14ee9556e734b772d8d67b947092b268d757fd4290e3ba2dfc2", size = 218733, upload-time = "2026-07-06T21:32:13.67Z" }, { url = "https://files.pythonhosted.org/packages/f9/cf/398272b8bbfd58aa314fda5a7f1cdbb26d1d78ae324a11211521315dd1f0/cffi-2.1.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:03e9810d18c646077e501f661b682fbf5dee4676048527ca3cffe66faa9960dd", size = 205543, upload-time = "2026-07-06T21:32:15.148Z" }, { url = "https://files.pythonhosted.org/packages/45/ca/f91641185cdd90c36d317a9dc7f85e88ef8682d8b300977baff5e23c35d8/cffi-2.1.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:19c54ac121cad98450b4896fa9a43ee0180d57bc4bc911a33db6cab1efab6cd3", size = 205460, upload-time = "2026-07-06T21:32:16.479Z" }, { url = "https://files.pythonhosted.org/packages/38/66/04781a77b411f0bb5b234d62c1814754ab75ebe455ccff1b08e8d7aae98f/cffi-2.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d433a51f1870e43a13b6732f92aaf540ff77c2015097c78556f75a2d6c030e0", size = 218760, upload-time = "2026-07-06T21:32:17.98Z" }, { url = "https://files.pythonhosted.org/packages/d0/9a/bb1d5ed9c3fcae158e9f6391bf309c95d98c2ac37ed56573228471d0af5e/cffi-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d7f118b5adbfdfead90c25822690b02bc8074fba949bb7858bec4ebd55adb43", size = 221230, upload-time = "2026-07-06T21:32:19.407Z" }, { url = "https://files.pythonhosted.org/packages/41/aa/3c1409cdd26094efacd1c36c66e0a6eb9d4296e4fd4f9901b8b2042f4323/cffi-2.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5f5df567f6eb216de69be06ce55c8b714090fae02b18a3b40da8163b8c5fa9c", size = 213524, upload-time = "2026-07-06T21:32:20.828Z" }, { url = "https://files.pythonhosted.org/packages/fa/75/74dfb7c3fc6ebbd408038476bd4c1d7e925c62614e7b9c534ecc34218288/cffi-2.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:11b3fb55f4f8ad92274ed26705f65d8f91457de71f5380061eb6d125a768fecd", size = 220341, upload-time = "2026-07-06T21:32:21.9Z" }, { url = "https://files.pythonhosted.org/packages/70/b6/9003c33a3e7d2c1306f5962e646457dcfe5a8cd8fce6bbe02d7af25db783/cffi-2.1.0-cp310-cp310-win32.whl", hash = "sha256:9d72af0cf10a76a600a9690078fe31c63b9588c8e86bf9fd353f713c84b5db0f", size = 174578, upload-time = "2026-07-06T21:32:23.073Z" }, { url = "https://files.pythonhosted.org/packages/8a/26/710688310447531c7a22f857c7f79d9855ec18b03e04494ced723fb37e2f/cffi-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb62edb5bb52cca65fab91a63afa7561607120d26090a7e8fda6fb9f064726da", size = 185071, upload-time = "2026-07-06T21:32:24.671Z" }, { url = "https://files.pythonhosted.org/packages/d3/67/85c89a59ba36a671e79638f44d466749f08179266a57e4f2ffdf92174072/cffi-2.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:02cb7ff33ded4f1532476731f89ede53e2e488a8e6205515a82144246ffa7dcc", size = 183845, upload-time = "2026-07-06T21:32:26.32Z" }, { url = "https://files.pythonhosted.org/packages/ea/dd/e3b0baa2d3d6a857ac72b7efbf18e32e487c9cdafcc13049ad765495b15e/cffi-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f5bce581e6b8c235e566a14768a943b172ada3ed73537bb0c0be1edee312d4e7", size = 184186, upload-time = "2026-07-06T21:32:28.025Z" }, { url = "https://files.pythonhosted.org/packages/65/68/9f3ef890cf3c6ab97bd531c5677f67613d302165d16f8142b2811782a614/cffi-2.1.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:30b65779d598c370374fefabf138d456fd6f3216bfa7bedfab1ba82025b0cd93", size = 211892, upload-time = "2026-07-06T21:32:29.565Z" }, { url = "https://files.pythonhosted.org/packages/22/d7/1a74539db16d8bfd839ff1515948948efbb162e574650fd3d846896eea95/cffi-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88023dfe18799507b73f1dbb0d14326a17465de1bc9c9c7655c22845e9ddc3a2", size = 218793, upload-time = "2026-07-06T21:32:30.951Z" }, { url = "https://files.pythonhosted.org/packages/ec/d1/9a5b7169499e8e8d8e636de70b97ac7c9447104d2ff1a2cd94790cea5162/cffi-2.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0a96b74cda968eebbad56d973efe5098974f0a9fb323865bf99ea1fd24e3e64c", size = 205737, upload-time = "2026-07-06T21:32:32.216Z" }, { url = "https://files.pythonhosted.org/packages/ba/b0/e131a9c41f10607926278453d9596163594fe1c4ebc46efe3b5e5b34eb84/cffi-2.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a5781494d4d400a3f47f8f1da94b324f6e6b440a53387774002890a2a2f4b50f", size = 204909, upload-time = "2026-07-06T21:32:33.655Z" }, { url = "https://files.pythonhosted.org/packages/fb/d2/4398416cd699b35167947c6e22aca52c47e69ad5695073c9f1f2c52e04aa/cffi-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aa7a1b53a2a4452ada2d1b5dade9960b2522f1e61293a811a077439e39029565", size = 217883, upload-time = "2026-07-06T21:32:35.173Z" }, { url = "https://files.pythonhosted.org/packages/a2/a5/d4fe77b589e5e82d43ebc809bf2e6474afe8e48e32ea050b9357645b6471/cffi-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d8272c0e483b024e1b9ad029821470ed8ec65631dbd90217469da0e7cd89f1c", size = 221251, upload-time = "2026-07-06T21:32:36.527Z" }, { url = "https://files.pythonhosted.org/packages/22/f0/a2fc43084c0433caf7f461bccc013e28f848d04ee1c5ed7fce71423cf4d9/cffi-2.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7762faa47e8ff7eb80bd261d9a7d8eea2d8baa69de5e95b70c1f338bbe712f02", size = 214250, upload-time = "2026-07-06T21:32:37.852Z" }, { url = "https://files.pythonhosted.org/packages/04/8c/b925975448cf20634a9fbd5efceb807219db452653648d2897c0989cab2d/cffi-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89095c1968b4ba8285840e131bf2891b09ae137fe2146905acae0354fbce1b5e", size = 219441, upload-time = "2026-07-06T21:32:39.146Z" }, { url = "https://files.pythonhosted.org/packages/eb/da/5c4918a2d61d86fa927d716cb3d8e4626ef8dc8f605a599d32f33897f59a/cffi-2.1.0-cp311-cp311-win32.whl", hash = "sha256:64c753a0f87a256020004f37a1c8c02c480e725f910f0b2a0f3f07debd1b2479", size = 174496, upload-time = "2026-07-06T21:32:40.467Z" }, { url = "https://files.pythonhosted.org/packages/f9/c8/6c2de1d55cf35ef8b92885d5ef280790f0fb9634d87ea1cc315176aecd61/cffi-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:4f26194e3d95e06501b942642855aed4f953d55e95d7d01b7c4483db3ecff458", size = 185113, upload-time = "2026-07-06T21:32:41.761Z" }, { url = "https://files.pythonhosted.org/packages/9e/4e/e8d7cb5783f1841a3c8fb3a7735838d7484d08ec08c9f984b14cac1ac0e9/cffi-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:35aaea0c7ee0e58a5cd8c2fd1a48fdf7ece0d2699b7ecdda08194e9ce5dd9b3d", size = 179927, upload-time = "2026-07-06T21:32:42.961Z" }, { url = "https://files.pythonhosted.org/packages/1e/85/990925db5df586ec90beb97529c853497e7f85ba0234830447faf41c3057/cffi-2.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:df2b82571a1b30f58a87bf4e5a9e78d2b1eff6c6ce8fd3aa3757221f93f0863f", size = 184829, upload-time = "2026-07-06T21:32:44.324Z" }, { url = "https://files.pythonhosted.org/packages/4b/92/e7bb136ad6b5352603732cf907ef862ca103f20f2031c1735a46300c20c9/cffi-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78474632761faa0fb96f30b1c928c84ebcf68713cbb80d15bab09dfe61640fde", size = 184728, upload-time = "2026-07-06T21:32:45.683Z" }, { url = "https://files.pythonhosted.org/packages/c3/c0/d1ec30ffb370f748f2fb54425972bfef9871e0132e82fb589c46b6676049/cffi-2.1.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5972433ad71a9e46516584ef60a0fda12d9dc459938d1539c3ddecf9bdc1368d", size = 214815, upload-time = "2026-07-06T21:32:48.557Z" }, { url = "https://files.pythonhosted.org/packages/1b/dc/5620cf930688be01f2d673804291de757a934c90b946dbdc3d84130c2ea4/cffi-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b6422532152adf4e59b110cb2808cee7a033800952f5c036b4af047ee43199e7", size = 222429, upload-time = "2026-07-06T21:32:49.848Z" }, { url = "https://files.pythonhosted.org/packages/4b/a4/77b53abbf7a1e0beb9637edbef2a94d15f9c822f591e85d439ffd91519a6/cffi-2.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:46b1c8db8f6122420f32d02fffb924c2fe9bc772d228c7c711748fff56aabb2b", size = 210315, upload-time = "2026-07-06T21:32:51.221Z" }, { url = "https://files.pythonhosted.org/packages/58/0c/f528df19cc94b675087324d4760d9e6d5bfae97d6217aa4fac43de4f5fcc/cffi-2.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9fafc5aa2e2a39aaf7f8cc0c1f044a9b07fca12e558dca53a3cc5c654ad67a7", size = 208859, upload-time = "2026-07-06T21:32:52.512Z" }, { url = "https://files.pythonhosted.org/packages/62/f2/c9522a81c32132799a1972c39f5c5f8b4c8b9f00488a23feaa6c06f07741/cffi-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e9f50d192a3e525b15a75ab5114e442d83d657b7ec29182a991bc9a88fd3a66", size = 221844, upload-time = "2026-07-06T21:32:53.704Z" }, { url = "https://files.pythonhosted.org/packages/6e/28/bd53988b9833e8f8ad539d26f4c07a6b3f6bcb1e9e02e7ca038250b3428d/cffi-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98fff996e983a36d3aa2eca83af40c5821202e7e6f32d13ae94e3d2286f10cfe", size = 225287, upload-time = "2026-07-06T21:32:54.907Z" }, { url = "https://files.pythonhosted.org/packages/79/99/0d0fd37f055224085f42bbb2c022d002e17dde4a97972822327b07d84101/cffi-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:379de10ce1ba048b1448599d1b37b24caee16309d1ac98d3982fc997f768700b", size = 223681, upload-time = "2026-07-06T21:32:56.329Z" }, { url = "https://files.pythonhosted.org/packages/b0/80/c138990aa2a70b1a269f6e06348729836d733d6f970867943f61d367f8cc/cffi-2.1.0-cp312-cp312-win32.whl", hash = "sha256:9b8f0f26ca4e7513c534d351eca551947d053fac438f2a04ac96d882909b0d3a", size = 175269, upload-time = "2026-07-06T21:32:57.777Z" }, { url = "https://files.pythonhosted.org/packages/a8/eb/f636456ff21a83fc13c032b58cc5dde061691546ac79efa284b2989b7982/cffi-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:c97f080ea627e2863524c5af3836e2270b5f5dfff1f104392b959f8df0c5d384", size = 185881, upload-time = "2026-07-06T21:32:59.253Z" }, { url = "https://files.pythonhosted.org/packages/dd/2c/400ea43e721727dca8a65c4521390e9196757caba4a45643acb2b63271b8/cffi-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:6d194185eabd279f1c05ebe3504265ddfc5ad2b58d0714f7db9f01da592e9eb6", size = 180088, upload-time = "2026-07-06T21:33:02.278Z" }, { url = "https://files.pythonhosted.org/packages/96/88/a996879e2eeccb815f6e3a5967b12a308257412acec882039d386bd2aa7b/cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:10537b1df4967ca26d21e5072d7d54188354483b91dc75058968d3f0cf13fbda", size = 194331, upload-time = "2026-07-06T21:33:03.697Z" }, { url = "https://files.pythonhosted.org/packages/58/85/7ae00d5c8dd6266f4e944c3db630f3c5c9a98b61d469c714d848b1d8138a/cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a95b05f9baf29b91171b3a8bd2020b028835243e7b0ff6bb23e2a3c228518b1b", size = 196966, upload-time = "2026-07-06T21:33:05.353Z" }, { url = "https://files.pythonhosted.org/packages/8c/e9/45c3a76ad8d43ad9261f4c95436da61128d3ca545d72b9612c0ab5be0b1c/cffi-2.1.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:15faec4adfff450819f3aee0e2e02c812de6edb88203aa58807955db2003472a", size = 184795, upload-time = "2026-07-06T21:33:06.699Z" }, { url = "https://files.pythonhosted.org/packages/84/4c/82f132cb4418ee6d953d982b19191e87e2a6372c8a4ce36e50b69d6ade4a/cffi-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:716ff8ec22f20b4d988b12884086bcef0fc99737043e503f7a3935a6be99b1ea", size = 184746, upload-time = "2026-07-06T21:33:08.071Z" }, { url = "https://files.pythonhosted.org/packages/a0/1c/4ed5a0e5bdca6cbc275556de3328dd1b76fd0c11cc13c88fe66d1d8715f2/cffi-2.1.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:63960549e4f8dc41e31accb97b975abaecfc44c03e396c093a6436763c2ea7db", size = 214747, upload-time = "2026-07-06T21:33:09.671Z" }, { url = "https://files.pythonhosted.org/packages/3a/a6/e879bb68cc23a2bc9ba8f4b7d8019f0c2694bad2ab6c4a3701d429439f58/cffi-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff067a8d8d880e7809e4ac88eb009bb848870115317b306666502ccad30b147f", size = 222392, upload-time = "2026-07-06T21:33:10.896Z" }, { url = "https://files.pythonhosted.org/packages/88/f6/01890cfd63c08f8eb96a8319b0443690197d240a8bd6346048cf7bde9190/cffi-2.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:3b926723c13eba9f81d2ef3820d63aeceec3b2d4639906047bf675cb8a7a500d", size = 210285, upload-time = "2026-07-06T21:33:12.251Z" }, { url = "https://files.pythonhosted.org/packages/a6/cf/2b684132056f438567b61e19d690dd31cd0921ace051e0a458be6074369e/cffi-2.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:47ff3a8bfd8cb9da1af7524b965127095055654c177fcfc7578debcb015eecd0", size = 208801, upload-time = "2026-07-06T21:33:13.617Z" }, { url = "https://files.pythonhosted.org/packages/6f/08/f2e7d62c460faae0926f2d6e423694aa409ced3bc1fe2927a0a6e5f05416/cffi-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:799416bae98336e400981ff6e532d67d5c709cfb30afb79865a1315f94b0e224", size = 221808, upload-time = "2026-07-06T21:33:15.466Z" }, { url = "https://files.pythonhosted.org/packages/38/37/04f54b8e63a02f3d908332c9effbf8c366167c6f733ed8a3d4f79b7e2a1e/cffi-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:961be50688f7fba2fa65f63712d3b9b341a22311f5253460ce933f52f0de1c8c", size = 225241, upload-time = "2026-07-06T21:33:16.869Z" }, { url = "https://files.pythonhosted.org/packages/a9/d6/c72eecca433cd3e681c65ed313ab4835d9d4a379704d0f628a6a05f51c2e/cffi-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf5c6cf48238b0eb4c086978c492ad1cbc22373fc5b2d7353b3a598ce6db887a", size = 223588, upload-time = "2026-07-06T21:33:18.239Z" }, { url = "https://files.pythonhosted.org/packages/c6/4b/e706f67279140f92939da3475ad610df18bfd52d50f14953a8e5fede71d5/cffi-2.1.0-cp313-cp313-win32.whl", hash = "sha256:db3eb7d46527159a878ec3460e9d40615bc25ba337d477db681aea6e4f05c5d2", size = 175248, upload-time = "2026-07-06T21:33:19.799Z" }, { url = "https://files.pythonhosted.org/packages/5a/47/59eb7975cb0e4ef0afa764ea945b29a5bb4537a9f771cb7d6c8a5dd74c95/cffi-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:8e74a6135550c4748af665b1b1118b6aab33b1fc6a16f9aff630af107c3b4512", size = 185717, upload-time = "2026-07-06T21:33:21.47Z" }, { url = "https://files.pythonhosted.org/packages/5a/af/34fee85c48f8d94efc8597bc09470c9dd274c145f1c12e0fbc6ab6d38d74/cffi-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:2282cd5e38aa8accd03e99d1256af8411c84cdbee6a89d841b563fdbd1f3e50f", size = 180114, upload-time = "2026-07-06T21:33:22.515Z" }, { url = "https://files.pythonhosted.org/packages/d8/f0/81478e482afa03f6d18dc8f2afb5edc45b3080853b634b5ed91961be0998/cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d2117334c3af3bdcb9a88522b844a2bdb5efdc4f71c6c822df55486ae1c3347a", size = 194142, upload-time = "2026-07-06T21:33:23.657Z" }, { url = "https://files.pythonhosted.org/packages/7d/95/8de304305cd9204974b0ca051b86d307cafca13aa575a0ef1b44d92c0d8c/cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:702c436735fbe99d59ada02a1f65cfc0d31c0ee8b7290912f8fbc5cd1e4b16c3", size = 196819, upload-time = "2026-07-06T21:33:25.007Z" }, { url = "https://files.pythonhosted.org/packages/20/71/7c8372d30e42415602ed9f268f7cfd66f1b855fed881ecd168bcb45dbc0b/cffi-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1ff3456eab0d889592d1936d6125bbfbc7ae4d3354a700f8bd80450a66445d4d", size = 184965, upload-time = "2026-07-06T21:33:26.605Z" }, { url = "https://files.pythonhosted.org/packages/d6/5c/584e626835f0375c928176c04137c96927165cb8733cdb3150ec04e5ee5e/cffi-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c4165821e131d6d4ca444347c2b694e2311bcfa3fe5a861cc72968f28867beac", size = 184952, upload-time = "2026-07-06T21:33:27.823Z" }, { url = "https://files.pythonhosted.org/packages/2e/d2/065fcae1c73979fac8e054462478d0ff8a29c40cdc2ed7ea5676a061df53/cffi-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:276f20fffd7b396e12516ba8edf9509210ac248cbbc5acbc39cd512f9f59ebe6", size = 222353, upload-time = "2026-07-06T21:33:29.178Z" }, { url = "https://files.pythonhosted.org/packages/ed/a5/e8bbb1ce5b3ac2f53ad6a10bde44318a5a8d99d4f4a000d44a6e39aeb3e4/cffi-2.1.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7d5980a3433d4b71a5e120f9dd551403d7824e31e2e67124fe2769c404c06913", size = 210051, upload-time = "2026-07-06T21:33:30.534Z" }, { url = "https://files.pythonhosted.org/packages/28/ed/c127d3ac36e899c965e3361357c3befacd6578c03f40125183e41c3b219e/cffi-2.1.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6ca4919c6e4f89aa99c42510b42cf54596892c00b3f9077f6bdd1505e24b9c8d", size = 208630, upload-time = "2026-07-06T21:33:31.753Z" }, { url = "https://files.pythonhosted.org/packages/cc/d7/97d3136f81db489ec8d1d67748c110d6c994268fd7528014aa9f2b085e4e/cffi-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d53d10f7da99ae46f7373b9150393e9c5eab9b224909982b43832668de4779f5", size = 221593, upload-time = "2026-07-06T21:33:33.044Z" }, { url = "https://files.pythonhosted.org/packages/d3/27/93195977168ee63aed233a1a0993a2178798654d1f4bddcdd321d6fd3b21/cffi-2.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c351efb95e832a853a29361675f33a7ce53de1a109cd73fd47af0712213aa4ce", size = 225146, upload-time = "2026-07-06T21:33:34.224Z" }, { url = "https://files.pythonhosted.org/packages/b3/c1/6dbd291ee2ae5a50a034aa057207081f545923bbf15dad4511e985aafff5/cffi-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7c7a88e2bac086f06d14577332760bdeecc42bdec8ac4077f6260557d9326", size = 223240, upload-time = "2026-07-06T21:33:35.57Z" }, { url = "https://files.pythonhosted.org/packages/0f/6f/ade5ce9863a57992a6ea3d0d10d7e29b8749fc127204b3d493d667b2815f/cffi-2.1.0-cp314-cp314-win32.whl", hash = "sha256:1854b724d00f6654c742097d5387569021be12d3a0f770eae1df8f8acfcc6acd", size = 177723, upload-time = "2026-07-06T21:33:51.626Z" }, { url = "https://files.pythonhosted.org/packages/41/de/92b9eeed4ae4a21d6fd9b2a2c8505cbed573299902ea73981cc13f7ff62c/cffi-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:1b96bfe2c4bd825681b7d311ad6d9b7280a091f43e8f63da5729638083cd3bfb", size = 187937, upload-time = "2026-07-06T21:33:53.403Z" }, { url = "https://files.pythonhosted.org/packages/2e/1a/cc6ae6c2913a03aab8898eee57963cf1035b8df5872ed8b9115fcc7e2be8/cffi-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:7d28dff1db6764108bc30788d85d61c876beff416d9a49cb9dd7c5a9f34f5804", size = 183001, upload-time = "2026-07-06T21:33:54.74Z" }, { url = "https://files.pythonhosted.org/packages/14/f0/134c00ce0779ec86dea2aa1aac69339c2741a8045072676763512363a2ea/cffi-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7ea6b3e2c4250ff1de21c630fe72d0f63eb95c2c32ffbf64a358cf4a8836d714", size = 188538, upload-time = "2026-07-06T21:33:36.792Z" }, { url = "https://files.pythonhosted.org/packages/50/d8/3b86aba791cb610d24e8a3e1b2cd529e71fa15096b04e4d4e360049d4a4c/cffi-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6af371f3767faeffc6ac1ef57cdfd25844403e9d3f476c5537caee499de96376", size = 188230, upload-time = "2026-07-06T21:33:38.011Z" }, { url = "https://files.pythonhosted.org/packages/14/d0/117dcd9209255ad8571fbc8c92ef32593a1d294dcec91ddc4e4db50606f2/cffi-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb4e8997a49aa2c08a3e43c9045d224448b8941d88e7ac163c7d383e560cbf98", size = 223899, upload-time = "2026-07-06T21:33:39.514Z" }, { url = "https://files.pythonhosted.org/packages/b6/3d/f20f8b886b254e3ad10e15cd4186d3aed49f3e6a35ab37aab9f8f25f7c03/cffi-2.1.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf01d8c84cbea96b944c73b22182e6c7c432b3475632b8111dbfdc95ddad6e13", size = 211652, upload-time = "2026-07-06T21:33:40.851Z" }, { url = "https://files.pythonhosted.org/packages/28/3b/fad54de07260b93ddeef4b96d0131d57ea900675df1d410ae1deee52d7a6/cffi-2.1.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:33eb1ad83ebe8f313e0df035c406227d55a79456704a863fad9842136af5ad7d", size = 210755, upload-time = "2026-07-06T21:33:42.183Z" }, { url = "https://files.pythonhosted.org/packages/cc/82/3d5c705acb7abbba9bbd7d79b8e62e0f25b6120eb7ae6ac49f1b721722fe/cffi-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ac0f1a2d0cfa7eea3f2aaf006ab6e70e8feeb16b75d65b7e5939982ca2f11056", size = 223933, upload-time = "2026-07-06T21:33:43.603Z" }, { url = "https://files.pythonhosted.org/packages/6c/d0/47e338384ab6b1004241002fa616301020cea4fc95f283506565d252f276/cffi-2.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c16914df9fb7f500e440e6875fa23ff5e0b31db01fa9c06af98d59a91f0dc2e4", size = 226749, upload-time = "2026-07-06T21:33:45.046Z" }, { url = "https://files.pythonhosted.org/packages/70/25/65bd5b58ea4bfdfc15cde02cb5365f89ef8ab8b2adfb8fe5c4bd4233382f/cffi-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5ecbd0499275d57506d397eebe1981cee87b47fcd9ef5c22cab7ed7644a39a94", size = 225703, upload-time = "2026-07-06T21:33:46.374Z" }, { url = "https://files.pythonhosted.org/packages/dc/78/aa01ac599a8a4322533d45a1f9bc93b338276d2d59dabbe7c6d92a775c81/cffi-2.1.0-cp314-cp314t-win32.whl", hash = "sha256:7d034dcffa09e9a46c93fa3a3be402096cb5354ac6e41ab8e5cc9cd8b642ad76", size = 182857, upload-time = "2026-07-06T21:33:47.696Z" }, { url = "https://files.pythonhosted.org/packages/b9/26/d00496b22de4d4228f32dde94ad996f350c8aad676d63bcca0743c8dea4d/cffi-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0582a58f3051372229ca8e7f5f589f9e5632678208d8636fea3676711fdf7fe5", size = 194065, upload-time = "2026-07-06T21:33:48.953Z" }, { url = "https://files.pythonhosted.org/packages/d5/dd/0c7dbf815a579ff005008a2d815a55d6bb047c349eef536d9dc53d3f0a8d/cffi-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:510aeeeac94811b138077451da1fb18b308a5feab47dd2b603af55804155e1c8", size = 186404, upload-time = "2026-07-06T21:33:50.309Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.9" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd6280cf040f233bd7d3407b743b4b4c74f70e8e1c4199cb112a62c941c0772a", size = 322240, upload-time = "2026-07-07T14:32:36.236Z" }, { url = "https://files.pythonhosted.org/packages/de/d1/b4319dc3229d8272fba305e206fc0a148e2de8d4087917ce62ae6382f359/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa99adc8f081b475a12843953db36831eaf83ec33eb46a90629ca6a5de45a616", size = 216475, upload-time = "2026-07-07T14:32:38.142Z" }, { url = "https://files.pythonhosted.org/packages/80/33/6c99c1b3e6b8bf730e1bc809b9a2608f224145069114c479a2e9e1494346/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c1225416b463483160e4af85d5fc3a9690ccb53fd4b1865a6437825f5ede3209", size = 238670, upload-time = "2026-07-07T14:32:39.658Z" }, { url = "https://files.pythonhosted.org/packages/7f/f4/ffbb83546e1f198ecc70ecd372b65cf2b50f9068b380abd67640f17a8e18/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d10d789dd9bcca1173c95af82c58433122564b7bc39385124be735a35cbe99", size = 233476, upload-time = "2026-07-07T14:32:41.155Z" }, { url = "https://files.pythonhosted.org/packages/e8/5f/b98b8da398637b551e427e7be922bdec19177dc54d6811dcdaa503f23aac/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bb41182d93ea91f60b4bc8fbf4c820c69ef8a12ab2d917f3f1834f1acad07e8", size = 223817, upload-time = "2026-07-07T14:32:42.592Z" }, { url = "https://files.pythonhosted.org/packages/36/31/a276bb2e66243072a3fd06fdcab9cbb61a305b02143d70d2bda21d888fa8/charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:bcf74c1df76758a395bf0af608c04c82257523f55c9868b334f06270d0f2112b", size = 207974, upload-time = "2026-07-07T14:32:44.258Z" }, { url = "https://files.pythonhosted.org/packages/5e/be/7ee4453d7e88dfbc4104ccd34900b9f2c7c17dac22881865fe0e82424a25/charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b5314963fce9b0b12743891de876e724997864ee22aa496f903f426c7e2fa5b2", size = 221655, upload-time = "2026-07-07T14:32:45.64Z" }, { url = "https://files.pythonhosted.org/packages/1d/85/181c652953eb5276d198f375b1dd641047392050098100a3a02d6534f657/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e9701d0049d92c16703a42771b98d560b95248949f23f8cf7b4eddd201814fb9", size = 219229, upload-time = "2026-07-07T14:32:47.376Z" }, { url = "https://files.pythonhosted.org/packages/0c/e7/aaf6da33fc9f4691cda8f7efbc9f69179d3d39ec8a4799baf273ee1d8db0/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:65a7ff3f705e57d392f7261b6d0550fe137c3019477431f1c355e0db0a7d3e15", size = 209704, upload-time = "2026-07-07T14:32:48.855Z" }, { url = "https://files.pythonhosted.org/packages/63/01/f2fb3bd3a73be48b173ee0c6aa8d2497af97d5663a8c4c4b491de4c62f7a/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79580094b00d1789d1f93ea55bc43cb2f611910c72235b7657f3482ddcc1b22d", size = 226243, upload-time = "2026-07-07T14:32:50.239Z" }, { url = "https://files.pythonhosted.org/packages/c4/02/c57a22739fe05246b0b5783b3bfb6afaac4eebb46f3ececdfb2f048f780e/charset_normalizer-3.4.9-cp310-cp310-win32.whl", hash = "sha256:432786d3561e69aeeae6c7e8648964ce0ad05736120135601f87ac26b9c83381", size = 150935, upload-time = "2026-07-07T14:32:51.676Z" }, { url = "https://files.pythonhosted.org/packages/37/8d/ca39a7559a4797505530d084fd3a49a2c959efbbbff146302fb7be4e3b35/charset_normalizer-3.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:8c041122946b7ba21bb32c45b1aa57b1be35527690aeb3c5c234521085632eee", size = 162314, upload-time = "2026-07-07T14:32:53.193Z" }, { url = "https://files.pythonhosted.org/packages/01/da/a44bd7a13d426e69e4894557106cd58669097bfad4a8681123b618fbfc5d/charset_normalizer-3.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:375b83ed0aecfce76c16d198fbc21f3b11b337d68662bea0a995046682a11419", size = 153075, upload-time = "2026-07-07T14:32:54.554Z" }, { url = "https://files.pythonhosted.org/packages/0b/e3/85ec501f206fb049259288c1f3506e53876937fb00edb47009348e66756b/charset_normalizer-3.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e94703ec9684807f20cfb5eed95c70f67f2a8f21ad620146d7b5a13677b93e5", size = 317075, upload-time = "2026-07-07T14:32:56.021Z" }, { url = "https://files.pythonhosted.org/packages/c3/69/2a5385192e67175f7d8bd5ce4f57c24bc956439adeae5c13a99aa28a53d1/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a441ea71902098ffe78c5abe6c494f44160b4af614ed16c3d9a3b1d17fd8ee2", size = 213837, upload-time = "2026-07-07T14:32:57.78Z" }, { url = "https://files.pythonhosted.org/packages/b3/46/03ddc7da576d814fe0a36dd1f0fd3258e95404b4b2e3c026b7923d7e133f/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:304b13570067b2547562e308af560b3963857b1fa90bd6afd978130130fe2d6a", size = 235503, upload-time = "2026-07-07T14:32:59.205Z" }, { url = "https://files.pythonhosted.org/packages/4e/6e/de0229a7ef40f6f9d28a837eebf4ec47bdca5dab4e900c84f22919af636a/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4773092f8019072343a7447203308b176e10199920eb02d6195e81bbb3274c29", size = 229944, upload-time = "2026-07-07T14:33:00.803Z" }, { url = "https://files.pythonhosted.org/packages/a5/34/49b9060e8418b14fb5cba9cf6bfb383111e2538a03a1fb18e66a95aeb3d5/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04ce310cb89c15df659582aee80a0603788732a5e017d5bd5c81158106ce249c", size = 221276, upload-time = "2026-07-07T14:33:02.199Z" }, { url = "https://files.pythonhosted.org/packages/44/95/80282cce0fae9c3061203d723ee87da996aed79679e65d8935050ee7ca1f/charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:c0323c9daef75ef2e5083624b4585018a0c9d5e3b40f607eed81a311270b934b", size = 205260, upload-time = "2026-07-07T14:33:03.698Z" }, { url = "https://files.pythonhosted.org/packages/0c/74/2f62c8821b969ea3bd67cc2e6976834f48ca5d12664d2559ebcd9bcfbed7/charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:871ff67ea1aad4dfd91736464934d56b32dac49f9fbe16cddba36198a7b3a0db", size = 217786, upload-time = "2026-07-07T14:33:05.12Z" }, { url = "https://files.pythonhosted.org/packages/d9/8d/feabb82cb49fcad14515b1d7d1ca4787b0da7fc723a212bf89bc9e0fac52/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:67830fc78e67501f47bb950471b2dcb9b35b140084429318e862895a8e89c993", size = 216798, upload-time = "2026-07-07T14:33:06.629Z" }, { url = "https://files.pythonhosted.org/packages/a5/ff/c946d63bc3786d5b84d960b0f7ab7e25b828486a946b5aa997625bcaf6a6/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3d92613ec25e43b05f042302531ec0f00b8445190e43325880cbd6ab7c2581da", size = 206429, upload-time = "2026-07-07T14:33:08.006Z" }, { url = "https://files.pythonhosted.org/packages/af/ba/5e5007c370702f85d2ef75791fac7943ed41e080364a673b20142e430e3e/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:280081916dc341820640489a66e4696049401ef1cf6dd672f672e70ad915aca3", size = 223066, upload-time = "2026-07-07T14:33:09.783Z" }, { url = "https://files.pythonhosted.org/packages/83/d5/9096aa3cf532dfad237861544eb47a0f20d5adbf1039760fed8eaae935d9/charset_normalizer-3.4.9-cp311-cp311-win32.whl", hash = "sha256:ac351b3b8014eead140e77e9717e2992c6bbe30b63bc3422422eb84865412e3d", size = 150456, upload-time = "2026-07-07T14:33:11.217Z" }, { url = "https://files.pythonhosted.org/packages/ed/a1/e29995109e455dc8eff8d0fac6ae509be39561318a7cfeac5d33ad029213/charset_normalizer-3.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:6366a16e1a25018694d6a5d784d09b046edc9eac40ea2b54065c3052672516a1", size = 161410, upload-time = "2026-07-07T14:33:12.743Z" }, { url = "https://files.pythonhosted.org/packages/4f/8d/1569f4d0032d6ba2a4fe4591c35bf87868c600c41a71eb5c2e1ffa8464c2/charset_normalizer-3.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:1d22856ffbe153a602df38e4a5464f0b748a54002e0d69ac6d2ad0a197cc99ec", size = 152649, upload-time = "2026-07-07T14:33:14.173Z" }, { url = "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0", size = 319300, upload-time = "2026-07-07T14:33:15.666Z" }, { url = "https://files.pythonhosted.org/packages/ec/96/5d9364e3342d69f3a045e1777bc47c85c383e6e9466d561b33fdb419d1f9/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9", size = 215802, upload-time = "2026-07-07T14:33:17.031Z" }, { url = "https://files.pythonhosted.org/packages/4b/4c/5361f9aa7f2cb58d94f2ab831b3d493f69efb1d239654b4744e3c09527cb/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44", size = 237171, upload-time = "2026-07-07T14:33:18.576Z" }, { url = "https://files.pythonhosted.org/packages/50/78/ce342ca4ff30b2eb49fe6d9578df85974f90c67d294113e94efdd9664cbd/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9", size = 233075, upload-time = "2026-07-07T14:33:20.084Z" }, { url = "https://files.pythonhosted.org/packages/01/c4/4fa4c8b3097a11f3c5f09a35b72ed6855fb1d332469504962ab7bafcc702/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd", size = 224256, upload-time = "2026-07-07T14:33:21.747Z" }, { url = "https://files.pythonhosted.org/packages/87/3a/ad914516df7e358a81aae018caa5e0470ba827fa6d763b1d2e87d920a5f6/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84", size = 208784, upload-time = "2026-07-07T14:33:23.313Z" }, { url = "https://files.pythonhosted.org/packages/d7/74/3c12f9755717dfe5c5c87da63f35d765fa0c00382ec26bf23f7fae34f2ba/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b", size = 219928, upload-time = "2026-07-07T14:33:24.814Z" }, { url = "https://files.pythonhosted.org/packages/33/9a/895095b83e7907abd6d3d99aad3a38ad0d9686cc186cb0c94c24320fe63e/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde", size = 218489, upload-time = "2026-07-07T14:33:26.42Z" }, { url = "https://files.pythonhosted.org/packages/a1/34/ef5c05f412f42520d7709b7d3784d19640839eb7366ded1755511585429f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39", size = 210267, upload-time = "2026-07-07T14:33:27.952Z" }, { url = "https://files.pythonhosted.org/packages/83/dc/9b29fa4412b318bf3bfea985c35d67eb55e04b59a7c3f2237168b0e0be6f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62", size = 226030, upload-time = "2026-07-07T14:33:29.397Z" }, { url = "https://files.pythonhosted.org/packages/0e/42/6dbc00b8cd16011691203e33570fa42ed5746599a2e878112d16eab403a3/charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642", size = 151185, upload-time = "2026-07-07T14:33:30.781Z" }, { url = "https://files.pythonhosted.org/packages/80/cc/f920afd1a23c58ccd53c1d36085a71893a4737ff5e66e0371efab6809850/charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0", size = 162557, upload-time = "2026-07-07T14:33:32.176Z" }, { url = "https://files.pythonhosted.org/packages/f0/e6/0386d43a261ff4e4b30c5857af7df877254b46bec7b9d1b74b6bf969a90b/charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2", size = 152665, upload-time = "2026-07-07T14:33:33.711Z" }, { url = "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:440eede837960000d74978f0eba527be106b5b9aee0daf779d395276ed0b0614", size = 317688, upload-time = "2026-07-07T14:33:35.408Z" }, { url = "https://files.pythonhosted.org/packages/d0/39/8ff066c672434225f8d25f8b739f992af250944392173dcc88362681c9bf/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21e764fd1e70b6a3e205a0e46f3051701f98a8cb3fad66eeb80e48bb502f8698", size = 214982, upload-time = "2026-07-07T14:33:36.996Z" }, { url = "https://files.pythonhosted.org/packages/92/8f/3a47a3667c83c2df9483d91644c6c107de3bf8874aa1793da9d3012eb986/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e4fd89cc178bced6ad29cb3e6dd4aa63fa5017c3524dbd0b25998fb64a87cc8b", size = 236460, upload-time = "2026-07-07T14:33:38.536Z" }, { url = "https://files.pythonhosted.org/packages/f1/60/b22cdbee7e4013dab8b0d7647fc6181120fbbbc8f7025c226d15bd5a47fc/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bd47ba7fc3ca94896759ea0109775132d3e7ab921fbf54038e1bab2e46c313c9", size = 232003, upload-time = "2026-07-07T14:33:40.059Z" }, { url = "https://files.pythonhosted.org/packages/ea/f8/72eb13dcabe7257035cea8aefd922caad2f110d252bf9f67c4c2ca763aee/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:84fd18bcc17526fc2b3c1af7d2b9217d32c9c04448c16ec693b9b4f1985c3d33", size = 223149, upload-time = "2026-07-07T14:33:41.631Z" }, { url = "https://files.pythonhosted.org/packages/b0/3e/faee8f9de92b14ee1198e9163252bb15efee7301b31256a3b6d9ebfdd0dd/charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:5b10cd92fc5c498b35a8635df6d5a100207f88b63a4dc1de7ef9a548e1e2cd63", size = 207901, upload-time = "2026-07-07T14:33:43.209Z" }, { url = "https://files.pythonhosted.org/packages/3a/25/45f30093ae27dd7b92a793b61882a38685f993700113ca36e0c9c14965e1/charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4fbdde9dd4a9ce5fd52c2b3a347bb50cc89483ef783f1cb00d408c13f7a96c0", size = 219176, upload-time = "2026-07-07T14:33:44.725Z" }, { url = "https://files.pythonhosted.org/packages/48/18/c8f397329c35e32f6a837e488986f4ae03bd2abebc453b48714991630c2f/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:416c229f77e5ea25b3dfd4b582f8d73d7e43c22320302b9ab128a2d3a0b38efe", size = 217356, upload-time = "2026-07-07T14:33:46.192Z" }, { url = "https://files.pythonhosted.org/packages/86/7e/5ce0bba863470fd1902d5e5843968951bddf38abe4742fc97116ef4598b3/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:75286256590a6320cf106a0d28970d3560aad9ee09aa7b34fb40524792436d35", size = 209614, upload-time = "2026-07-07T14:33:47.705Z" }, { url = "https://files.pythonhosted.org/packages/6c/ef/2473d3c4d869155be4af1191111d59c4d5c4e0173026f7e85b176e23bf65/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69b157c5d3292bcd443faca052f3096f637f1e074b98212a933c074ae23dc3b8", size = 224991, upload-time = "2026-07-07T14:33:49.238Z" }, { url = "https://files.pythonhosted.org/packages/d0/a3/53ddae3db108a088156aa8ddfafd411ebbc1340f48c5573f697b27f69a39/charset_normalizer-3.4.9-cp313-cp313-win32.whl", hash = "sha256:51307f5c71007673a2bf8232ad973483d281e74cb99c8c5a990af1eefa6277d9", size = 150622, upload-time = "2026-07-07T14:33:50.711Z" }, { url = "https://files.pythonhosted.org/packages/e8/ef/6953a77c7cf2c2ff9998e6f575ab3e380119f100223381565a4f94c1f836/charset_normalizer-3.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:fe2c7201c642b7c308f1675355ad7ff7b66acfe3541625efe5a3ad38f29d6115", size = 161947, upload-time = "2026-07-07T14:33:52.197Z" }, { url = "https://files.pythonhosted.org/packages/6e/fb/d560d1d1555debbfe7849d9cac6145c1b537709d79576bf22557ed803b82/charset_normalizer-3.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:611057cc5d5c0afc743ba8be6bd828c17e0aaa8643f9d0a9b9bb7dea80eb8012", size = 152594, upload-time = "2026-07-07T14:33:53.486Z" }, { url = "https://files.pythonhosted.org/packages/7e/8d/496817fa0944239ecae662dd57ea765cfeaec6a735f9f025d4b7b72e7143/charset_normalizer-3.4.9-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:0327fcd59a935777d83410750c50600ee9571af2846f71ce40f25b13da1ef380", size = 317253, upload-time = "2026-07-07T14:33:54.994Z" }, { url = "https://files.pythonhosted.org/packages/2b/f9/ef4a69ea338ad3c0deceea0f5f7d2380ae8b52132b06d652cb0d2cd86706/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a79d9f4d8001473a30c163556b3c3bfebec837495a412dde78b51672f6134f9", size = 215898, upload-time = "2026-07-07T14:33:56.334Z" }, { url = "https://files.pythonhosted.org/packages/8c/e7/5ddfd76fc061eb52de219658a4aa431cbacadf0a0219c8854f00da50d289/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33bdcc2a32c0a0e861f60841a512c8acc658c87c2ac59d89e3a46dacf7d866e4", size = 236718, upload-time = "2026-07-07T14:33:57.9Z" }, { url = "https://files.pythonhosted.org/packages/49/ba/768fa3f36048d81c477a0ce61f813bc1454d80917ccfe550abd9f44f5e24/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f840ed6d8ecba8255df8c42b87fadeda98ddfc6eeec05e2dc66e26d46dd6f58a", size = 232519, upload-time = "2026-07-07T14:33:59.811Z" }, { url = "https://files.pythonhosted.org/packages/f4/c4/b3e049d2aa3766180c78507110543d9d50894cc97f57de543f1be521dcdc/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c25fe15c70c59eb7c5ce8c06a1f3fa1da0ecc5ea1e7a5922c40fd2fa9b0d5046", size = 223143, upload-time = "2026-07-07T14:34:01.517Z" }, { url = "https://files.pythonhosted.org/packages/19/79/55c32d06d76ae4feafe053f061f3e3ab70bcf19f4007797ce8c3efda7830/charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:f7fb7d750cfa0a070d2c24e831fd3481019a60dd317ea2b39acbcebc08b6ed81", size = 206742, upload-time = "2026-07-07T14:34:03.04Z" }, { url = "https://files.pythonhosted.org/packages/10/e0/47c079dd82d217c807479cd59ffd30af56307ea31c108b75758970459ad3/charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1c96a7a18b9690a4d46df09e3e3382406ae3213727cd1019ebade1c4a81917", size = 219191, upload-time = "2026-07-07T14:34:04.657Z" }, { url = "https://files.pythonhosted.org/packages/42/ab/b9bc2e77d6b44a7e46ef62ec5cac1c9a6ba7b9135a5d560f002696ec9995/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a4cfde78a9f2880208d16a93b795726a3017d5977e08d1e162a7a31322479c41", size = 218328, upload-time = "2026-07-07T14:34:06.115Z" }, { url = "https://files.pythonhosted.org/packages/f1/78/c9c71d599f5aa2d42bcdd35cbbd46d7f535351a57e40ff7d8e5a7e219401/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4d6fcde76f94f5cb9e43e9e9a61f16dacefd228cbbf6f1a09bd9b219a92f1a1", size = 207406, upload-time = "2026-07-07T14:34:07.554Z" }, { url = "https://files.pythonhosted.org/packages/f6/39/c914445c321a845097ce4f6ac7de9a18228a77b766272125a1ce00d851eb/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:898f0e9068ca27d37f8e83a5b962821df851532e6c4a7d615c1c033f9da6eedf", size = 225157, upload-time = "2026-07-07T14:34:09.061Z" }, { url = "https://files.pythonhosted.org/packages/9b/f2/c0d4b8508565a36bc5c624e88ed297f5b0b1095011034d7f5b83a69908b5/charset_normalizer-3.4.9-cp314-cp314-win32.whl", hash = "sha256:c1c948747b03be832dceed96ca815cef7360de9aa19d37c730f8e3f6101aca48", size = 151095, upload-time = "2026-07-07T14:34:10.901Z" }, { url = "https://files.pythonhosted.org/packages/49/fd/a1d26144398c67486422a72bf5812cda22cb4ccfcd95a290fb41ceb4b8e2/charset_normalizer-3.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:16b65ea0f2465b6fb52aa22de5eca612aa964ddfec00a912e26f4656cbef890b", size = 162796, upload-time = "2026-07-07T14:34:12.47Z" }, { url = "https://files.pythonhosted.org/packages/20/95/d75e82f8ce9fd323ebf059c16c9aadefb22a1ecde13b7840b35835e4886c/charset_normalizer-3.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:40a126142a56b2dfc0aacbad1de8310cbf60da7656db0e6b16eebd48e3e93519", size = 153334, upload-time = "2026-07-07T14:34:14.044Z" }, { url = "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:609b3ba8fcc0fb5ab7af00719d0fb6ad0cb518e48e7712d12fd68f1327951198", size = 338848, upload-time = "2026-07-07T14:34:15.688Z" }, { url = "https://files.pythonhosted.org/packages/cd/91/7253a32e86b7e1d1239b1b36ba6dd0f021a21107ab33054b53119cc083b9/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51447e9aa2684679af07ca5021c3db526e0284347ebf4ffcec1154c3350cfe32", size = 223022, upload-time = "2026-07-07T14:34:17.248Z" }, { url = "https://files.pythonhosted.org/packages/cb/32/2e64bd2be10e89c61e57ebe6a93fd98ae88eb7ebe414b5121f22c96c69eb/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cc1b0fff8ead343dae06305f954eb8468ba0ec1a97881f42489d198e4ce3c632", size = 241590, upload-time = "2026-07-07T14:34:18.813Z" }, { url = "https://files.pythonhosted.org/packages/3d/ef/d96ec496cfea0c21db43b0ad03891308b02388d054cc902cf0e5a1ad6a88/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa36ec09ef71d158186bc79e359ff5fdd6e7996fe8ab638f00d6b93139ba4fcf", size = 239584, upload-time = "2026-07-07T14:34:20.52Z" }, { url = "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df115d4d83168fdf2cae48ef1ff6d1cb4c466364e30861b37121de0f3bf1b990", size = 230224, upload-time = "2026-07-07T14:34:22.189Z" }, { url = "https://files.pythonhosted.org/packages/52/94/af74dde74a3996bd959c350709bfe50e297823d70a8c1cbd54b838880863/charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f86c6358749bd4fda175388691e3ba8c46e24c5347d0afd20f9b7edfc9faf07d", size = 212667, upload-time = "2026-07-07T14:34:23.857Z" }, { url = "https://files.pythonhosted.org/packages/ee/f0/f1c4fe746c395922961b5916ed1d7d6e7d4c84851d19ed43cc89980ec953/charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:32286a2c8d167e897177b673176c1e3e00d4057caf5d2b64eef9a3666b03018e", size = 227179, upload-time = "2026-07-07T14:34:25.586Z" }, { url = "https://files.pythonhosted.org/packages/e4/56/6c745619ac397e8871e2bcd3cea1eec86b877488f33888b3aef5c3ed506e/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:83aed2c10721ddd90f68140685391b50811a880af20654c59af6b6c66c40513c", size = 225372, upload-time = "2026-07-07T14:34:27.212Z" }, { url = "https://files.pythonhosted.org/packages/78/ad/98aae8630ac71f16711968e38a5acfecce41b778bf2f0312851020f565a8/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cd6c3d4b783c556fa00bf540854e42f135e2f256abd29669fcd0da0f2dec79c2", size = 215222, upload-time = "2026-07-07T14:34:28.774Z" }, { url = "https://files.pythonhosted.org/packages/f7/40/9593d54209765207a7f11073c06494c1721e4ca4a0a426c597679bf7f91e/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ee2f2a527e3c1a6e6411eb4209642e138b544a2d72fe5d0d76daf77b24063534", size = 231958, upload-time = "2026-07-07T14:34:30.345Z" }, { url = "https://files.pythonhosted.org/packages/b1/27/693ee5e8a18191eb38647360c51cd505013e2bd3b366aa43fd5344c21e3c/charset_normalizer-3.4.9-cp314-cp314t-win32.whl", hash = "sha256:0d861473f743244d349b50f850d10eb87aeb22bbdcc8e64f79273c94af5a8226", size = 155580, upload-time = "2026-07-07T14:34:31.884Z" }, { url = "https://files.pythonhosted.org/packages/80/3f/bd97d3d9c613013d07cb7733d299385b41df37f0471310f5a73dc359f0b8/charset_normalizer-3.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:9b8e0f3107e2200b76f6054de99016eac3ee6762713587b36baaa7e4bd2ae177", size = 167620, upload-time = "2026-07-07T14:34:33.438Z" }, { url = "https://files.pythonhosted.org/packages/3d/c6/eee9dca4439b1061f76373f06ea855678cc4a64c1c3c90b50e479edbb8eb/charset_normalizer-3.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:19ac87f93086ce37b86e098888555c4b4bc48102279bae3350098c0ed664b501", size = 158037, upload-time = "2026-07-07T14:34:35.018Z" }, { url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" }, ] [[package]] name = "click" version = "8.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" }, ] [[package]] name = "codecov" version = "2.1.13" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2c/bb/594b26d2c85616be6195a64289c578662678afa4910cef2d3ce8417cf73e/codecov-2.1.13.tar.gz", hash = "sha256:2362b685633caeaf45b9951a9b76ce359cd3581dd515b430c6c3f5dfb4d92a8c", size = 21416, upload-time = "2023-04-17T23:11:39.779Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/af/02/18785edcdf6266cdd6c6dc7635f1cbeefd9a5b4c3bb8aff8bd681e9dd095/codecov-2.1.13-py2.py3-none-any.whl", hash = "sha256:c2ca5e51bba9ebb43644c43d0690148a55086f7f5e6fd36170858fa4206744d5", size = 16512, upload-time = "2023-04-17T23:11:37.344Z" }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] name = "confuse" version = "2.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyyaml" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/45/3ad821336a7953a2322e7e2d062488cfe179748725e5165117151b88a121/confuse-2.2.1.tar.gz", hash = "sha256:8e7600c3261852122eb5f17b24b06ab8e5437b21d6224853c1420c38ac469d3c", size = 52837, upload-time = "2026-07-19T14:56:24.289Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7f/9c/65beb352015e520146b3debc9942cfbd5f6ec5aea7fdcedff2edc23954ab/confuse-2.2.1-py3-none-any.whl", hash = "sha256:0705a61938ae48d20c29fdb641f7dbd79aed5325bb7d0bd2df8a4dacb14de2ad", size = 28005, upload-time = "2026-07-19T14:56:22.94Z" }, ] [[package]] name = "coverage" version = "7.15.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/76/d0/55fe630f4cf94e3fcba868240fad8c8cdd1f764e2a932f8926347e6ec4cd/coverage-7.15.2.tar.gz", hash = "sha256:3df60dc267f0a2ca23cb7a9ab1109c62b9335ffbf519fcfe167157c28c09b81d", size = 927741, upload-time = "2026-07-15T18:56:19.558Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/10/03/060ce69008ac97bbc01b1411b3e55b61f6f015659400b46749b662107831/coverage-7.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b5bd92ff1ec22e535eab0de75fa6db021992791f461a2aceb7822c625a1187d", size = 221284, upload-time = "2026-07-15T18:53:29.52Z" }, { url = "https://files.pythonhosted.org/packages/fc/a3/d936e8b53edd9684100a6aefaf3fcabaa54728fe33324436c8d279c047aa/coverage-7.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:44826758cfe73fcd0e6af5deb4ba6d5417cc1d13df3acb35c93484a11160f846", size = 221799, upload-time = "2026-07-15T18:53:31.708Z" }, { url = "https://files.pythonhosted.org/packages/ae/a3/ca234b06aec7ee28226f11d39a696b4481fe5eddfce8e03bf39979bb8ffb/coverage-7.15.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09f5c6ec5901f667bd97dd140b5b9a2586b10efec66f46fb1e6d8135f8b95bdf", size = 248544, upload-time = "2026-07-15T18:53:33.212Z" }, { url = "https://files.pythonhosted.org/packages/2b/89/dda79527bb7573ba91828b2fb91b3105d87378d6a2749ca0c0924ce0addd/coverage-7.15.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1d16e3a7104ea84f03e614611b3edbf6fb6892554b3ab0fe7fbb3f2b2ef04376", size = 250374, upload-time = "2026-07-15T18:53:34.683Z" }, { url = "https://files.pythonhosted.org/packages/67/c6/c33755a34572f81f49a8c0cdf6b622f35ccb3238b136e1909daf0cdd4319/coverage-7.15.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d46e62cb35d91e6e2589fda6d28074426b0e276422b5d2ebef2c6b11dc60dbfd", size = 252239, upload-time = "2026-07-15T18:53:36.205Z" }, { url = "https://files.pythonhosted.org/packages/b9/6f/dc341741b375be53a5baeee5b4bf0f0e525d38caed428f7932d23bb7bcb1/coverage-7.15.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dfd3db045e95960ae3683059571e597fda7cc610106a8916f77c5839048c1deb", size = 254150, upload-time = "2026-07-15T18:53:37.863Z" }, { url = "https://files.pythonhosted.org/packages/e9/8d/966a18a5b195cb4e77b14c53f5f3dce22b5da05e6de7fafd1e08f2d2067a/coverage-7.15.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:affd532502d34c0472d0cdb181325c89f1d2c44992fef0c17e88e7b1576259a1", size = 249234, upload-time = "2026-07-15T18:53:39.394Z" }, { url = "https://files.pythonhosted.org/packages/c5/8b/8b2e367496ab48484d48e79984fec76cdc1b7cb5d3a00ee799a5602e3ec9/coverage-7.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d17d7512151fedfcc64c1821a8977fc9be0dbf495754669afcab7b57abc98ae9", size = 250276, upload-time = "2026-07-15T18:53:41.027Z" }, { url = "https://files.pythonhosted.org/packages/63/92/1199318a200eb6c8c6ce0192c892c8710ac791abbe0f35099294620bbfda/coverage-7.15.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e26ff680768b8095e8874aabe0e9d3a47a2a9f176a8340d05f8604c56457c23a", size = 248283, upload-time = "2026-07-15T18:53:42.557Z" }, { url = "https://files.pythonhosted.org/packages/56/da/be284a55c5619bda891a89c27dfd59324a2c6a14d755cf6aac6960ceebeb/coverage-7.15.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:7e8f27131dc7cd53de2c137dd207b3720919320b3c20d499dc30aa9ee6173287", size = 252093, upload-time = "2026-07-15T18:53:44.271Z" }, { url = "https://files.pythonhosted.org/packages/d4/53/ee112da833ddd77b73c6d781a98029b45b584b136615b4900ed0569f887e/coverage-7.15.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:728a33676d4c3f0db977990a4bd421dcaa3be3e53b5b6273036fff6666008e89", size = 248552, upload-time = "2026-07-15T18:53:45.7Z" }, { url = "https://files.pythonhosted.org/packages/82/6a/802cfc802e9113494c80bf3f284cd4d72faeb1f24e244f61046af364f2ca/coverage-7.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29c052f7c83ccfcc5c577eaae025d2e4a9bb80daf03c0ac31c996e83b000ce88", size = 249154, upload-time = "2026-07-15T18:53:47.256Z" }, { url = "https://files.pythonhosted.org/packages/2c/65/529808e91d651147edae408fd9e894abc3b8cad7f3e594bbc36719a3e13a/coverage-7.15.2-cp310-cp310-win32.whl", hash = "sha256:1268ac8fb9ddcd783d3948dbabaf80a5d53bfdaa0575e873e2139a692f797443", size = 223334, upload-time = "2026-07-15T18:53:48.768Z" }, { url = "https://files.pythonhosted.org/packages/68/0f/0e1829d7001130876dfbc0b4e1c737ea7c155b809e3e4a98a0aa268e2369/coverage-7.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:9f4432898c4bf2fba0435bbe35dd4437d7264565e5a88a21f5b49d8662a6b629", size = 223959, upload-time = "2026-07-15T18:53:50.429Z" }, { url = "https://files.pythonhosted.org/packages/7d/3a/54536704f507d4573bf9161c4d0dd3dd59b6d85e48c664e901b6844d8e33/coverage-7.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f1ec6f304b156669cfde653b4e9a953f5de87e247ea02ac599bce0ab2744036", size = 221414, upload-time = "2026-07-15T18:53:51.941Z" }, { url = "https://files.pythonhosted.org/packages/b6/d9/8ba925d29743e3577b21e4d8c11a702b76bc93c41e7fdfd1177af63d4b8d/coverage-7.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d3361879d736f469f45723c11ea1a5bbdaf1f6928f0e632c940378b5aa9b660", size = 221913, upload-time = "2026-07-15T18:53:53.682Z" }, { url = "https://files.pythonhosted.org/packages/09/54/a855f3aa0187f2b431ade4e4791b77b56282cfb5d201c83ec26a31b5b36a/coverage-7.15.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c6a98d698f9e2c8008d0370ec7fc452ebfcc530002ae2d0061170d768b992589", size = 252332, upload-time = "2026-07-15T18:53:55.467Z" }, { url = "https://files.pythonhosted.org/packages/8e/d3/13ac97b4370640ba3452fc8559b06cc2f479ce3ba4a0b632a73e44c38a7d/coverage-7.15.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d50dd325e18ec25bfcc10cd7f99b04df1ab9ec76b0918c260e60817ad0643dee", size = 254243, upload-time = "2026-07-15T18:53:57.055Z" }, { url = "https://files.pythonhosted.org/packages/88/83/5eca144942d8d0659d3f55176517f4a59cdc65eefd17146a0770935a3ebd/coverage-7.15.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67d7602480a47bdf5b675635403625553ebaa70d5a62a657c035149fd401cea0", size = 256352, upload-time = "2026-07-15T18:53:58.83Z" }, { url = "https://files.pythonhosted.org/packages/4e/ba/d3db2e01a50fc88cdb4c0f19542bcf6f61489e34dc9aa3538413e2459a38/coverage-7.15.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cee0f89f4767a6057c8fbf168f8135f18be651300496086bd873e3189fed0487", size = 258313, upload-time = "2026-07-15T18:54:00.497Z" }, { url = "https://files.pythonhosted.org/packages/78/b3/aba83416e9177df28e5186d856c19158c59fc0e7e814aaa61a4a2354ad1b/coverage-7.15.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a29ec5305a7335aacee2d799e3422e91e1c8a12474986e2b3b07e315c91be82f", size = 252449, upload-time = "2026-07-15T18:54:02.456Z" }, { url = "https://files.pythonhosted.org/packages/6a/a5/4b00ecac0194431ab451b0f6710f8e2517d04cef60f821b14dec4637d575/coverage-7.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:48ccc6395958eda89093ecdc35644c86f23a8b23a7f4d44958812b721aad67c1", size = 254043, upload-time = "2026-07-15T18:54:04.072Z" }, { url = "https://files.pythonhosted.org/packages/75/b6/cfa209b4313ee7f1b34da47efcd789ea51c024ad35af390e00f5a3c10a2e/coverage-7.15.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:81f382c5a94b434ec1f6da607edb904c76d7212e618cd4d1bc9f97bed4120ef5", size = 252107, upload-time = "2026-07-15T18:54:06.745Z" }, { url = "https://files.pythonhosted.org/packages/36/67/e8cac5a6954038c98d7fe7eb9802afe7ab3ecb637bb7cc00e69b4148b56d/coverage-7.15.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bbc808daf4f5cd567af8075ecc72d21c6dfef9a254709a621a84c217c935ebc0", size = 255873, upload-time = "2026-07-15T18:54:08.48Z" }, { url = "https://files.pythonhosted.org/packages/2c/92/395cca9f330a86c3fe3471d73e2c102116c4c58fdc619dbbc125c6e93a54/coverage-7.15.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a4c46b247b5d4b78f613bd89fea926d32b25c6cc61a50bd1e99ba310348f3dad", size = 251826, upload-time = "2026-07-15T18:54:10.083Z" }, { url = "https://files.pythonhosted.org/packages/51/60/3e91b20295439652424f426b7086ec5bf4fbe3f604c73eda22b986c4fd6b/coverage-7.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:094dd37f3ef7b2da8b068b583d1f4c40f91c65197e16c52a71962d5d537fc5db", size = 252735, upload-time = "2026-07-15T18:54:11.878Z" }, { url = "https://files.pythonhosted.org/packages/a5/eb/8c07839005e5e3c6b3877d3a6e2a80ce766589f31dd2b6882b78d59a7b8c/coverage-7.15.2-cp311-cp311-win32.whl", hash = "sha256:a63b9e190711134d581c4d703df5df09851b1acf99792c7aacbbe9f41f0283c9", size = 223500, upload-time = "2026-07-15T18:54:13.525Z" }, { url = "https://files.pythonhosted.org/packages/2e/98/59d83c257cd59f0fbaf9d9ddb26b744a576760dfd1ae16e516408894a02b/coverage-7.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:8bb9f4b4279187560796a4cdaca3b0a93dd97e48ee667df005f4ed9a97403688", size = 223973, upload-time = "2026-07-15T18:54:15.163Z" }, { url = "https://files.pythonhosted.org/packages/ea/09/2d285c8bef5c4f695d120c1c96dc11715638aa8e134069f210bb6a62a9fe/coverage-7.15.2-cp311-cp311-win_arm64.whl", hash = "sha256:8c726b232659cbd2ae57ade46509eb068c9bd7a06df9fcbff6fe484870006934", size = 223519, upload-time = "2026-07-15T18:54:16.803Z" }, { url = "https://files.pythonhosted.org/packages/6a/50/eb5bf42e531611a9f8d272556b1ed4de503f84a91413584094487cf69f8f/coverage-7.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1adac78e5abc7c5438f7a209c9ca69d06542f0bf481d728b6989ea80b813fdf9", size = 221587, upload-time = "2026-07-15T18:54:18.439Z" }, { url = "https://files.pythonhosted.org/packages/06/d1/da99af464c335d4e023a6efcd7ec30f63b88a43c93745154ab74ffb31cea/coverage-7.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b868acc62aa5de3be7a9d05c2333bf8359ca987e43f9cb30ff8fbda6a024ab73", size = 221943, upload-time = "2026-07-15T18:54:20.062Z" }, { url = "https://files.pythonhosted.org/packages/5b/8a/13c42723d61ca447eafa18732e8141dd6a63f2732e1c7e1502c182dd88d7/coverage-7.15.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6f6966fc30e6f06ca8f98fb0ce51eda6b111b3ee8d066a8b1ec9e77fa06ab55d", size = 253450, upload-time = "2026-07-15T18:54:21.765Z" }, { url = "https://files.pythonhosted.org/packages/d7/29/99021303f98fbdcb63504b4d07bea4cc025b9b2dd907c4f07c85d50a0dab/coverage-7.15.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:68af907f595ab01a78f794932ff3bdf929c316d3000810d38dbc247129e26f8b", size = 256187, upload-time = "2026-07-15T18:54:23.4Z" }, { url = "https://files.pythonhosted.org/packages/f9/a8/fd503715ed6ca9c5d742923aa5209257340b367a867b2ced0c7d4ba8a0b9/coverage-7.15.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:afa29e2eff3d5729267e2cb2fd4ce9d61c952932fb2694e34ccb5d9540c6a296", size = 257301, upload-time = "2026-07-15T18:54:25.183Z" }, { url = "https://files.pythonhosted.org/packages/da/40/3f4b8fb409810036ebc2857d36adc0498c6e957b5df0290c5036b2e143f1/coverage-7.15.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bbf44513ceb1589e31948e20eafbde9deaface90e1a1afa5f5f77b4423d17ce6", size = 259562, upload-time = "2026-07-15T18:54:27.204Z" }, { url = "https://files.pythonhosted.org/packages/0b/8a/9bdffbef47db77cce3d6b02a28f7e919b19f0106c4b080c2c2246040f885/coverage-7.15.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9deddf09eecb717b7f980414b43d90a5b22ff3967d2949ab29cb0aa83d9e9098", size = 253841, upload-time = "2026-07-15T18:54:29.134Z" }, { url = "https://files.pythonhosted.org/packages/1b/1e/9031efde019d31a06646261fce6dfc5c3c74e951e27a71e5c9a424563178/coverage-7.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae901f7e55ba405c84ee1cab3d3e962e4e871e4a2bcb9c90911adbd69b42ac5a", size = 255221, upload-time = "2026-07-15T18:54:31.142Z" }, { url = "https://files.pythonhosted.org/packages/56/db/787acde872389fc84a9ef9d8cd1ccc658e391ab4cb5b28092a714426a394/coverage-7.15.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a0f47002c6eeb7c280228467a4cb0cc15ca2103a8421b986b2d3ec04a0f9bd8b", size = 253366, upload-time = "2026-07-15T18:54:32.886Z" }, { url = "https://files.pythonhosted.org/packages/2f/9b/6f57bc4b93c842eef1695f8cdaf2318e35e7ba54f5ba80d84be213ab7858/coverage-7.15.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1cd7a5beb7af3e864a13b1f0fb26efd3695da43ef0daf71e586adfffaf34d5b2", size = 257434, upload-time = "2026-07-15T18:54:34.7Z" }, { url = "https://files.pythonhosted.org/packages/88/26/b3186a21b2acc83e451118978905c81c7072c3333707804db09a78c096a2/coverage-7.15.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:97a5c5457a9fb1d6c4e06cfb5dc835871fbfb6a6a51addc9e925bdeff5ef7440", size = 252935, upload-time = "2026-07-15T18:54:36.548Z" }, { url = "https://files.pythonhosted.org/packages/20/c2/c9f3376b2e717ea69ed7a6e9a5fcab968fb0b290db6cf4bd9a1fc7541b75/coverage-7.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0901cfe6c13bcd2302da4f83e884555d2a22bda6e4c476f09ef204ba20ca536e", size = 254807, upload-time = "2026-07-15T18:54:38.296Z" }, { url = "https://files.pythonhosted.org/packages/f0/e1/dfc15401f4a8aaeb486e1ba3e9e3c40522a6e38bd0ecf0b3f29cb8082957/coverage-7.15.2-cp312-cp312-win32.whl", hash = "sha256:b171bdd71cb7ff792bf32e376173b0ace7e7963e7e57c58dfc42063a6a7174cd", size = 223641, upload-time = "2026-07-15T18:54:40.103Z" }, { url = "https://files.pythonhosted.org/packages/91/40/81b6d809d320cd366ec5bdf8176575e897dcb8efe7fb4b489ef9e93e4d13/coverage-7.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:582edc45c2040543fef83341be23c43024a3ab3ae0c2d8bc498a06282905ad40", size = 224172, upload-time = "2026-07-15T18:54:41.882Z" }, { url = "https://files.pythonhosted.org/packages/ef/28/9f14ec438149f7de557f45518f09b4a7917b795cc37083aa7db482693f8c/coverage-7.15.2-cp312-cp312-win_arm64.whl", hash = "sha256:a638db90c61cd219aeee65e83a24fdaa57269a741ae0cf773309208ac862cee3", size = 223556, upload-time = "2026-07-15T18:54:43.674Z" }, { url = "https://files.pythonhosted.org/packages/fc/d5/f8c838e6b7282976f7c918884b792df7a0c42c5bba5d99c60ad2d221d56d/coverage-7.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1121caa19159a38b5463eaae4b1e1fde81e525b15ecc5e000cd5b1a108f743a8", size = 221606, upload-time = "2026-07-15T18:54:45.448Z" }, { url = "https://files.pythonhosted.org/packages/bf/37/97c926376364f66298cc44893b89cdf17b8bc406376497c4061ae4b8a8ff/coverage-7.15.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a300c6934e0989c327b9e8a1e110329da4641149f872bbe9f70168be66da76c1", size = 221982, upload-time = "2026-07-15T18:54:47.341Z" }, { url = "https://files.pythonhosted.org/packages/b7/30/a36050a6e83c2135ee0776f452ca3948224befc6d7f26acecc082d0c106a/coverage-7.15.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2617f8799d268fabdeef42a7e89ac3a23e1deee9025427db2df970f99a89a578", size = 252972, upload-time = "2026-07-15T18:54:49.2Z" }, { url = "https://files.pythonhosted.org/packages/31/d3/06b5f1daf95f0f15ab05bd75f26ba5f3c8b33d0bb72f3aaa3cf41d1bad3a/coverage-7.15.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7dc2950a2992cd676d35c20ae63522836deeb034f08874699d14068710af3dc1", size = 255569, upload-time = "2026-07-15T18:54:51.098Z" }, { url = "https://files.pythonhosted.org/packages/81/1c/9afb3f8de2b8d36960391c48559a2e3ff96594b58099f115921549ea8d0d/coverage-7.15.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e36686f7a442185db2400b3df171aac520869faf9deb59df687d28659eda2a6", size = 256806, upload-time = "2026-07-15T18:54:53.145Z" }, { url = "https://files.pythonhosted.org/packages/64/d8/b989f96061a5e32d82fddd1b1b9ff48a7c8f8ae7606f0e80fd9de54b1e33/coverage-7.15.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d29ca7bd67af6e12e74632d65f026eabc1364da5c254494cd914446a28a3ef7", size = 258936, upload-time = "2026-07-15T18:54:55.015Z" }, { url = "https://files.pythonhosted.org/packages/b8/fa/f99771f5110457c7b511c1935ca49ddf288218eaa84322e028b9334146ae/coverage-7.15.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:db9c8438057e5b0f6a22a0af99c0c1d26b57fbbdbd1be5861ddb8f897fcc3a2d", size = 253178, upload-time = "2026-07-15T18:54:57.527Z" }, { url = "https://files.pythonhosted.org/packages/f6/96/c098a6044d119c751ceede7be91035fa8310170ec24a6523aff72f0a5793/coverage-7.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:63022c4c8dec1d0342f05c3ede99842fe3d007689acc45e86f123a1746e4a026", size = 254934, upload-time = "2026-07-15T18:54:59.41Z" }, { url = "https://files.pythonhosted.org/packages/b2/a2/1457b3a7a50c8d77500103b97a046db863e2f59a1cf6d2f814595f349885/coverage-7.15.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6c0be82b4d4aa5b2704e08518e2252f3e3d110164bcca826816801052e48a7aa", size = 252898, upload-time = "2026-07-15T18:55:01.338Z" }, { url = "https://files.pythonhosted.org/packages/6c/0e/76958874c471ecfcdde0d2b2747bb2c61bdbf34a40636f4ce9db9923e643/coverage-7.15.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4510fb9cdf6bb02dfa6af0be4a534b8102d086e22e4a33f8836df663da3d660d", size = 257056, upload-time = "2026-07-15T18:55:03.243Z" }, { url = "https://files.pythonhosted.org/packages/7c/7c/3d7c4e3bf58baa40327dc7edc2272b17cf02299366d52763db1b0ca1556a/coverage-7.15.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:42ec3d989421b174a2ab607c1539f24127ad362757b7f1c0c0d7a2993f7eb37b", size = 252718, upload-time = "2026-07-15T18:55:05.029Z" }, { url = "https://files.pythonhosted.org/packages/c8/b8/1cecffed9ce14fb25be9ba42d37b6bb61485c9a3ddd43cd3dde36b6087d8/coverage-7.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8f91bce78e32343af184c3b7fa28fcf5a9e2641f4b6623d392038f804939188", size = 254490, upload-time = "2026-07-15T18:55:06.889Z" }, { url = "https://files.pythonhosted.org/packages/6c/2c/42984561bc7f4c045dca67516a0c50ee5ef8d84352dbeb5559dc86c4823e/coverage-7.15.2-cp313-cp313-win32.whl", hash = "sha256:434e68d531858205895eb0d74b73d20b84260de426387d53c422a5acda2cf050", size = 223647, upload-time = "2026-07-15T18:55:08.941Z" }, { url = "https://files.pythonhosted.org/packages/41/9f/39c7c9245efc583beddf89a87683574e663ed93637f3afb6cd7b88405676/coverage-7.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:26c3b04a6377fd7c09800921fa934e3a17c0020439cd59df73e73ae1d4b6a78c", size = 224190, upload-time = "2026-07-15T18:55:10.789Z" }, { url = "https://files.pythonhosted.org/packages/c7/de/3a2883cf8a213659280ef4b403059e17a9acaeb7fc7fd4105e1226ff2e6d/coverage-7.15.2-cp313-cp313-win_arm64.whl", hash = "sha256:3ed010aa1b69cda8e827aabfca9866216c980e2dca82ab9a78c5f83689964c8b", size = 223583, upload-time = "2026-07-15T18:55:12.678Z" }, { url = "https://files.pythonhosted.org/packages/81/5f/aed265fd7a3551a394f36dfe41868aee709b7f95db4052205b4ad1563ac3/coverage-7.15.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:40f633c5c5fc783732f6312280122e859538fa24461235597c13d803ea9a108a", size = 221650, upload-time = "2026-07-15T18:55:14.527Z" }, { url = "https://files.pythonhosted.org/packages/6b/2c/222ba12a545189017120f8eddfc1a0bd4616b47d5d4a8d99421edb2fe4c6/coverage-7.15.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:075560438765b7a2ef43bf7aa7758661b53d889df47f062a31bda6c1ade553a2", size = 221988, upload-time = "2026-07-15T18:55:16.674Z" }, { url = "https://files.pythonhosted.org/packages/aa/38/304b5877ab46e6c290b4292cfcf3fe28245f0e5597cad7f6acc91fc7e0a4/coverage-7.15.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:25fd15dd40a0a2c51a500d664ca29053c09c3259d998407bf982b6e114696138", size = 253029, upload-time = "2026-07-15T18:55:18.856Z" }, { url = "https://files.pythonhosted.org/packages/6c/58/821b533b8db9e44cf1d8a97bd525149ced40dde1d0093da02cb78e715244/coverage-7.15.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b9a6367e4aff723e8ee8190836836124284e8fcd4265e307c844010cfa074f3f", size = 255536, upload-time = "2026-07-15T18:55:21.027Z" }, { url = "https://files.pythonhosted.org/packages/f1/f2/7aa06604c389d32ea7f0a6a988359a7eafc3cd3f8e7bc2e88cd2fdf0b877/coverage-7.15.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9854ca62c152874b2060772503535be2e8f53f70b8aaa7686b094888d872f984", size = 256881, upload-time = "2026-07-15T18:55:23.125Z" }, { url = "https://files.pythonhosted.org/packages/a2/4f/1ef342339c7916d0096bc5888cc0f653882cc7bc8f897d5cb89143287c9b/coverage-7.15.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:913b6c56e110da40e035bbd168353bf7aaa2544a5eaccea5d98a4629aac156c7", size = 259196, upload-time = "2026-07-15T18:55:25.099Z" }, { url = "https://files.pythonhosted.org/packages/fe/f4/7ed055d7a9c5ec13b161773a115a5ccc6b0081d568c31fad830806306cc7/coverage-7.15.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aaccad4129d735a8a4d526f26929894c9a4e8ef7034566f210b176749d6906e3", size = 253036, upload-time = "2026-07-15T18:55:27.018Z" }, { url = "https://files.pythonhosted.org/packages/14/79/ea82cca18c242a3a38b6c017da39726aa62dcb64aa635abf79b92009975c/coverage-7.15.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a164b50081fc7357331c4024ef4d17b78ba325f8380d05f5a69599a7e05257ee", size = 254887, upload-time = "2026-07-15T18:55:29.084Z" }, { url = "https://files.pythonhosted.org/packages/a4/ba/a136db3c0d9562b00e10b72540dbf3a33cd3bc5b95060c9308e247494623/coverage-7.15.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bfd341ccf78128e72c094bc70cc25b3ef309c33c7c2c66ba3ed4309549e02de1", size = 252852, upload-time = "2026-07-15T18:55:31.184Z" }, { url = "https://files.pythonhosted.org/packages/17/17/ea334246b16b7d059953fad6fdefa11e33c68efbd3fe37b1098120a1fac2/coverage-7.15.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1473b3ba8e7ee0f076117b1a72c23f579a2b9e2bb742f48a8d86ea27ca93f91a", size = 257128, upload-time = "2026-07-15T18:55:33.163Z" }, { url = "https://files.pythonhosted.org/packages/ed/c3/074fb66d46d607855f710876b117cbda562c5ab08363528e78820449f937/coverage-7.15.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:17c432b5f73ad52ef46fb06019f6fa7c66ce381961cf0f7dfd1d3a4bd3a98145", size = 252668, upload-time = "2026-07-15T18:55:35.063Z" }, { url = "https://files.pythonhosted.org/packages/e1/c1/f620850ada9b36435921c9a3a8057013422b1d964eb4bf37fe138724d192/coverage-7.15.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:77f0ef5011df53a4bd1b35211ab122287f8d9b8d7aa1c4553e5c2deb24b1d446", size = 254325, upload-time = "2026-07-15T18:55:37.125Z" }, { url = "https://files.pythonhosted.org/packages/cc/31/a729ca3689404493af82ef8e6ff70bd88bdda8da89aeef6ca9b387aeb2b4/coverage-7.15.2-cp314-cp314-win32.whl", hash = "sha256:f653e5d7248c1191ec988a85c72edeab46c3ff44f90639a4ed4874ec0be90243", size = 223844, upload-time = "2026-07-15T18:55:39.078Z" }, { url = "https://files.pythonhosted.org/packages/c6/83/5d809dc808fb1698c671f3e372259bb9158e64b7ea526fc6ab7de64de9fe/coverage-7.15.2-cp314-cp314-win_amd64.whl", hash = "sha256:9911f31aad8906abe337c271343485cf20df5e70df5d2f57f9f136e7b55f26bc", size = 224331, upload-time = "2026-07-15T18:55:41.346Z" }, { url = "https://files.pythonhosted.org/packages/16/4e/35e488548e952795829e129995c4174df33bf432b591d1aa42c8d9e4e7ad/coverage-7.15.2-cp314-cp314-win_arm64.whl", hash = "sha256:e38def96ad59853824c97953fdcd2c320a84ba3ce99b417db78af8bb6c3db635", size = 223760, upload-time = "2026-07-15T18:55:43.518Z" }, { url = "https://files.pythonhosted.org/packages/ed/49/dd2c86cd6374038f6e415fb5bfb86db5218553209c081384a020369dee79/coverage-7.15.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:835ec4e20b45f0a7f63ed78f94065aca00de033403df8377bfe8b9c6abc0a7be", size = 222384, upload-time = "2026-07-15T18:55:45.569Z" }, { url = "https://files.pythonhosted.org/packages/d3/74/173ff17a1c0808e5a438f549f6f145d5ac7528f2791310b63523e3200ac7/coverage-7.15.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7466cc7ab6dc0db871d264bf99e8779f0917ee63d40730af0552f71535a6e072", size = 222647, upload-time = "2026-07-15T18:55:47.544Z" }, { url = "https://files.pythonhosted.org/packages/84/f8/b8cba872162356fb44ac79c10309d987206a4461e32072fc29228dad7331/coverage-7.15.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e370c12133095ff18432de8c044962be85a5a96d90c6fcbce8e17e76236d2328", size = 264013, upload-time = "2026-07-15T18:55:49.768Z" }, { url = "https://files.pythonhosted.org/packages/ee/67/a807a7586d0b8cae485308ddd55756f0806c92f8e0b411bacbf23c48edf3/coverage-7.15.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fe41909c9515c3bfdb5f02c4d1f857dba322d9a9a1178069b91eea77889df63a", size = 266135, upload-time = "2026-07-15T18:55:51.941Z" }, { url = "https://files.pythonhosted.org/packages/ce/67/cd78771dc985f7e4ebdcc82b1a96d9a932af9e806f01f2f91a89f4c72e80/coverage-7.15.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6aa28cfb6488e5453b5b762d65f73aa586380f6693a04d58078ce228a29b06c0", size = 268555, upload-time = "2026-07-15T18:55:54.065Z" }, { url = "https://files.pythonhosted.org/packages/18/3e/10134cf81275188c58568f324fc74aedff32c63ca4d5bbc513a91944a6f0/coverage-7.15.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcc0aae933921d03096f53b0b03eeb702129fd406dee59f08d2efacc68681fa5", size = 269674, upload-time = "2026-07-15T18:55:56.066Z" }, { url = "https://files.pythonhosted.org/packages/75/4a/771b77de446cba985dc414bbc5844bd21604da05dbc044286df8318a48a7/coverage-7.15.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7c63387e21ab21f512c69c9756a8c7dadd322c7275edb064064433c9a09c3743", size = 263101, upload-time = "2026-07-15T18:55:58.107Z" }, { url = "https://files.pythonhosted.org/packages/5f/b5/70a7011da15f4071943361183aefa27847f3e3aec4fd335f1cb3d3a622b1/coverage-7.15.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e55510bc98ae943cece9e667a6c0fe94c6a92913720dea34243657a17993d0c", size = 266007, upload-time = "2026-07-15T18:56:00.468Z" }, { url = "https://files.pythonhosted.org/packages/b4/0d/f9547e804ce7ad49646ffeffac26699510efbe6c0f751b66fdc960c4e825/coverage-7.15.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2ff08701be2d1556fc78b326c80a3e8042da09352ecb3819105f8e386c8a3071", size = 263611, upload-time = "2026-07-15T18:56:02.615Z" }, { url = "https://files.pythonhosted.org/packages/ac/59/f576a396659c0efd351f5c1544f67c3560e89c7761cabf7f65e412beeda5/coverage-7.15.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:38c9518b7103826c403a461544e3c2e77151e8676d06eaed85911a97e962584a", size = 267344, upload-time = "2026-07-15T18:56:04.622Z" }, { url = "https://files.pythonhosted.org/packages/7c/5d/c2e4fce3579c0cb635024293f1a32bbe26df101b3e3a69f22243d1352b6c/coverage-7.15.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:dee88b1ed88587abd8c0269a1fc1f4cc77f7750d1dfde2869e2a123af420e67d", size = 262456, upload-time = "2026-07-15T18:56:06.641Z" }, { url = "https://files.pythonhosted.org/packages/bb/dd/956287d69436b66094bc4b57ac2da71e43bfd2a5524e958900b9f582fcf8/coverage-7.15.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fbeeeecea279727f8ac16c8e1133ddfeee793e985c86ae343d6a5ce744eef8c", size = 264771, upload-time = "2026-07-15T18:56:08.795Z" }, { url = "https://files.pythonhosted.org/packages/2c/5a/6f979530c2734c575de77cf58f5f28d51f7123a94b5030fd9156fe5f363c/coverage-7.15.2-cp314-cp314t-win32.whl", hash = "sha256:cb0fddaa6884be6aae36ced9544b5e90f7d5f03845a2853bf47a14953a4e8688", size = 224151, upload-time = "2026-07-15T18:56:10.856Z" }, { url = "https://files.pythonhosted.org/packages/54/7e/27f6b2a74d484742f4017553e710b01e396b23d809df3e95ca0bb9a2824b/coverage-7.15.2-cp314-cp314t-win_amd64.whl", hash = "sha256:77f091ea3a9cc611cd29f433565476bc1936c084ac8eee00ea0e7e70c27e4199", size = 224981, upload-time = "2026-07-15T18:56:12.928Z" }, { url = "https://files.pythonhosted.org/packages/b1/48/284863423aa474240f6842bd00d680da22f4e6ea2e466618ef7c9c9e69a9/coverage-7.15.2-cp314-cp314t-win_arm64.whl", hash = "sha256:6fc448c377d6eeb00a47c673494bd9bae29280ca53987e1869e67ebedfe20658", size = 224294, upload-time = "2026-07-15T18:56:15.156Z" }, { url = "https://files.pythonhosted.org/packages/ec/82/32e3bd191d498e64f6f911ad55d14006a0861e54869d2d32452326399e65/coverage-7.15.2-py3-none-any.whl", hash = "sha256:eb6bcae8d1a9d305351ecb108232441d11c5cfe9de840a04388ba5d2db8d735c", size = 213375, upload-time = "2026-07-15T18:56:17.305Z" }, ] [package.optional-dependencies] toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] [[package]] name = "dbus-python" version = "1.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ff/24/63118050c7dd7be04b1ccd60eab53fef00abe844442e1b6dec92dae505d6/dbus-python-1.4.0.tar.gz", hash = "sha256:991666e498f60dbf3e49b8b7678f5559b8a65034fdf61aae62cdecdb7d89c770", size = 232490, upload-time = "2025-03-13T19:57:54.212Z" } [[package]] name = "decorator" version = "5.3.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/60/8b/32f9823da46cde7df2087faa08cd98d01b908f8dcab982cdba9c84e85355/decorator-5.3.1.tar.gz", hash = "sha256:4cbcdd55a6efadb9dbea26b858f4fb3264567b52d69ca0d25b721b553f60ea82", size = 58084, upload-time = "2026-05-18T06:03:28.057Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/05/7f/798705f5296a58ca505d600456748d1be48078eac8a7050d8a98bc9edb89/decorator-5.3.1-py3-none-any.whl", hash = "sha256:f47fe6fdbd2edd623ecfe36875d37aba411624e2670dd395dddae1358689bb3c", size = 10365, upload-time = "2026-05-18T06:03:26.517Z" }, ] [[package]] name = "dict2css" version = "0.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "domdf-python-tools" }, { name = "tinycss2" }, ] sdist = { url = "https://files.pythonhosted.org/packages/83/ae/242596e550f79aa85ab6b5310caadd0b592063dc0c20c397d25707981f65/dict2css-0.6.0.tar.gz", hash = "sha256:143e55cb71c98a88c79f2c41e08a5fa4d875659275756f794e31ccd69936ce88", size = 9268, upload-time = "2026-05-21T08:34:29.598Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f7/68/0fbc6124cdd4f5a92599d18345bd24c67977988d0bb277f3ea284321d836/dict2css-0.6.0-py3-none-any.whl", hash = "sha256:5251f1df1c78ffdf09313657a7f88add0ad219127d9aeb18fb343b052d6bfbbe", size = 11874, upload-time = "2026-05-21T08:34:28.548Z" }, ] [[package]] name = "docstrfmt" version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "black" }, { name = "click" }, { name = "coverage" }, { name = "docutils" }, { name = "docutils-stubs" }, { name = "libcst" }, { name = "platformdirs" }, { name = "roman" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "tabulate" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "types-docutils" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/5b/d5a11792a63c1c136be94672f63fe141699366480686ab096a180a815656/docstrfmt-2.2.0.tar.gz", hash = "sha256:372b850cb557cd2ba99433f7e2497de56ae19386de497eed624334938647db72", size = 43398, upload-time = "2026-06-21T13:44:59.351Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7a/9e/07309bb9bf761388d833fba31df715b14c375919dbeafbe7f981fb8d8b6a/docstrfmt-2.2.0-py3-none-any.whl", hash = "sha256:757055934c48a287c151d155acb755031d8924105fbdca28cbd77499b838647d", size = 42936, upload-time = "2026-06-21T13:44:58.02Z" }, ] [[package]] name = "docutils" version = "0.21.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, ] [[package]] name = "docutils-stubs" version = "0.0.22" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, ] sdist = { url = "https://files.pythonhosted.org/packages/31/fb/3eda037eed8b98d6b2169e4198a8f12a03a461c4d4dc44de1a7790d0f7c7/docutils-stubs-0.0.22.tar.gz", hash = "sha256:1736d9650cfc20cff8c72582806c33a5c642694e2df9e430717e7da7e73efbdf", size = 43699, upload-time = "2022-01-02T11:13:17.499Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/59/85/10507e1011d5370b94567e4b57f93086a2476d1da73caf98dc53aa87004b/docutils_stubs-0.0.22-py3-none-any.whl", hash = "sha256:157807309de24e8c96af9a13afe207410f1fc6e5aab5d974fd6b9191f04de327", size = 87506, upload-time = "2022-01-02T11:13:15.94Z" }, ] [[package]] name = "domdf-python-tools" version = "3.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "natsort" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/36/8b/ab2d8a292bba8fe3135cacc8bfd3576710a14b8f2d0a8cde19130d5c9d21/domdf_python_tools-3.10.0.tar.gz", hash = "sha256:2ae308d2f4f1e9145f5f4ba57f840fbfd1c2983ee26e4824347789649d3ae298", size = 100458, upload-time = "2025-02-12T17:34:05.747Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5b/11/208f72084084d3f6a2ed5ebfdfc846692c3f7ad6dce65e400194924f7eed/domdf_python_tools-3.10.0-py3-none-any.whl", hash = "sha256:5e71c1be71bbcc1f881d690c8984b60e64298ec256903b3147f068bc33090c36", size = 126860, upload-time = "2025-02-12T17:34:04.093Z" }, ] [[package]] name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] [[package]] name = "factory-boy" version = "3.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "faker" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ba/98/75cacae9945f67cfe323829fc2ac451f64517a8a330b572a06a323997065/factory_boy-3.3.3.tar.gz", hash = "sha256:866862d226128dfac7f2b4160287e899daf54f2612778327dd03d0e2cb1e3d03", size = 164146, upload-time = "2025-02-03T09:49:04.433Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/8d/2bc5f5546ff2ccb3f7de06742853483ab75bf74f36a92254702f8baecc79/factory_boy-3.3.3-py2.py3-none-any.whl", hash = "sha256:1c39e3289f7e667c4285433f305f8d506efc2fe9c73aaea4151ebd5cdea394fc", size = 37036, upload-time = "2025-02-03T09:49:01.659Z" }, ] [[package]] name = "faker" version = "40.36.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/d2/026af1e002bbc6df534d1f8262b18ec79a974f928e9290bfbfdfe7c7b2af/faker-40.36.0.tar.gz", hash = "sha256:754048c76c03afa7de83eee8f4bcee3cf668cbb7d995f54a4e9678db7f110308", size = 2025903, upload-time = "2026-07-24T21:11:33.088Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/50/9a/b947ed175ce9a0dcb070ccf3607f0ce8720cfb5ed1a36166a150b2acd5af/faker-40.36.0-py3-none-any.whl", hash = "sha256:82b9497d9cfe017048075bcf969298a74b1b6e39f5e4dad1211085d1133f7b62", size = 2062829, upload-time = "2026-07-24T21:11:31.37Z" }, ] [[package]] name = "filelock" version = "3.32.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c0/80/8232b582c4b318b817cf1274ba74976b07b34d35ef439b3eb948f98645a1/filelock-3.32.0.tar.gz", hash = "sha256:7be2ad23a14607ccc71808e68fe30848aeace7058ace17852f68e2a68e310402", size = 213757, upload-time = "2026-07-21T13:17:42.898Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/06/79/b4c714bef36bc4ec2beeae1e0c124f0223888cd8c6feb1cdc56038116920/filelock-3.32.0-py3-none-any.whl", hash = "sha256:d396bea984af47333ef05e50eae7eff88c84256de6112aea0ec48a233c064fe3", size = 97732, upload-time = "2026-07-21T13:17:41.55Z" }, ] [[package]] name = "filetype" version = "1.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020, upload-time = "2022-11-02T17:34:04.141Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, ] [[package]] name = "flask" version = "3.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "blinker" }, { name = "click" }, { name = "itsdangerous" }, { name = "jinja2" }, { name = "markupsafe" }, { name = "werkzeug" }, ] sdist = { url = "https://files.pythonhosted.org/packages/26/00/35d85dcce6c57fdc871f3867d465d780f302a175ea360f62533f12b27e2b/flask-3.1.3.tar.gz", hash = "sha256:0ef0e52b8a9cd932855379197dd8f94047b359ca0a78695144304cb45f87c9eb", size = 759004, upload-time = "2026-02-19T05:00:57.678Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl", hash = "sha256:f4bcbefc124291925f1a26446da31a5178f9483862233b23c0c96a20701f670c", size = 103424, upload-time = "2026-02-19T05:00:56.027Z" }, ] [[package]] name = "flask-cors" version = "6.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "flask" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, { name = "werkzeug" }, ] sdist = { url = "https://files.pythonhosted.org/packages/47/03/4e464a50860f9adf08b5c1d3479cb8ea1f12af2aa69535c7042c6e628135/flask_cors-6.0.5.tar.gz", hash = "sha256:30c5031552cd59f620ac0c8211dac45b345d3b2df310e7721879e4f46ef9c601", size = 101386, upload-time = "2026-06-08T20:20:17.765Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/49/55/5bb1a2d918e9f02f131e47a59032bae70e48050e986e941511fd737a935c/flask_cors-6.0.5-py3-none-any.whl", hash = "sha256:68fcf75693e961f3af26683b23c4b9a8fb6b64de17d20d0c37b95e8de7ab2ed8", size = 16692, upload-time = "2026-06-08T20:20:16.247Z" }, ] [[package]] name = "h11" version = "0.16.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] [[package]] name = "html5lib" version = "1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, { name = "webencodings" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ac/b6/b55c3f49042f1df3dcd422b7f224f939892ee94f22abcf503a9b7339eaf2/html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f", size = 272215, upload-time = "2020-06-22T23:32:38.834Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6c/dd/a834df6482147d48e225a49515aabc28974ad5a4ca3215c18a882565b028/html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d", size = 112173, upload-time = "2020-06-22T23:32:36.781Z" }, ] [[package]] name = "httpcore2" version = "2.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "h11" }, { name = "truststore" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/a8/20ed1ed79cbc2ecdf5301c0968ab7c85547212e2a7bd126ddd2d986e206e/httpcore2-2.9.1.tar.gz", hash = "sha256:4d8acbf8b306f48c9d6046591fd5ba4037d1b1b1000d140fc2c3eab1e9a0c0e2", size = 67089, upload-time = "2026-07-24T09:21:03.867Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl", hash = "sha256:6182472379e855fe4221246a2bb7ecede403bc61c6798062ae1787d051ccde26", size = 82809, upload-time = "2026-07-24T09:21:01.178Z" }, ] [[package]] name = "httpx2" version = "2.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "httpcore2" }, { name = "idna" }, { name = "truststore" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/14/38128fbafd7e0ed41d874df6c9a653d47c2d111cfe59e2b4ac95161b4abd/httpx2-2.9.1.tar.gz", hash = "sha256:1932a768737e3666291582833da748cc4e563c337cf96706fccc04fa6e58764a", size = 95458, upload-time = "2026-07-24T09:21:04.972Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl", hash = "sha256:1820fe14a9ab1107bfeff39259987429450b070ec0ff38cc87eb0d8c97fdc71a", size = 91191, upload-time = "2026-07-24T09:21:02.6Z" }, ] [[package]] name = "idna" version = "3.18" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, ] [[package]] name = "ifaddr" version = "0.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e8/ac/fb4c578f4a3256561548cd825646680edcadb9440f3f68add95ade1eb791/ifaddr-0.2.0.tar.gz", hash = "sha256:cc0cbfcaabf765d44595825fb96a99bb12c79716b73b44330ea38ee2b0c4aed4", size = 10485, upload-time = "2022-06-15T21:40:27.561Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9c/1f/19ebc343cc71a7ffa78f17018535adc5cbdd87afb31d7c34874680148b32/ifaddr-0.2.0-py3-none-any.whl", hash = "sha256:085e0305cfe6f16ab12d72e2024030f5d52674afad6911bb1eee207177b8a748", size = 12314, upload-time = "2022-06-15T21:40:25.756Z" }, ] [[package]] name = "imagesize" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6c/e6/7bf14eeb8f8b7251141944835abd42eb20a658d89084b7e1f3e5fe394090/imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3", size = 1773045, upload-time = "2026-03-03T14:18:29.941Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5f/53/fb7122b71361a0d121b669dcf3d31244ef75badbbb724af388948de543e2/imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96", size = 9441, upload-time = "2026-03-03T14:18:27.892Z" }, ] [[package]] name = "inflate64" version = "1.0.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3e/f3/41bb2901543abe7aad0b0b0284ae5854bb75f848cf406bf8a046bf525f67/inflate64-1.0.4.tar.gz", hash = "sha256:b398c686960c029777afc0ed281a86f66adb956cfc3fbf6667cc6453f7b407ce", size = 902542, upload-time = "2025-11-28T10:55:52.641Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/d5/5c13cfc7954ed716ae0e5e64c4f54be43f8c145b546472b67803feaa18a4/inflate64-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f1a47837d4322e0684824f91eb635aa6fd1967584140c478b0a1aca7b11740d6", size = 58602, upload-time = "2025-11-28T10:54:21.346Z" }, { url = "https://files.pythonhosted.org/packages/33/57/4d740b677cda81ec6f47c05b502ed15103c8a7d9c3e91ee93352d46fe69c/inflate64-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8600478542e2354d1ee7b5c57c957006cabacd8b787b4046951f487a2216e5c0", size = 35856, upload-time = "2025-11-28T10:54:22.629Z" }, { url = "https://files.pythonhosted.org/packages/17/cd/ec3c058283706a43ab790e8d611a3a787a4f4cc4ae3faeafba6e2e216e36/inflate64-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb2b5a62579d074f38352a3494c3c6ac1a90516b75c5793c39303547f1fea925", size = 36007, upload-time = "2025-11-28T10:54:23.685Z" }, { url = "https://files.pythonhosted.org/packages/24/83/90f7086f8078057a090db43459e478dc45e2d5ce2509f9c6a6a08100efa0/inflate64-1.0.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dcfafc572a642215894af1ec8d05949fa35eb7cb36d053aa97b11eccf1ae579e", size = 95055, upload-time = "2025-11-28T10:54:24.864Z" }, { url = "https://files.pythonhosted.org/packages/95/d3/4f760f095ce8a9494d441b96a8735346141dd24f52fa573c971c0da1c958/inflate64-1.0.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cb93159cb60aee8cab62541aa70e4c460f13359660a27a1a486518bba0153535", size = 96645, upload-time = "2025-11-28T10:54:26.308Z" }, { url = "https://files.pythonhosted.org/packages/8c/2a/78ab2fcb02c13e3c8c93c2d82bf5eec1862b428bc6177dcc76ac4044408d/inflate64-1.0.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:89126ceb4d96e76842f4697017a9a3e750c34e029ddb360b3d8ca79a648d47f6", size = 92933, upload-time = "2025-11-28T10:54:27.563Z" }, { url = "https://files.pythonhosted.org/packages/c5/1b/c9a2d84fc117dddee0749dc1b3ab9ed725bf92e866ef0ede0945a5128ef0/inflate64-1.0.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f70e6692617ec82500b203eefac8765302298ce7e73584fcf995bb9e23184530", size = 95898, upload-time = "2025-11-28T10:54:28.91Z" }, { url = "https://files.pythonhosted.org/packages/bd/85/5879fa47122c7d5b563c6dacbd4a782bd9464405f69d46af01e02d4a3907/inflate64-1.0.4-cp310-cp310-win32.whl", hash = "sha256:d08cdda33341b4f992af60c12dc60e370e9993b80a936c17244a602711eeb727", size = 32940, upload-time = "2025-11-28T10:54:30.385Z" }, { url = "https://files.pythonhosted.org/packages/a3/59/cef1b3505dc33d8cb9d115481923dec1de1372d29ac278622feecf9c03a1/inflate64-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:950dd7fe53474df5f4699b8f099980027e812d55fd82d8e167d599822c3d27d6", size = 35541, upload-time = "2025-11-28T10:54:31.837Z" }, { url = "https://files.pythonhosted.org/packages/72/13/d964fbfceeee6752c36c45645e5e9a9ef0dd70d4ce64e5e7316822e43382/inflate64-1.0.4-cp310-cp310-win_arm64.whl", hash = "sha256:bad20de249d6336793f6267880668dbb286ca5c6e6991795aa6344c817588068", size = 33460, upload-time = "2025-11-28T10:54:32.954Z" }, { url = "https://files.pythonhosted.org/packages/39/e4/2fc07d71cf863ed4167e7d3eb7f89de0341ffe3ed3a62ff6cc4123bdbda6/inflate64-1.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bccda9815b27623e805a34ee3ee4f46c93f0cc7ac621f9834d75f033fd79c27a", size = 58595, upload-time = "2025-11-28T10:54:34.338Z" }, { url = "https://files.pythonhosted.org/packages/53/77/1119bb53e8f4c9c77f2a5e3ab7d8c3e905fcfc9912073962b9b4cbf72118/inflate64-1.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c11e2a3cb9d9b49620c9b0c806dd0c55daec3b6bb665299b770a68f01bfc5432", size = 35854, upload-time = "2025-11-28T10:54:35.796Z" }, { url = "https://files.pythonhosted.org/packages/de/40/8b028a731f6fabbb49069a58f1aa5c3332688b57dcb8726f9e596661ce5b/inflate64-1.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e42def03ace8c58fd50b0df4f40241c45a2314c3876d020cce24acf958323c98", size = 36011, upload-time = "2025-11-28T10:54:37.208Z" }, { url = "https://files.pythonhosted.org/packages/86/a3/5b67ef7fd5e7546d4c2be8a9a869c70d9fd525de1cfb2b4dc4b0855eeee8/inflate64-1.0.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7912927a509ca58d1a445ce4ff6e6e9f276dc1d72687386cdf7103bf590e785c", size = 98112, upload-time = "2025-11-28T10:54:38.616Z" }, { url = "https://files.pythonhosted.org/packages/5b/6e/6443ea6c42f6b244c4e59cb43f16e6b903669f718a96e3f1985acf473dea/inflate64-1.0.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ec40c0383cbd84d845dcb785a48ae76eef43246c923f84fda380fdd5ea653d3c", size = 99549, upload-time = "2025-11-28T10:54:40.167Z" }, { url = "https://files.pythonhosted.org/packages/e3/ce/e98577e0771b857b491a64a3f7495eb507e0752b80093068b69813088df1/inflate64-1.0.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b01539fea372c6078b9707d9121c12cb321e587e193f50e257ce06cf5b15e41", size = 95946, upload-time = "2025-11-28T10:54:41.318Z" }, { url = "https://files.pythonhosted.org/packages/6b/3e/8165ff4051dff08b2cc8448dafd15a697564e84cf40f3ee0dc0df16eed16/inflate64-1.0.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bf4e34e32a37a42e9cf8bd9681f89e3e37b218f97d8b8cc95bd065419bc8db13", size = 98766, upload-time = "2025-11-28T10:54:43.366Z" }, { url = "https://files.pythonhosted.org/packages/79/b8/20cad309ded1d97195c5ad50e341b38ddc2e82f5c44ee7d000c4372c8b56/inflate64-1.0.4-cp311-cp311-win32.whl", hash = "sha256:2725ccc14b138f0ad622d0322b769f177f9edfe016ee9ed3404102935d39e7de", size = 32939, upload-time = "2025-11-28T10:54:44.507Z" }, { url = "https://files.pythonhosted.org/packages/8c/32/be5cac018960157d33d61278377d590d5cc34922222cb0c4dc3284ce6eeb/inflate64-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:7056148548c1f25dcb38251f88c19b4635a5f32af4c7bad00621c85509e3d8c0", size = 35535, upload-time = "2025-11-28T10:54:46.214Z" }, { url = "https://files.pythonhosted.org/packages/13/36/9b130e45299d587f306178d65e950e1c8f60a09db8bb55c7cdce8fdda3b6/inflate64-1.0.4-cp311-cp311-win_arm64.whl", hash = "sha256:2ea7bdcad65e255b4596f84880f6e0c1756d6336d620e302653257defa407742", size = 33457, upload-time = "2025-11-28T10:54:47.258Z" }, { url = "https://files.pythonhosted.org/packages/ed/33/5cfa7468960de1be0833e7e41adf5b7804a0aef2fb46f3679df3876bf3ab/inflate64-1.0.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c8009e4a4918ee6c8cbc49e58fe159464895064cfdf0565fed3f49ca81e45272", size = 58619, upload-time = "2025-11-28T10:54:48.315Z" }, { url = "https://files.pythonhosted.org/packages/cd/0a/583c7c2832da36e986c5758d0afb6f5944599e55c5b798b066a9ef63e581/inflate64-1.0.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0d173a7a0e865bb7d19685c5b1ad2994712b8361b24136d7e94abeff58505647", size = 35865, upload-time = "2025-11-28T10:54:49.389Z" }, { url = "https://files.pythonhosted.org/packages/72/4b/9c6acfbe900e5c8698132244c68036b0455bd2169f46e356c83dc0366f11/inflate64-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8bad992f2d034f5f7e36208e54502d1b0829ce772c898e5dc59109833420148a", size = 36019, upload-time = "2025-11-28T10:54:50.813Z" }, { url = "https://files.pythonhosted.org/packages/7f/66/c0c3d3b4b863aab2c2ce631d219a8eb3b95b78acd5f40d3212f071e693db/inflate64-1.0.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6bfcf806912ced77a21394f7363805ecacd626b79f93cba87d505a48e88ede78", size = 98765, upload-time = "2025-11-28T10:54:52.273Z" }, { url = "https://files.pythonhosted.org/packages/37/00/1a2351a85d36b26c5b2b8cfbb37ad86084c98f592dd7590f8577d8b33993/inflate64-1.0.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62d1aac3aba094ae42e27ce7581b414c90f218248be0953b6aeb11a127225e5d", size = 100594, upload-time = "2025-11-28T10:54:53.684Z" }, { url = "https://files.pythonhosted.org/packages/f7/3e/5d18ff5b86aaaf54117e1bb6ce15cb17163f56035f9c480e609d35f258ab/inflate64-1.0.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8065166f355122484f004225b379d403346bdae69ec624786a9334f025580675", size = 96745, upload-time = "2025-11-28T10:54:55.277Z" }, { url = "https://files.pythonhosted.org/packages/84/ff/306d5d6aca1e04e596d2a504a59ff9a900623a6ec852f38aab99f384562d/inflate64-1.0.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:94a95f32087d223d2e119ff5c7c264109e8d4cb7e421e7a688a899a6fe021b38", size = 99795, upload-time = "2025-11-28T10:54:56.485Z" }, { url = "https://files.pythonhosted.org/packages/cf/ec/d4caa4bf3c9e520c15e900fee5a00fc523953843e14aa378ca1abfb2b4ea/inflate64-1.0.4-cp312-cp312-win32.whl", hash = "sha256:ad4fa490bb7dc2a4640a3adaa2d5950f4a465ba034bbcf184c2103646e58ad97", size = 32956, upload-time = "2025-11-28T10:54:57.642Z" }, { url = "https://files.pythonhosted.org/packages/33/c4/c0de4e9bdf12e449360b710e9ab5b5248804610f382b538773cbd07b72bb/inflate64-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:2c6befdf83d088a6e0d10d0873a9d4bfde2ce00ad7a52c8189cf303306f98030", size = 35577, upload-time = "2025-11-28T10:54:59.14Z" }, { url = "https://files.pythonhosted.org/packages/80/07/03a5ef74ad3869b3c5af3b09216321f5a1a5a45265f7bd6d5abc669c7622/inflate64-1.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:2b263c619469f90a75f29c421c53d31b208ad494a078235a8f6db2bc96583fdc", size = 33465, upload-time = "2025-11-28T10:55:00.568Z" }, { url = "https://files.pythonhosted.org/packages/c2/55/b7de7ae318a4f233f892c4f7c8b7e0e8643abe3fdcc53ed35020a9fe3f47/inflate64-1.0.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3f37540d0e64884a935fd62a7d17e40ab69f05ec63e815483b6513675d01bef", size = 58633, upload-time = "2025-11-28T10:55:01.931Z" }, { url = "https://files.pythonhosted.org/packages/b8/5f/6f89c8524503fd7a9ca2bd91fe60d7291b3f684e9d41edb38ef49e10fc3d/inflate64-1.0.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4d24112180c95d12f279cade9a1e21f8be7f4790c4109c293292edf87d061992", size = 35864, upload-time = "2025-11-28T10:55:03.075Z" }, { url = "https://files.pythonhosted.org/packages/7d/14/9eadd59244b38cf85ccd0ca43d1296c50b3a33aa37be4fb68a1928efa58c/inflate64-1.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5c098dab17821f466fc6e6a3d78fc6e0295bb51458015f03416b1d58d6a8df4f", size = 36019, upload-time = "2025-11-28T10:55:04.126Z" }, { url = "https://files.pythonhosted.org/packages/ca/04/399e82d8f5003dd92c8a0c5c1a9a8ce0919114710a496cbe88848bff3a72/inflate64-1.0.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a984b9287ff0fb596eb058d66a9e94530556afd2b7c054b44f2e0aeeff894e8f", size = 98973, upload-time = "2025-11-28T10:55:05.229Z" }, { url = "https://files.pythonhosted.org/packages/c0/c5/038dc2593bbc4272d87eac8c9f75692267d47f834ced888f6d81995df606/inflate64-1.0.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f62a13d0327631778fa2a47c308ae2b07b2659b7bb8564783259ac65949f8c0c", size = 100777, upload-time = "2025-11-28T10:55:06.41Z" }, { url = "https://files.pythonhosted.org/packages/74/4a/f6d3031dd3578510894a41bfe1ac149228970ce1629a43f20e0c5abbe8d1/inflate64-1.0.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:513201336fb3b0b7e2aee5dbbbe30a9f1b23291738b5ceb80076fc285f2ec2f1", size = 96967, upload-time = "2025-11-28T10:55:07.594Z" }, { url = "https://files.pythonhosted.org/packages/26/ef/7ab3bde4e176609ae0e607a8a9bb38d201885275664a6d574299f5bf7850/inflate64-1.0.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:84ce3a97272ba745fce52b38363855c7201968f6402a794bbade774e64c657b9", size = 99997, upload-time = "2025-11-28T10:55:08.85Z" }, { url = "https://files.pythonhosted.org/packages/39/59/8256b3e802e203c8645e0b32b25e6bd94508ad572593f0cdf8234db3879a/inflate64-1.0.4-cp313-cp313-win32.whl", hash = "sha256:332051a9d7e50579b90a3f555d68f53414b06f636c9ffe82e97c0baae3c8fbcc", size = 32958, upload-time = "2025-11-28T10:55:10.343Z" }, { url = "https://files.pythonhosted.org/packages/e7/4f/5784ee1eb8260f2310e24ef2883f1f494f9332bcfde4ed14ee780372149e/inflate64-1.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:3983f53b590ff7d0ba243f664ce852aca882482f30f7a8eab33e10d769336d0c", size = 35578, upload-time = "2025-11-28T10:55:11.389Z" }, { url = "https://files.pythonhosted.org/packages/39/e8/8d927770ce25dc9764c8104207a80653d65471d0a6a8f9ead350016e4586/inflate64-1.0.4-cp313-cp313-win_arm64.whl", hash = "sha256:118d8286f085e99a14341c76ef9fbffd56619ccc80318a9a204aea3dbfa71470", size = 33465, upload-time = "2025-11-28T10:55:12.824Z" }, { url = "https://files.pythonhosted.org/packages/5b/fb/ec9d10f44f2fc7666ad5d70acae2b8a1941e8e08ccae1fad0820f7796be3/inflate64-1.0.4-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:4f61925b2d4248eac2ebb15350a80aaa0d1f7f1dc770bd5ebbbb3b0db4a6a416", size = 58727, upload-time = "2025-11-28T10:55:13.834Z" }, { url = "https://files.pythonhosted.org/packages/81/80/24ba0d2ee14e07e275e9c5b058e59a8a58f8ef42dd51a78ebbfd7c857ac4/inflate64-1.0.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c1acf18b08b32981a4a11ec5a112b8ad5d7c7a5b15cb5bdbdb5b19201e9aa180", size = 35945, upload-time = "2025-11-28T10:55:15.225Z" }, { url = "https://files.pythonhosted.org/packages/70/b8/073a79716e093db973b8823bdfb02e10fbdf65642dbe1fa3cda24832aeb2/inflate64-1.0.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:abddae8920b2eaef824254e14b8d4ff54afbe6194a1bbe9816584859f0c1244d", size = 36060, upload-time = "2025-11-28T10:55:16.261Z" }, { url = "https://files.pythonhosted.org/packages/4c/f0/87d3c317ed0acd94f5e9b3b1b9e9000228ea2af0cb4618c62cbfc816da34/inflate64-1.0.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b303132cc562a906543a56f35c4e164e3880da6ff041cb4a7b1df9f9d2b4bb69", size = 98995, upload-time = "2025-11-28T10:55:17.405Z" }, { url = "https://files.pythonhosted.org/packages/90/72/0b6035302e9c33f004240a50cb6e2e1fc7bb1f2b415b02d939c551bdd06b/inflate64-1.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f0993214dea0738c557fa56c13cd9083aef0097a201d726c21984ad7f577514", size = 100781, upload-time = "2025-11-28T10:55:18.597Z" }, { url = "https://files.pythonhosted.org/packages/2b/05/5f383c615ec0f01bcbbc699a71da167623e494083ab7ed0df86b4bddf125/inflate64-1.0.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a6baedc3288d7a4ff588951d3a9a97a5391dceed6255ff5b16e42cae7274bfa9", size = 97038, upload-time = "2025-11-28T10:55:20.156Z" }, { url = "https://files.pythonhosted.org/packages/4e/9a/c1482718c717c49c67490c42b4fdced9476e894eaebd52193e488c12e188/inflate64-1.0.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a846ce1f38845b20bef2625af1b512be83416d97824539524c5a34e7a729aec7", size = 100016, upload-time = "2025-11-28T10:55:21.337Z" }, { url = "https://files.pythonhosted.org/packages/b8/7f/700ede7474e72a1c0e2e8fe36624cd0225ca8b2875eca33d64aa2de75f4d/inflate64-1.0.4-cp314-cp314-win32.whl", hash = "sha256:eef87908c780439393d577a155868317f0a275b47b417db9f47d8633ec791745", size = 33691, upload-time = "2025-11-28T10:55:22.515Z" }, { url = "https://files.pythonhosted.org/packages/dd/51/f2972df8cceecc9bf3afa3353d517ffc7125285198c844588e9aaf98f5d0/inflate64-1.0.4-cp314-cp314-win_amd64.whl", hash = "sha256:fb2fdd63ef3933b67af98b3f2ee2f57e7787278041d7ba4821382fedd729b68a", size = 36304, upload-time = "2025-11-28T10:55:24.005Z" }, { url = "https://files.pythonhosted.org/packages/29/77/16200aced67215119fb30ec9a5889b48289ee2fa5ce5137623a9ad41b2c4/inflate64-1.0.4-cp314-cp314-win_arm64.whl", hash = "sha256:2e129669a0243ac7816fd526946ee01c25688fe81623a6d6bc95b3156d80f4fb", size = 34491, upload-time = "2025-11-28T10:55:25.068Z" }, { url = "https://files.pythonhosted.org/packages/c0/79/b466ec7666c40912ea81a305a8a2b75f5998e6cec1d3d75e067d76203731/inflate64-1.0.4-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:b17bf665d948dc4edeea0cd17752415d0cd7240c882b9c7e136ad4cc4321e9d4", size = 59300, upload-time = "2025-11-28T10:55:26.185Z" }, { url = "https://files.pythonhosted.org/packages/c9/ad/16e1168ac80f39894e6cb18b439eec63fec42cbced239aebfe12081b6ec7/inflate64-1.0.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:6751758301936fbb38fa38eb5312e14e27b6a1abf568f83c17557fab2694373d", size = 36258, upload-time = "2025-11-28T10:55:27.295Z" }, { url = "https://files.pythonhosted.org/packages/25/42/c463b42fd8a7947b4445fbaf57c265bb7f3114362fb7aee6884ffd8b5341/inflate64-1.0.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d6a4136752aa2a544301059d8f13780aeb88c34d60770258436a87dacd3fc304", size = 36296, upload-time = "2025-11-28T10:55:28.632Z" }, { url = "https://files.pythonhosted.org/packages/39/f1/cf6121926e405020e9e7bccb78ec7781fbc87500ec67368e7d9e866758be/inflate64-1.0.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:938ebc6b28578bfd365d1a9fdb18b7faab08321babeb2198e8025d07d8dc7fb5", size = 106788, upload-time = "2025-11-28T10:55:29.797Z" }, { url = "https://files.pythonhosted.org/packages/9c/dd/b653f9962497cf4d3520d69272894c37fd76f86a0e04bb3bd9f32827dc2f/inflate64-1.0.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:61f51f80fa6f367288343c1a2cd20a42af454883087064e9274fd2a8c3a5a200", size = 107959, upload-time = "2025-11-28T10:55:31.306Z" }, { url = "https://files.pythonhosted.org/packages/60/ae/65d88109b63611c9b6c29008201107127cf2603d186ab99beec39d85f38e/inflate64-1.0.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:172b51da7bbfa66b33f0a5405e944807b9949e92cf4cd9f983c07af8152766df", size = 104213, upload-time = "2025-11-28T10:55:32.506Z" }, { url = "https://files.pythonhosted.org/packages/f9/94/c17de2f55b9fb1269bca4657f9089efe4ba0f3d4b652f07b34dfc69f69a2/inflate64-1.0.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8ca9a2985afd5a14fb48cd126a67e5944ccb7a0a6bdec58c4f796c8c88a84539", size = 106629, upload-time = "2025-11-28T10:55:33.735Z" }, { url = "https://files.pythonhosted.org/packages/8e/30/8bbc587bb2ad09ab7edf1f9215b2c5faf4fa7ee7c071daefe9ed55e28814/inflate64-1.0.4-cp314-cp314t-win32.whl", hash = "sha256:f8964ceaabea294bc20abc9ef408c6aae978a75c25c83168a76cd87a37c38938", size = 33865, upload-time = "2025-11-28T10:55:35.335Z" }, { url = "https://files.pythonhosted.org/packages/91/87/8bf6f412f93c8b6dc14866a021b83321331fbdd17f6ab902a24dbf88773d/inflate64-1.0.4-cp314-cp314t-win_amd64.whl", hash = "sha256:7d13b04cba65c12d21e65eaa77da9484e265e8e821b26e0761d1455ad3a878d9", size = 36943, upload-time = "2025-11-28T10:55:36.983Z" }, { url = "https://files.pythonhosted.org/packages/7d/85/33447bb3c4e3c0ae7b1fde3aadc52a18b2b0193cfcf4f585977e924c6463/inflate64-1.0.4-cp314-cp314t-win_arm64.whl", hash = "sha256:9ae3ee727235a06dc3cd353ee5761fdd8e3b56ad119c711f61680528972a6ced", size = 34846, upload-time = "2025-11-28T10:55:38.433Z" }, ] [[package]] name = "inflection" version = "0.5.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e1/7e/691d061b7329bc8d54edbf0ec22fbfb2afe61facb681f9aaa9bff7a27d04/inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", size = 15091, upload-time = "2020-08-22T08:16:29.139Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2", size = 9454, upload-time = "2020-08-22T08:16:27.816Z" }, ] [[package]] name = "iniconfig" version = "2.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] [[package]] name = "itsdangerous" version = "2.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, ] [[package]] name = "jellyfish" version = "1.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0b/14/fc5bdb637996df181e5c4fa3b15dcc27d33215e6c41753564ae453bdb40f/jellyfish-1.2.1.tar.gz", hash = "sha256:72d2fda61b23babe862018729be73c8b0dc12e3e6601f36f6e65d905e249f4db", size = 364417, upload-time = "2025-10-11T19:36:37.219Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/3f/b1734e45d4fe1620916616829a87486b26b7455352a23b9939110a26dbde/jellyfish-1.2.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b35d4b5b688f759ffd075190a9850b04671bad14c5b37124eb43e99306ec16ea", size = 325627, upload-time = "2025-10-11T19:34:53.199Z" }, { url = "https://files.pythonhosted.org/packages/c5/a3/eb770060544a553281654aa6b03f379231c1ef677e6b9a62735c4a9b3c69/jellyfish-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b37b76ea338c4a473c34a9b9e1e033a78aafb9040a8c0eea579fc5805d8e4b46", size = 320325, upload-time = "2025-10-11T19:34:54.914Z" }, { url = "https://files.pythonhosted.org/packages/4b/81/461c20d8e60801a4da33c81f970991910db0dc398e7ddfad9a25bf0da764/jellyfish-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:137cfcc26396d0f2e1265ac61f800bb921921ea722a43dd897e58190f767c474", size = 353308, upload-time = "2025-10-11T19:34:56.195Z" }, { url = "https://files.pythonhosted.org/packages/bc/ca/b53c9869d4cc8183f0d09b073459937d8f39df2b02d1ab05b25c6f4cfc14/jellyfish-1.2.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab1bfea271ce4bda09d975080d5465cf5a8b127e7c0ea61ea3f972417a7a2193", size = 362931, upload-time = "2025-10-11T19:34:57.527Z" }, { url = "https://files.pythonhosted.org/packages/b3/5f/a08be31c51249d13b324be4c443acd18e172f9f511b70d63c791209ec9f9/jellyfish-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2348f698f9c1d72023afc8d39939045421a01da9b7e3078e3029227e35f28419", size = 360672, upload-time = "2025-10-11T19:34:58.821Z" }, { url = "https://files.pythonhosted.org/packages/ec/7e/a04b682872295507437f96567cfea5cc71199cbbd8a541c8310b9b48126e/jellyfish-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4072e21ad4036af41bd57b447b1dda64fe60aa679cfa8854ba0a0338152439f1", size = 533943, upload-time = "2025-10-11T19:35:00.839Z" }, { url = "https://files.pythonhosted.org/packages/70/8d/a4f6e6b8fc626e4a42ec190428efe74806290bf7fd9d61a864e68b8a9f74/jellyfish-1.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cf6cd68921f2bacc547ba1cf64ad0e76bc1727f3bab13bba2e5f5869aba038b1", size = 554469, upload-time = "2025-10-11T19:35:02.152Z" }, { url = "https://files.pythonhosted.org/packages/f9/80/66ad92b292e0a8096ebd2c2d6363219cf23df02e90a275b6d3b9df740d29/jellyfish-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:01647c12261bc1f7b102e918e7665497176d87f6fc96271439c8855872bc2606", size = 523928, upload-time = "2025-10-11T19:35:03.47Z" }, { url = "https://files.pythonhosted.org/packages/9f/de/fab776c8c4eb997d147bc6a1374d14e7229f42915ccd3471619e761020f2/jellyfish-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ddf05ea471da2808d77ecfa425d8884124b4754f4d483afa7703b6655530cf5c", size = 209286, upload-time = "2025-10-11T19:35:04.438Z" }, { url = "https://files.pythonhosted.org/packages/f3/95/3257c5483c9a31819aad394db64451b81937f7749aed98b26a51928da2cb/jellyfish-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:e4a210a960f3917da757b0581750b6e0a8db9acef68dafbc1b6e2ae39e847ba8", size = 213572, upload-time = "2025-10-11T19:35:05.605Z" }, { url = "https://files.pythonhosted.org/packages/ee/67/5d5ec4004d92573cbccd33fc84d0ad61e523b29f7b17b062913b183961e1/jellyfish-1.2.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9913789a98ccf49213fbb1dabc597847a0ec33d3b0e151689498f4b38ba9be0f", size = 325488, upload-time = "2025-10-11T19:35:06.87Z" }, { url = "https://files.pythonhosted.org/packages/83/21/6cf3add349cd0002cc586178bd8f1fd006894e5c70f959a8db5507cfe075/jellyfish-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4e36d9000d4f7e1a35689a74ec7749d27a216dfa6c47cac2e5ad3de8a523bd69", size = 320226, upload-time = "2025-10-11T19:35:08.314Z" }, { url = "https://files.pythonhosted.org/packages/1c/ed/b5458b09482913caece2e9f807599318e48490b01c3c3134b636ecd7af8c/jellyfish-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7853d2ed7d6929c029312ec849410f1ea7ae76ce72ad1140fb73f6e8a1e6aa4f", size = 353091, upload-time = "2025-10-11T19:35:09.395Z" }, { url = "https://files.pythonhosted.org/packages/67/be/7e01fda506f3249d3548d35d1203e009a850734297ccfe4039ce76a927dc/jellyfish-1.2.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68080af234256ef943f0add6fc79816b0c643d8df291c17a85c1b6e45bdfbb96", size = 362820, upload-time = "2025-10-11T19:35:11.28Z" }, { url = "https://files.pythonhosted.org/packages/f5/95/39302d0df1e1b7c348c1fe6fda27cc6cd4c0bd0b27d79f34de3981a14e55/jellyfish-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c5acb213aa75a61bcfc176566e20f2503069667e760d83d403b59e115fef0dd", size = 360560, upload-time = "2025-10-11T19:35:12.266Z" }, { url = "https://files.pythonhosted.org/packages/ac/9d/b477787bc032e8b5b1ffd798e1c638ecbd54621967dc5577ccd10b5e9444/jellyfish-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4b28fcefc0c3534277ff0306e6c10672fb050f4784b5f3be7037e80801569fb5", size = 533823, upload-time = "2025-10-11T19:35:13.268Z" }, { url = "https://files.pythonhosted.org/packages/73/7e/c6e389c4fccfc2838b1d3fe21736b5bf9ea1e739287d128a291eb84df158/jellyfish-1.2.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f69aeb08659a6c81d559bbe319075e3417434ae5b3a5e4a758d1c4055a03497a", size = 554439, upload-time = "2025-10-11T19:35:14.595Z" }, { url = "https://files.pythonhosted.org/packages/17/1e/3239b2dfdfb2f1d8795a8d35936c5eadb90475dbbeebacf45e083579d560/jellyfish-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:63770120cc3386dcc13bcc4df508ab281a6b14c3b2c0e33586439a6c40ee122f", size = 523762, upload-time = "2025-10-11T19:35:15.614Z" }, { url = "https://files.pythonhosted.org/packages/2c/05/62f16bec1d2cd74e6944dfb18a8511bd9df9f2d58e041567f909da22ee26/jellyfish-1.2.1-cp311-cp311-win32.whl", hash = "sha256:ecf62d4aad0baa8832ab60f96e7baedbe6558bd292597503d927e9c5bce745d8", size = 208967, upload-time = "2025-10-11T19:35:16.616Z" }, { url = "https://files.pythonhosted.org/packages/87/a4/69b65d9090d297407bc530f2e5b8707aa1caa9484e7281a04da6821f13be/jellyfish-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:bd186c041d9be86c4fa5e2490943ce5d7f05b472f45d7f49426f259f3dd20bc4", size = 213556, upload-time = "2025-10-11T19:35:17.528Z" }, { url = "https://files.pythonhosted.org/packages/9c/52/4112537334f1b21ead968a663f0aeb8a5774f42f9c92ded69bad21db1c5e/jellyfish-1.2.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:32a85b752cb51463face13e2b1797cfa617cd7fb7073f15feaa4020a86a346ce", size = 323225, upload-time = "2025-10-11T19:35:18.555Z" }, { url = "https://files.pythonhosted.org/packages/b2/0d/c54aa2476e5e63673910720b75f3b15e2484687fff9a457a84861f3fa898/jellyfish-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:675ab43840488944899ca87f02d4813c1e32107e56afaba7489705a70214e8aa", size = 317839, upload-time = "2025-10-11T19:35:19.648Z" }, { url = "https://files.pythonhosted.org/packages/51/3f/a81347d705150a69e446cabcbe8f223ad990164dffd3e6f8178ed44cf198/jellyfish-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c888f624d03e55e501bc438906505c79fb307d8da37a6dda18dd1ac2e6d5ea9c", size = 353337, upload-time = "2025-10-11T19:35:20.651Z" }, { url = "https://files.pythonhosted.org/packages/e7/3a/b655e72b852f6c304a2bc12091485f71e58e8c6374a15c8f21a1f0e1b9cd/jellyfish-1.2.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d2b56a1fd2c5126c4a3362ec4470291cdd3c7daa22f583da67e75e30dc425ce6", size = 362632, upload-time = "2025-10-11T19:35:21.624Z" }, { url = "https://files.pythonhosted.org/packages/4e/be/f9f9a0b7ba48c994e0573d718e39bde713572cfb11f967d97328420a7aef/jellyfish-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a3ccff843822e7f3ad6f91662488a3630724c8587976bce114f3c7238e8ffa1", size = 360514, upload-time = "2025-10-11T19:35:22.886Z" }, { url = "https://files.pythonhosted.org/packages/f0/b6/960e556e155f65438c1b70d50f745ceb2989de8255a769ccaad26bf94a3f/jellyfish-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10da696747e2de0336180fd5ba77ef769a7c80f9743123545f7fc0251efbbcec", size = 533973, upload-time = "2025-10-11T19:35:24.077Z" }, { url = "https://files.pythonhosted.org/packages/24/63/f5b5fb00c0df70387f699535c38190a97f30b79c2e7d4afb97794f838875/jellyfish-1.2.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:c3c18f13175a9c90f3abd8805720b0eb3e10eca1d5d4e0cf57722b2a62d62016", size = 553863, upload-time = "2025-10-11T19:35:25.64Z" }, { url = "https://files.pythonhosted.org/packages/86/45/4de6626b6045884ed27995e170bacd09239b19549e25d95492cde10ea052/jellyfish-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0368596e176bf548b3be2979ff33e274fb6d5e13b2cebe85137b8b698b002a85", size = 523629, upload-time = "2025-10-11T19:35:26.732Z" }, { url = "https://files.pythonhosted.org/packages/73/d6/8593e08568438b207f91b2fba2f6c879abc85dc450c0ad599a4e81dd9f07/jellyfish-1.2.1-cp312-cp312-win32.whl", hash = "sha256:451ddf4094e108e33d3b86d7817a7e20a2c5e6812d08c34ee22f6a595f38dcca", size = 209179, upload-time = "2025-10-11T19:35:27.72Z" }, { url = "https://files.pythonhosted.org/packages/0f/ff/ae991a96e8a370f41bbd91dbabdc94b404a164b0ab268388f43c2ab10d45/jellyfish-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:15318c13070fe6d9caeb7e10f9cdf89ff47c9d20f05a9a2c0d3b5cb8062a7033", size = 213630, upload-time = "2025-10-11T19:35:28.978Z" }, { url = "https://files.pythonhosted.org/packages/5c/e6/75feeda1c3634525296aa56265db151f896005b139e177f8b1a285546a1f/jellyfish-1.2.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4b3e3223aaad74e18aacc74775e01815e68af810258ceea6fa6a81b19f384312", size = 322958, upload-time = "2025-10-11T19:35:29.906Z" }, { url = "https://files.pythonhosted.org/packages/0e/66/4b92bb55b545ebefbf085e45cbcda576d2a2a3dc48fd61dae469c27e73a6/jellyfish-1.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e967e67058b78189d2b20a9586c7720a05ec4a580d6a98c796cd5cd2b7b11303", size = 317859, upload-time = "2025-10-11T19:35:31.312Z" }, { url = "https://files.pythonhosted.org/packages/fe/8e/9d0055f921c884605bf22a96e376b016993928126e8a4c7fd8698260fb4e/jellyfish-1.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32581c50b34a09889b2d96796170e53da313a1e7fde32be63c82e50e7e791e3c", size = 353222, upload-time = "2025-10-11T19:35:32.352Z" }, { url = "https://files.pythonhosted.org/packages/4f/d2/deca58a62e57f7e2b2172ab39f522831279ee08ec0943fc0d0e33cd6e6f9/jellyfish-1.2.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07b022412ebece96759006cb015d46b8218d7f896d8b327c6bbee784ddf38ed9", size = 362392, upload-time = "2025-10-11T19:35:33.305Z" }, { url = "https://files.pythonhosted.org/packages/12/40/9a7f62d367f5a862950ce3598188fe0e22e11d1f5d6eaad6eda5adc354b0/jellyfish-1.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a49eb817eaa6591f43a31e5c93d79904de62537f029907ef88c050d781a638", size = 360358, upload-time = "2025-10-11T19:35:34.585Z" }, { url = "https://files.pythonhosted.org/packages/a5/e5/6b44a1058df3dfa3dd1174c9f86685c78f780d0b68851a057075aea14587/jellyfish-1.2.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:e1b990fb15985571616f7f40a12d6fa062897b19fb5359b6dec3cd811d802c24", size = 533945, upload-time = "2025-10-11T19:35:35.764Z" }, { url = "https://files.pythonhosted.org/packages/50/4c/2397f43ad2692a1052299607838b41a4c2dd5707fde4ce459d686e763eb1/jellyfish-1.2.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:dd895cf63fac0a9f11b524fff810d9a6081dcf3c518b34172ac8684eb504dd43", size = 553707, upload-time = "2025-10-11T19:35:36.926Z" }, { url = "https://files.pythonhosted.org/packages/de/aa/dc7cf053c8c40035791de1dc2f45b1f57772a14b0dc53318720e87073831/jellyfish-1.2.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:6d2bac5982d7a08759ea487bfa00149e6aa8a3be7cd43c4ed1be1e3505425c69", size = 523323, upload-time = "2025-10-11T19:35:37.981Z" }, { url = "https://files.pythonhosted.org/packages/2b/1a/610c7f1f7777646322f489b5ed1e4631370c9fa4fb40a8246af71b496b6d/jellyfish-1.2.1-cp313-cp313-win32.whl", hash = "sha256:509355ebedec69a8bf0cc113a6bf9c01820d12fe2eea44f47dfa809faf2d5463", size = 209143, upload-time = "2025-10-11T19:35:39.276Z" }, { url = "https://files.pythonhosted.org/packages/80/9a/6102b23b03a6df779fee76c979c0eb819b300c83b468900df78bb574b944/jellyfish-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:9c747ae5c0fb4bd519f6abbfe4bd704b2f1c63fd4dd3dbb8d8864478974e1571", size = 213466, upload-time = "2025-10-11T19:35:40.24Z" }, { url = "https://files.pythonhosted.org/packages/89/c3/92190ff494881008ff127d67aba80245a5071ec7c3ff1181ceddc6c9d636/jellyfish-1.2.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:212aaf177236192a735bbbf5938717aa8518d14a25b08b015e47e783e70be060", size = 322379, upload-time = "2025-10-11T19:35:41.21Z" }, { url = "https://files.pythonhosted.org/packages/d4/db/993c81f3e95e06e2a5cb71aaf9af063d8798a34c9715c8059707ddc12b86/jellyfish-1.2.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b8986d9768daddd5e87abf513ae168ea0afe690a444d4c82d5b1b14b0d045820", size = 317270, upload-time = "2025-10-11T19:35:43.367Z" }, { url = "https://files.pythonhosted.org/packages/fc/6a/0f521b098e136c43c7ae1e77db4a792f9e65167fe818820502996488b926/jellyfish-1.2.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fa0ba0946f3c274f6a87aaa3c631dc70a363bd46cceea828ce777e8db653b6f", size = 352931, upload-time = "2025-10-11T19:35:44.402Z" }, { url = "https://files.pythonhosted.org/packages/a0/c4/5d2242a650f890384b435610ef2962b1ac6091c070912a81a97020d2502a/jellyfish-1.2.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6e76b23431a667cd485fb562428d1ad29bae9fdd0fcdfb5a51cc8087bae0e88c", size = 362473, upload-time = "2025-10-11T19:35:45.427Z" }, { url = "https://files.pythonhosted.org/packages/d5/fe/831fc45a4d3e497bccc4735809551320968360d14b89eb3d7cb892549316/jellyfish-1.2.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a058f4c6a591d5e5a47569f5648a26303ba19c76a960fef7e0beba2aa959e52e", size = 359772, upload-time = "2025-10-11T19:35:46.65Z" }, { url = "https://files.pythonhosted.org/packages/b4/0f/d132265e299947e4462c1485f829a08a513c97c41bdfe758754e4a5c1dfe/jellyfish-1.2.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:6a49ce2a580edd3b16b69421137deef464e2f8907f9ef906d49950b1a52908c1", size = 533628, upload-time = "2025-10-11T19:35:47.691Z" }, { url = "https://files.pythonhosted.org/packages/52/2a/d51dbf0aceb9b141dd8318ce6a41ab08a5deaae56be16a8bf3d8685ac817/jellyfish-1.2.1-cp314-cp314-musllinux_1_1_i686.whl", hash = "sha256:c85aa2bc76a36d92a3197f406f86636664d5b323727dfec4fa2842a8a24a06ae", size = 553614, upload-time = "2025-10-11T19:35:52.928Z" }, { url = "https://files.pythonhosted.org/packages/f9/e1/fcc7c5919d871537942425f707b764af65b76c7b88377aa71083c5280e37/jellyfish-1.2.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:29cfa8bfb72aacf2d611a3313b358ed4d4140fa3d3efcffea750c8e7f8acb1aa", size = 523057, upload-time = "2025-10-11T19:35:54.423Z" }, { url = "https://files.pythonhosted.org/packages/95/65/ee5289540b2015643493cc29b50350dbe63ca1977a902de5295a4df8c25a/jellyfish-1.2.1-cp314-cp314-win32.whl", hash = "sha256:f121218dc33fb318c34ddd889dc7362606ce1316af2bb63b73cc1df81523ca34", size = 209340, upload-time = "2025-10-11T19:35:55.69Z" }, { url = "https://files.pythonhosted.org/packages/bc/e2/fa5de38380b0f5bd531b27a78acb0dc6118dab0b21f56d36008b829aa7de/jellyfish-1.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:9a73b5c6425a70ebd440579a677eb4f03b327b2f59090db34e6c937aeea5aabd", size = 213399, upload-time = "2025-10-11T19:35:56.776Z" }, { url = "https://files.pythonhosted.org/packages/f5/2b/ef99cc9ed0c14171b62dfb68dca7e1cecec02b4c007ea47709a3d51ffba6/jellyfish-1.2.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c499ea3a134130797c50e367687a6a46a12653c59af381bee92c41a5ab0bd55d", size = 327121, upload-time = "2025-10-11T19:36:09.777Z" }, { url = "https://files.pythonhosted.org/packages/c1/c9/1159831bf5c2356affab834039cb6fce596ea74e39fc77533ea349f1eef2/jellyfish-1.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:91cad49a4fb731b726afc5ae385a3217a7016ed88a04da40c131cff8136a5db5", size = 321825, upload-time = "2025-10-11T19:36:10.887Z" }, { url = "https://files.pythonhosted.org/packages/bf/66/4328b3ecfb79266b261d195b920c78975e9a0ee793c9fe1e08904e924ad6/jellyfish-1.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bda2275f31a64adf3483e39f7a4e2107f7dfe3a3f85f0d2c0cb6ae5fbe4a443", size = 355093, upload-time = "2025-10-11T19:36:11.921Z" }, { url = "https://files.pythonhosted.org/packages/bb/9d/5bbc2ec2e3fd0f93e54642aa1a0772bd909e7bb2755a6a8ad8b7d75e97b8/jellyfish-1.2.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:98a133b40dc00cfda6609e1b0cb0ab0b77796fc2719aae886a12009514f73499", size = 364202, upload-time = "2025-10-11T19:36:12.867Z" }, { url = "https://files.pythonhosted.org/packages/99/88/bec6bd9899194355f8007e376bbf0824ff6bb9dd78754a5e8b095ee00c1c/jellyfish-1.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa30c7b59bd1c5e105693108a6d7a98f3e7a1a59e23e15bc5897b91fd5849f5", size = 362053, upload-time = "2025-10-11T19:36:14.086Z" }, { url = "https://files.pythonhosted.org/packages/6a/15/ca2f05b39145460579b7bfb164d210ce30a68bc1136b74f48bae33e3442b/jellyfish-1.2.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:db97d873f23b0c15b4ed911ece10e5cc0bb96cdc53666d5c3788bd0af81807f1", size = 535693, upload-time = "2025-10-11T19:36:15.205Z" }, { url = "https://files.pythonhosted.org/packages/d1/82/8889c441d768a80eeea575e471d54613ea88c579883a2c30afa04fa0987b/jellyfish-1.2.1-pp310-pypy310_pp73-musllinux_1_1_i686.whl", hash = "sha256:393f609fd6139ce782e747e22c399483ffc58341009e6a97e39ffe5f5b2c674c", size = 555789, upload-time = "2025-10-11T19:36:16.433Z" }, { url = "https://files.pythonhosted.org/packages/af/65/abca7f780fb66840500ab7842c2285de6c09c5130a769fe3712a3a647af9/jellyfish-1.2.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fb3c6e537cb4605c22895a8d4a10cdb26611ba2bbfc7f0b4c1d06bb9d8aad648", size = 525431, upload-time = "2025-10-11T19:36:17.788Z" }, { url = "https://files.pythonhosted.org/packages/96/72/e4897449abd844d501412873d1d15bd846bcc919648c0b1043e225268b21/jellyfish-1.2.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:748dc45a0394fbe9120b8b3b9a39fab0967c7e2d6ecdd5304af018e774f80f96", size = 326967, upload-time = "2025-10-11T19:36:18.851Z" }, { url = "https://files.pythonhosted.org/packages/60/3f/c7a550abd212ae40c2a555055a3f16ba39376e486ba0189e150fb25cf6b1/jellyfish-1.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:13f1ac9caba22af10bfe42f674822643c0266009f882e0fe652079706dc5d13a", size = 321759, upload-time = "2025-10-11T19:36:19.882Z" }, { url = "https://files.pythonhosted.org/packages/19/58/a268365ba659f04d4db0c94325042aa9aee69c3a9a5823a5b2a2db308a5c/jellyfish-1.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ffeeb6c78c45fbb6d2a22b0173fb8a6af849001d6c26fab49c525136dbd9734", size = 354847, upload-time = "2025-10-11T19:36:20.976Z" }, { url = "https://files.pythonhosted.org/packages/5d/63/371351a5e0e19d642e33c1c8b4c3ef47538f36bbd8d76a06ee34000b38a2/jellyfish-1.2.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1354b558a0a16597b6032dd0af64bebd24994f7e7484cf14993320eb764b06cb", size = 364210, upload-time = "2025-10-11T19:36:22.071Z" }, { url = "https://files.pythonhosted.org/packages/a8/ed/f43d79b9b6d846189b1235f8303d1246ca9cba79a61a26cac790b57c1789/jellyfish-1.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5977810972c6f0b2e61252c4758fd5aee21abf663ff309881195a99d37daa94", size = 361876, upload-time = "2025-10-11T19:36:23.235Z" }, { url = "https://files.pythonhosted.org/packages/74/5c/82455195b77cd1996c3618bd5aa8f25a9fc254d401a3c1425fb60cf97742/jellyfish-1.2.1-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:536c80d8d4ec7f39cbb10b85d926ff96cef3cde4a83ca0991c07cd9835d5dc13", size = 535488, upload-time = "2025-10-11T19:36:24.252Z" }, { url = "https://files.pythonhosted.org/packages/74/3d/295468c5df5a8d03f522b0c21fc3e694d6be376602a6d755bf7815947522/jellyfish-1.2.1-pp311-pypy311_pp73-musllinux_1_1_i686.whl", hash = "sha256:21baa92d4a5112167721156f6d061c2ae105f2995b3a5e19cec6662928f0c439", size = 555818, upload-time = "2025-10-11T19:36:25.667Z" }, { url = "https://files.pythonhosted.org/packages/41/6d/4029265138a5a0b18e4df381560e467339bec477f4efaa7614736dbc433e/jellyfish-1.2.1-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:68ea3ddd4dae1152a7f7155ef02a7bfad919611158d71b301f9aa167685819af", size = 525259, upload-time = "2025-10-11T19:36:26.726Z" }, ] [[package]] name = "jinja2" version = "3.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] name = "joblib" version = "1.5.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, ] [[package]] name = "langdetect" version = "1.0.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } [[package]] name = "lap" version = "0.5.13" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f1/ae/5cc637c2e5158b7dcf1a9744d33b11dfc21d9309931169402f573e4d1ee3/lap-0.5.13.tar.gz", hash = "sha256:9eff7169e3ca452995af0493cc20d35452c4bfd06122c36c06457119ffbd411b", size = 1537351, upload-time = "2026-02-23T12:37:24.789Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/26/d6/91e97e538c9916ac6a3a12b700a13891704be8ea9b7b4e39dff21be9db69/lap-0.5.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2cc08c4ff49626ba6c1b707f0b02e92cf57a44359e65d9e769acdff1b510eebf", size = 1481773, upload-time = "2026-02-23T12:35:58.667Z" }, { url = "https://files.pythonhosted.org/packages/37/1b/1911550ed035c26aa54d1fc6bfafdd97f02e3cc2284904d0de410f17a681/lap-0.5.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:32cd1d38500da8e1ef51398121f1408ce23890cbc133647a0f665576b127eca7", size = 1478874, upload-time = "2026-02-23T12:36:00.368Z" }, { url = "https://files.pythonhosted.org/packages/e8/51/f046eb06c8a18b8c4a1121981b7c513e882216a000d47a5ecb317b247891/lap-0.5.13-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:33c53173abbd8da0ba8c4eef0a7f2dc72230c7c9bc0b634fe5c98873b4999ab8", size = 1708529, upload-time = "2026-02-23T12:36:01.624Z" }, { url = "https://files.pythonhosted.org/packages/bd/eb/6a6b6c53738e06af8be5fca3dd3839cd65c35cf0cc6640ec7505374e413c/lap-0.5.13-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10169f0401cf0ecd12f34d701abebbe2233c9fc5b9b5b46794157f5662646cb5", size = 1703789, upload-time = "2026-02-23T12:36:03.103Z" }, { url = "https://files.pythonhosted.org/packages/e7/7f/4bf5cc303b42c9a1c4f99b3f7398559167611aa786aee670fec5a6d81939/lap-0.5.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:65d88ca30e30805d57a45bee6dfa40893c0f3ee8c32120ddf660c625ad24d52a", size = 1700875, upload-time = "2026-02-23T12:36:04.507Z" }, { url = "https://files.pythonhosted.org/packages/36/c0/0de7f82521247242cca8506f7d4d13801d549d74337313545c1499e0d831/lap-0.5.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ba28e9350ec93ddc94c0a44ae55a8802bc5f19bb7d5e6df5df3f9aa7f7a0e3f1", size = 1710973, upload-time = "2026-02-23T12:36:05.901Z" }, { url = "https://files.pythonhosted.org/packages/27/63/9448f9a7275fe108acb5858d3d13f4d7eb2732ec239aad76088bacb58558/lap-0.5.13-cp310-cp310-win_amd64.whl", hash = "sha256:f36bc604ae05cb80541a544a8d594c6b07c927a320495fbbaa91f92e2a80b70c", size = 1478098, upload-time = "2026-02-23T12:36:07.124Z" }, { url = "https://files.pythonhosted.org/packages/26/1a/37a9fb2d9f8affea98a7260e160767897366f17922d027ed865a128b2e28/lap-0.5.13-cp310-cp310-win_arm64.whl", hash = "sha256:7538f7dbe0fac37dba7c5e9dc0a8bff34ce397eea9406f2126f49c3a9884e86d", size = 1467291, upload-time = "2026-02-23T12:36:08.342Z" }, { url = "https://files.pythonhosted.org/packages/d5/fc/4114078e67010a48bbe0c581f04c46a5e2da158cfc3e080d0232ef99de3f/lap-0.5.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c00af0eb19ba2b4a6ae6886061449318e3b917670b6fd17c99bffbdc88bf9038", size = 1480911, upload-time = "2026-02-23T12:36:10.114Z" }, { url = "https://files.pythonhosted.org/packages/4e/9b/21d52da69d084908bf33733cd51170f429987af3f96162deff7f5f60114d/lap-0.5.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9ed754fd43eef62e0e98038506bac04d8dfdc27b5812b93a91fcfcbf21d1a61f", size = 1478251, upload-time = "2026-02-23T12:36:11.524Z" }, { url = "https://files.pythonhosted.org/packages/83/7e/d6cfdda3b96559065c2a205debd4104d2064ecd936ed3ac3180e572f6555/lap-0.5.13-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f67f2bae5c95d2eb252dca6262a4038a41d52f76f4e4407e0f7bac22847c0e76", size = 1717286, upload-time = "2026-02-23T12:36:12.744Z" }, { url = "https://files.pythonhosted.org/packages/3d/90/8b5d5b308dc899d54ae8cb4292f035f0ea530d3fddd5d35e8e533de5256b/lap-0.5.13-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dadc17c83b429c27274de67474edbe407721e467e9c166611743b8871097edeb", size = 1713904, upload-time = "2026-02-23T12:36:14.239Z" }, { url = "https://files.pythonhosted.org/packages/02/c6/19d5e6896e496616573cfbd78f87c9508201304904e2cac4c27abca3364d/lap-0.5.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c974c51b2be1c4db696b953fbcf3657bf84c418304fac33064b86ed99194d25c", size = 1710762, upload-time = "2026-02-23T12:36:15.419Z" }, { url = "https://files.pythonhosted.org/packages/12/ce/a089226a167b46d9e16b7e300ef9c9a8c2229e19da9e671aa5e3f90265fe/lap-0.5.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2037d9a30b3f9a9fe185af419ca0d53f6ba3941d9677620522b1f1a62c3dd861", size = 1717976, upload-time = "2026-02-23T12:36:17.018Z" }, { url = "https://files.pythonhosted.org/packages/00/d1/052da79a000b09dd0f9c659dd2cbc5b46931e3804799fe2f8b3ef2a37599/lap-0.5.13-cp311-cp311-win_amd64.whl", hash = "sha256:df8dd3689004711c07b0d5fb7507644b01d578ef03b3328fa4bfd43f941be508", size = 1478189, upload-time = "2026-02-23T12:36:18.215Z" }, { url = "https://files.pythonhosted.org/packages/0b/fc/7b6e9c6b4f04c0f1f10884902584968a6ebc89e000aa37986c8bda2977c4/lap-0.5.13-cp311-cp311-win_arm64.whl", hash = "sha256:fe0debc9a5e1e6cccdb00127b1c03eade14b8d3cd2a56c96c8ae445276767d7c", size = 1467043, upload-time = "2026-02-23T12:36:19.514Z" }, { url = "https://files.pythonhosted.org/packages/e1/95/96bd702a260ddcdeef35a1d99a510b1f0cd51eab40f749daa728a2f66728/lap-0.5.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:77bbb235de0a416c77aae07aa2bebed4846ed741002da7721059279bd130ed4d", size = 1480314, upload-time = "2026-02-23T12:36:20.979Z" }, { url = "https://files.pythonhosted.org/packages/6c/c8/c16081ffcc8bf9f123940af8b74bfc8a1fac4f36b3cd7e9b440fdecd9fbc/lap-0.5.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8a793935e238f5430f764c38a1757331e86487738e5c7e8b82c374860e5a1074", size = 1478096, upload-time = "2026-02-23T12:36:22.419Z" }, { url = "https://files.pythonhosted.org/packages/92/0a/8d8395c8ea22a665ab4150fb2bcb97cc1f987843a1d316aaabc2d71044dd/lap-0.5.13-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:226c24acbc1acd22c76bac54525174577571d7e71e70845d0c43dd664332e867", size = 1732084, upload-time = "2026-02-23T12:36:24.003Z" }, { url = "https://files.pythonhosted.org/packages/8e/82/63fd09e866677f4263372785b23908efcce8da39bcc72fcced51e606bbe2/lap-0.5.13-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:355600a369281c830f900a9a215f8a8729c89ce3f2bf75e1943386fe3d8d1c88", size = 1725964, upload-time = "2026-02-23T12:36:25.339Z" }, { url = "https://files.pythonhosted.org/packages/4c/d3/82678703ab1b5a8773905e982244624b14ad004d8d3068d466c56bde0a31/lap-0.5.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a099030000709e5acfc85b1f3a464a2b7a61abc50e51ab0235f3058d9f26abb", size = 1724642, upload-time = "2026-02-23T12:36:26.759Z" }, { url = "https://files.pythonhosted.org/packages/89/f9/e1b61bd002ed6d37e71c355e102ca626f5c50218e769d3105215733b6c0d/lap-0.5.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8687037b179a4a5014f69d26ab917fd2129bbe5894b0768e0a18a60e242794da", size = 1735247, upload-time = "2026-02-23T12:36:28.16Z" }, { url = "https://files.pythonhosted.org/packages/b8/c7/cfd1b2274c00aba8513c0fa385c7e71790a9f44d7d23f5cdbcd94a895c06/lap-0.5.13-cp312-cp312-win_amd64.whl", hash = "sha256:eb9fc5d7977cb73cc6e69ee704b5329d18d0b1e1da27f4a6c848259b8148f39a", size = 1476908, upload-time = "2026-02-23T12:36:29.449Z" }, { url = "https://files.pythonhosted.org/packages/9e/bc/9101b3837c3aad5b0ca84f7fcdb8a75ecc666d8f060e7592a97e55f6da57/lap-0.5.13-cp312-cp312-win_arm64.whl", hash = "sha256:0f96f70d093896f0c61c48ad0b31b88225d310e7f6ab50401ca8fe9f5d5268d4", size = 1465883, upload-time = "2026-02-23T12:36:30.832Z" }, { url = "https://files.pythonhosted.org/packages/84/5b/329c1cdb1fd3a7c9d971310351a1bdfb4264110f9101e2ead942c852a7a0/lap-0.5.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d5e4b4d3b5b7530f28181c7e5dde892d808c19a08a8a8406c505095a272b9849", size = 1479642, upload-time = "2026-02-23T12:36:33.248Z" }, { url = "https://files.pythonhosted.org/packages/dd/ea/c2b401643c1c0a4e404bc15335302ccd7cddf0f095dbf4b04e911a84ce31/lap-0.5.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a806e4af277199c4161164a4ea9311f217ed0c084ca5fde010743d2ac8ac9ba", size = 1477371, upload-time = "2026-02-23T12:36:34.527Z" }, { url = "https://files.pythonhosted.org/packages/c8/5a/ef374f285dbab0673071503688e869354f6c2374be57880b1b997baba161/lap-0.5.13-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:508f6360c7bf2c59d89adff7dba8fd39166573d23f002f54a678c2e026b614cc", size = 1720150, upload-time = "2026-02-23T12:36:35.781Z" }, { url = "https://files.pythonhosted.org/packages/fa/16/b9316bee1776229baad3dca301daca5acd0cde0523227a4fb8e223b85bf6/lap-0.5.13-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdd55fb97879ba924821f8386a51bbbe8f1088fc4f4d9cd1afa40635c1b17036", size = 1715566, upload-time = "2026-02-23T12:36:37.275Z" }, { url = "https://files.pythonhosted.org/packages/6d/c3/341bdec28a1aaf99ed874fc48793d154ea9985bb498c8a4fd459cf9424e8/lap-0.5.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b145a738c55d26556a233d1bc597f96e0e00c0d11a1bfca07cf5907c00969126", size = 1705991, upload-time = "2026-02-23T12:36:39.086Z" }, { url = "https://files.pythonhosted.org/packages/d0/cc/c9f3c1e82a070d4f64d13a50e326fcc719714f3fe576792dcf3afce625ab/lap-0.5.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab5c634733dd0cdb3ef32f607644d238894df8781bbd91cfbf46435872ad4c92", size = 1716593, upload-time = "2026-02-23T12:36:40.291Z" }, { url = "https://files.pythonhosted.org/packages/cc/d7/613db6729e31c945f31d3875d9b00e4b43aff7aa4c53557054bdec29bc95/lap-0.5.13-cp313-cp313-win_amd64.whl", hash = "sha256:1170bd45958733e3ce00ba116fe5e5f1b49b744310d32eca8bf84f71121b7811", size = 1476231, upload-time = "2026-02-23T12:36:41.578Z" }, { url = "https://files.pythonhosted.org/packages/d5/2b/21503a02c513eb6ae496f65c46ec66a83a87711f7abe7d2c28a431bd099a/lap-0.5.13-cp313-cp313-win_arm64.whl", hash = "sha256:5a94c154fdc3b38c3f0b3ee89ee14b96781f0660aaeababa33d67d2667b4c27e", size = 1465522, upload-time = "2026-02-23T12:36:42.835Z" }, { url = "https://files.pythonhosted.org/packages/eb/ec/0b16230748a32fb7d4b8374b8680e5c453735b88e662f6ea54626ad5bef4/lap-0.5.13-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c0dfa1df4a6b30d250b9b304add985feb156d62ca3df79cfe1a40e6c80b9d304", size = 1479614, upload-time = "2026-02-23T12:36:44.5Z" }, { url = "https://files.pythonhosted.org/packages/0d/49/2d78d0d9cad96b15e37e7195854e32bfc61c9674dea1c5b62092880e89af/lap-0.5.13-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a2bb48c8fd21bb9f69099760cfc90233467e52c62e1528b271f961b4d3b59308", size = 1477530, upload-time = "2026-02-23T12:36:46.016Z" }, { url = "https://files.pythonhosted.org/packages/ee/0d/da2d6d3c87e09e3d89b83fb4b35717d6608e514b37a299f8f23d4eccafa5/lap-0.5.13-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8a29fcacbd1d94c68e0b36513558213940943d62ae8fd65f55350f7b8be073c0", size = 1716942, upload-time = "2026-02-23T12:36:47.492Z" }, { url = "https://files.pythonhosted.org/packages/a0/3e/7ebfdbd52f818074c6517779c6da1f25a8e5eced38cb1518e7c2a618d04d/lap-0.5.13-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f5a7a5f309fa55588eb21ec1bb347356800d4007b0547bb25b5d98552cfaa1", size = 1714853, upload-time = "2026-02-23T12:36:49.084Z" }, { url = "https://files.pythonhosted.org/packages/d8/8e/5fcedfaf18c2db03410e7b6bda191cb81ec1e452b1f38e27f668ad87a33e/lap-0.5.13-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a1ab768edaa10ee9ad32bd651ed904104c5ca12c7333bad8cd43cb62bdb62fd9", size = 1705449, upload-time = "2026-02-23T12:36:50.663Z" }, { url = "https://files.pythonhosted.org/packages/cd/04/3ba6fd224fe1994bb7fa6f0131cc73f54f5487df69a2dacd4dc02df66f78/lap-0.5.13-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:398db6cb10287e97c2f54c9f333adbee4a2e502f00744b402173a95749ee35c0", size = 1713766, upload-time = "2026-02-23T12:36:52.004Z" }, { url = "https://files.pythonhosted.org/packages/32/57/a6b18ec8dbb0145debfa3c8dfa9f35c3e5a28e96340cd8138370d1605657/lap-0.5.13-cp314-cp314-win_amd64.whl", hash = "sha256:40ef084ff5cd10fffbac76f56de4f5c2da039af57412e19a496c263397c8ffb4", size = 1477488, upload-time = "2026-02-23T12:36:53.514Z" }, { url = "https://files.pythonhosted.org/packages/c1/37/a23772ed1ced8d58e089f23d835857b9ae759a9f5733edc4b0c52fb393db/lap-0.5.13-cp314-cp314-win_arm64.whl", hash = "sha256:b5ef3928303c37661f887e1f8b28a381b07bcb0b9868fe911b5ef4e205f31495", size = 1467015, upload-time = "2026-02-23T12:36:54.684Z" }, ] [[package]] name = "lazy-loader" version = "0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/ac/21a1f8aa3777f5658576777ea76bfb124b702c520bbe90edf4ae9915eafa/lazy_loader-0.5.tar.gz", hash = "sha256:717f9179a0dbed357012ddad50a5ad3d5e4d9a0b8712680d4e687f5e6e6ed9b3", size = 15294, upload-time = "2026-03-06T15:45:09.054Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl", hash = "sha256:ab0ea149e9c554d4ffeeb21105ac60bed7f3b4fd69b1d2360a4add51b170b005", size = 8044, upload-time = "2026-03-06T15:45:07.668Z" }, ] [[package]] name = "libcst" version = "1.8.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyyaml", marker = "python_full_version != '3.13.*'" }, { name = "pyyaml-ft", marker = "python_full_version == '3.13.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/cd/337df968b38d94c5aabd3e1b10630f047a2b345f6e1d4456bd9fe7417537/libcst-1.8.6.tar.gz", hash = "sha256:f729c37c9317126da9475bdd06a7208eb52fcbd180a6341648b45a56b4ba708b", size = 891354, upload-time = "2025-11-03T22:33:30.621Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c4/52/97d5454dee9d014821fe0c88f3dc0e83131b97dd074a4d49537056a75475/libcst-1.8.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a20c5182af04332cc94d8520792befda06d73daf2865e6dddc5161c72ea92cb9", size = 2211698, upload-time = "2025-11-03T22:31:50.117Z" }, { url = "https://files.pythonhosted.org/packages/6c/a4/d1205985d378164687af3247a9c8f8bdb96278b0686ac98ab951bc6d336a/libcst-1.8.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:36473e47cb199b7e6531d653ee6ffed057de1d179301e6c67f651f3af0b499d6", size = 2093104, upload-time = "2025-11-03T22:31:52.189Z" }, { url = "https://files.pythonhosted.org/packages/9e/de/1338da681b7625b51e584922576d54f1b8db8fc7ff4dc79121afc5d4d2cd/libcst-1.8.6-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:06fc56335a45d61b7c1b856bfab4587b84cfe31e9d6368f60bb3c9129d900f58", size = 2237419, upload-time = "2025-11-03T22:31:53.526Z" }, { url = "https://files.pythonhosted.org/packages/50/06/ee66f2d83b870534756e593d464d8b33b0914c224dff3a407e0f74dc04e0/libcst-1.8.6-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6b23d14a7fc0addd9795795763af26b185deb7c456b1e7cc4d5228e69dab5ce8", size = 2300820, upload-time = "2025-11-03T22:31:55.995Z" }, { url = "https://files.pythonhosted.org/packages/9c/ca/959088729de8e0eac8dd516e4fb8623d8d92bad539060fa85c9e94d418a5/libcst-1.8.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:16cfe0cfca5fd840e1fb2c30afb628b023d3085b30c3484a79b61eae9d6fe7ba", size = 2301201, upload-time = "2025-11-03T22:31:57.347Z" }, { url = "https://files.pythonhosted.org/packages/c2/4c/2a21a8c452436097dfe1da277f738c3517f3f728713f16d84b9a3d67ca8d/libcst-1.8.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:455f49a93aea4070132c30ebb6c07c2dea0ba6c1fde5ffde59fc45dbb9cfbe4b", size = 2408213, upload-time = "2025-11-03T22:31:59.221Z" }, { url = "https://files.pythonhosted.org/packages/3e/26/8f7b671fad38a515bb20b038718fd2221ab658299119ac9bcec56c2ced27/libcst-1.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:72cca15800ffc00ba25788e4626189fe0bc5fe2a0c1cb4294bce2e4df21cc073", size = 2119189, upload-time = "2025-11-03T22:32:00.696Z" }, { url = "https://files.pythonhosted.org/packages/5b/bf/ffb23a48e27001165cc5c81c5d9b3d6583b21b7f5449109e03a0020b060c/libcst-1.8.6-cp310-cp310-win_arm64.whl", hash = "sha256:6cad63e3a26556b020b634d25a8703b605c0e0b491426b3e6b9e12ed20f09100", size = 2001736, upload-time = "2025-11-03T22:32:02.986Z" }, { url = "https://files.pythonhosted.org/packages/dc/15/95c2ecadc0fb4af8a7057ac2012a4c0ad5921b9ef1ace6c20006b56d3b5f/libcst-1.8.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3649a813660fbffd7bc24d3f810b1f75ac98bd40d9d6f56d1f0ee38579021073", size = 2211289, upload-time = "2025-11-03T22:32:04.673Z" }, { url = "https://files.pythonhosted.org/packages/80/c3/7e1107acd5ed15cf60cc07c7bb64498a33042dc4821874aea3ec4942f3cd/libcst-1.8.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0cbe17067055829607c5ba4afa46bfa4d0dd554c0b5a583546e690b7367a29b6", size = 2092927, upload-time = "2025-11-03T22:32:06.209Z" }, { url = "https://files.pythonhosted.org/packages/c1/ff/0d2be87f67e2841a4a37d35505e74b65991d30693295c46fc0380ace0454/libcst-1.8.6-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:59a7e388c57d21d63722018978a8ddba7b176e3a99bd34b9b84a576ed53f2978", size = 2237002, upload-time = "2025-11-03T22:32:07.559Z" }, { url = "https://files.pythonhosted.org/packages/69/99/8c4a1b35c7894ccd7d33eae01ac8967122f43da41325223181ca7e4738fe/libcst-1.8.6-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:b6c1248cc62952a3a005792b10cdef2a4e130847be9c74f33a7d617486f7e532", size = 2301048, upload-time = "2025-11-03T22:32:08.869Z" }, { url = "https://files.pythonhosted.org/packages/9b/8b/d1aa811eacf936cccfb386ae0585aa530ea1221ccf528d67144e041f5915/libcst-1.8.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6421a930b028c5ef4a943b32a5a78b7f1bf15138214525a2088f11acbb7d3d64", size = 2300675, upload-time = "2025-11-03T22:32:10.579Z" }, { url = "https://files.pythonhosted.org/packages/c6/6b/7b65cd41f25a10c1fef2389ddc5c2b2cc23dc4d648083fa3e1aa7e0eeac2/libcst-1.8.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6d8b67874f2188399a71a71731e1ba2d1a2c3173b7565d1cc7ffb32e8fbaba5b", size = 2407934, upload-time = "2025-11-03T22:32:11.856Z" }, { url = "https://files.pythonhosted.org/packages/c5/8b/401cfff374bb3b785adfad78f05225225767ee190997176b2a9da9ed9460/libcst-1.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:b0d8c364c44ae343937f474b2e492c1040df96d94530377c2f9263fb77096e4f", size = 2119247, upload-time = "2025-11-03T22:32:13.279Z" }, { url = "https://files.pythonhosted.org/packages/f1/17/085f59eaa044b6ff6bc42148a5449df2b7f0ba567307de7782fe85c39ee2/libcst-1.8.6-cp311-cp311-win_arm64.whl", hash = "sha256:5dcaaebc835dfe5755bc85f9b186fb7e2895dda78e805e577fef1011d51d5a5c", size = 2001774, upload-time = "2025-11-03T22:32:14.647Z" }, { url = "https://files.pythonhosted.org/packages/0c/3c/93365c17da3d42b055a8edb0e1e99f1c60c776471db6c9b7f1ddf6a44b28/libcst-1.8.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0c13d5bd3d8414a129e9dccaf0e5785108a4441e9b266e1e5e9d1f82d1b943c9", size = 2206166, upload-time = "2025-11-03T22:32:16.012Z" }, { url = "https://files.pythonhosted.org/packages/1d/cb/7530940e6ac50c6dd6022349721074e19309eb6aa296e942ede2213c1a19/libcst-1.8.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1472eeafd67cdb22544e59cf3bfc25d23dc94058a68cf41f6654ff4fcb92e09", size = 2083726, upload-time = "2025-11-03T22:32:17.312Z" }, { url = "https://files.pythonhosted.org/packages/1b/cf/7e5eaa8c8f2c54913160671575351d129170db757bb5e4b7faffed022271/libcst-1.8.6-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:089c58e75cb142ec33738a1a4ea7760a28b40c078ab2fd26b270dac7d2633a4d", size = 2235755, upload-time = "2025-11-03T22:32:18.859Z" }, { url = "https://files.pythonhosted.org/packages/55/54/570ec2b0e9a3de0af9922e3bb1b69a5429beefbc753a7ea770a27ad308bd/libcst-1.8.6-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c9d7aeafb1b07d25a964b148c0dda9451efb47bbbf67756e16eeae65004b0eb5", size = 2301473, upload-time = "2025-11-03T22:32:20.499Z" }, { url = "https://files.pythonhosted.org/packages/11/4c/163457d1717cd12181c421a4cca493454bcabd143fc7e53313bc6a4ad82a/libcst-1.8.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:207481197afd328aa91d02670c15b48d0256e676ce1ad4bafb6dc2b593cc58f1", size = 2298899, upload-time = "2025-11-03T22:32:21.765Z" }, { url = "https://files.pythonhosted.org/packages/35/1d/317ddef3669883619ef3d3395ea583305f353ef4ad87d7a5ac1c39be38e3/libcst-1.8.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:375965f34cc6f09f5f809244d3ff9bd4f6cb6699f571121cebce53622e7e0b86", size = 2408239, upload-time = "2025-11-03T22:32:23.275Z" }, { url = "https://files.pythonhosted.org/packages/9a/a1/f47d8cccf74e212dd6044b9d6dbc223636508da99acff1d54786653196bc/libcst-1.8.6-cp312-cp312-win_amd64.whl", hash = "sha256:da95b38693b989eaa8d32e452e8261cfa77fe5babfef1d8d2ac25af8c4aa7e6d", size = 2119660, upload-time = "2025-11-03T22:32:24.822Z" }, { url = "https://files.pythonhosted.org/packages/19/d0/dd313bf6a7942cdf951828f07ecc1a7695263f385065edc75ef3016a3cb5/libcst-1.8.6-cp312-cp312-win_arm64.whl", hash = "sha256:bff00e1c766658adbd09a175267f8b2f7616e5ee70ce45db3d7c4ce6d9f6bec7", size = 1999824, upload-time = "2025-11-03T22:32:26.131Z" }, { url = "https://files.pythonhosted.org/packages/90/01/723cd467ec267e712480c772aacc5aa73f82370c9665162fd12c41b0065b/libcst-1.8.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7445479ebe7d1aff0ee094ab5a1c7718e1ad78d33e3241e1a1ec65dcdbc22ffb", size = 2206386, upload-time = "2025-11-03T22:32:27.422Z" }, { url = "https://files.pythonhosted.org/packages/17/50/b944944f910f24c094f9b083f76f61e3985af5a376f5342a21e01e2d1a81/libcst-1.8.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4fc3fef8a2c983e7abf5d633e1884c5dd6fa0dcb8f6e32035abd3d3803a3a196", size = 2083945, upload-time = "2025-11-03T22:32:28.847Z" }, { url = "https://files.pythonhosted.org/packages/36/a1/bd1b2b2b7f153d82301cdaddba787f4a9fc781816df6bdb295ca5f88b7cf/libcst-1.8.6-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:1a3a5e4ee870907aa85a4076c914ae69066715a2741b821d9bf16f9579de1105", size = 2235818, upload-time = "2025-11-03T22:32:30.504Z" }, { url = "https://files.pythonhosted.org/packages/b9/ab/f5433988acc3b4d188c4bb154e57837df9488cc9ab551267cdeabd3bb5e7/libcst-1.8.6-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6609291c41f7ad0bac570bfca5af8fea1f4a27987d30a1fa8b67fe5e67e6c78d", size = 2301289, upload-time = "2025-11-03T22:32:31.812Z" }, { url = "https://files.pythonhosted.org/packages/5d/57/89f4ba7a6f1ac274eec9903a9e9174890d2198266eee8c00bc27eb45ecf7/libcst-1.8.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:25eaeae6567091443b5374b4c7d33a33636a2d58f5eda02135e96fc6c8807786", size = 2299230, upload-time = "2025-11-03T22:32:33.242Z" }, { url = "https://files.pythonhosted.org/packages/f2/36/0aa693bc24cce163a942df49d36bf47a7ed614a0cd5598eee2623bc31913/libcst-1.8.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04030ea4d39d69a65873b1d4d877def1c3951a7ada1824242539e399b8763d30", size = 2408519, upload-time = "2025-11-03T22:32:34.678Z" }, { url = "https://files.pythonhosted.org/packages/db/18/6dd055b5f15afa640fb3304b2ee9df8b7f72e79513814dbd0a78638f4a0e/libcst-1.8.6-cp313-cp313-win_amd64.whl", hash = "sha256:8066f1b70f21a2961e96bedf48649f27dfd5ea68be5cd1bed3742b047f14acde", size = 2119853, upload-time = "2025-11-03T22:32:36.287Z" }, { url = "https://files.pythonhosted.org/packages/c9/ed/5ddb2a22f0b0abdd6dcffa40621ada1feaf252a15e5b2733a0a85dfd0429/libcst-1.8.6-cp313-cp313-win_arm64.whl", hash = "sha256:c188d06b583900e662cd791a3f962a8c96d3dfc9b36ea315be39e0a4c4792ebf", size = 1999808, upload-time = "2025-11-03T22:32:38.1Z" }, { url = "https://files.pythonhosted.org/packages/25/d3/72b2de2c40b97e1ef4a1a1db4e5e52163fc7e7740ffef3846d30bc0096b5/libcst-1.8.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c41c76e034a1094afed7057023b1d8967f968782433f7299cd170eaa01ec033e", size = 2190553, upload-time = "2025-11-03T22:32:39.819Z" }, { url = "https://files.pythonhosted.org/packages/0d/20/983b7b210ccc3ad94a82db54230e92599c4a11b9cfc7ce3bc97c1d2df75c/libcst-1.8.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5432e785322aba3170352f6e72b32bea58d28abd141ac37cc9b0bf6b7c778f58", size = 2074717, upload-time = "2025-11-03T22:32:41.373Z" }, { url = "https://files.pythonhosted.org/packages/13/f2/9e01678fedc772e09672ed99930de7355757035780d65d59266fcee212b8/libcst-1.8.6-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:85b7025795b796dea5284d290ff69de5089fc8e989b25d6f6f15b6800be7167f", size = 2225834, upload-time = "2025-11-03T22:32:42.716Z" }, { url = "https://files.pythonhosted.org/packages/4a/0d/7bed847b5c8c365e9f1953da274edc87577042bee5a5af21fba63276e756/libcst-1.8.6-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:536567441182a62fb706e7aa954aca034827b19746832205953b2c725d254a93", size = 2287107, upload-time = "2025-11-03T22:32:44.549Z" }, { url = "https://files.pythonhosted.org/packages/02/f0/7e51fa84ade26c518bfbe7e2e4758b56d86a114c72d60309ac0d350426c4/libcst-1.8.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f04d3672bde1704f383a19e8f8331521abdbc1ed13abb349325a02ac56e5012", size = 2288672, upload-time = "2025-11-03T22:32:45.867Z" }, { url = "https://files.pythonhosted.org/packages/ad/cd/15762659a3f5799d36aab1bc2b7e732672722e249d7800e3c5f943b41250/libcst-1.8.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f04febcd70e1e67917be7de513c8d4749d2e09206798558d7fe632134426ea4", size = 2392661, upload-time = "2025-11-03T22:32:47.232Z" }, { url = "https://files.pythonhosted.org/packages/e4/6b/b7f9246c323910fcbe021241500f82e357521495dcfe419004dbb272c7cb/libcst-1.8.6-cp313-cp313t-win_amd64.whl", hash = "sha256:1dc3b897c8b0f7323412da3f4ad12b16b909150efc42238e19cbf19b561cc330", size = 2105068, upload-time = "2025-11-03T22:32:49.145Z" }, { url = "https://files.pythonhosted.org/packages/a6/0b/4fd40607bc4807ec2b93b054594373d7fa3d31bb983789901afcb9bcebe9/libcst-1.8.6-cp313-cp313t-win_arm64.whl", hash = "sha256:44f38139fa95e488db0f8976f9c7ca39a64d6bc09f2eceef260aa1f6da6a2e42", size = 1985181, upload-time = "2025-11-03T22:32:50.597Z" }, { url = "https://files.pythonhosted.org/packages/3a/60/4105441989e321f7ad0fd28ffccb83eb6aac0b7cfb0366dab855dcccfbe5/libcst-1.8.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:b188e626ce61de5ad1f95161b8557beb39253de4ec74fc9b1f25593324a0279c", size = 2204202, upload-time = "2025-11-03T22:32:52.311Z" }, { url = "https://files.pythonhosted.org/packages/67/2f/51a6f285c3a183e50cfe5269d4a533c21625aac2c8de5cdf2d41f079320d/libcst-1.8.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:87e74f7d7dfcba9efa91127081e22331d7c42515f0a0ac6e81d4cf2c3ed14661", size = 2083581, upload-time = "2025-11-03T22:32:54.269Z" }, { url = "https://files.pythonhosted.org/packages/2f/64/921b1c19b638860af76cdb28bc81d430056592910b9478eea49e31a7f47a/libcst-1.8.6-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:3a926a4b42015ee24ddfc8ae940c97bd99483d286b315b3ce82f3bafd9f53474", size = 2236495, upload-time = "2025-11-03T22:32:55.723Z" }, { url = "https://files.pythonhosted.org/packages/12/a8/b00592f9bede618cbb3df6ffe802fc65f1d1c03d48a10d353b108057d09c/libcst-1.8.6-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:3f4fbb7f569e69fd9e89d9d9caa57ca42c577c28ed05062f96a8c207594e75b8", size = 2301466, upload-time = "2025-11-03T22:32:57.337Z" }, { url = "https://files.pythonhosted.org/packages/af/df/790d9002f31580fefd0aec2f373a0f5da99070e04c5e8b1c995d0104f303/libcst-1.8.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:08bd63a8ce674be431260649e70fca1d43f1554f1591eac657f403ff8ef82c7a", size = 2300264, upload-time = "2025-11-03T22:32:58.852Z" }, { url = "https://files.pythonhosted.org/packages/21/de/dc3f10e65bab461be5de57850d2910a02c24c3ddb0da28f0e6e4133c3487/libcst-1.8.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e00e275d4ba95d4963431ea3e409aa407566a74ee2bf309a402f84fc744abe47", size = 2408572, upload-time = "2025-11-03T22:33:00.552Z" }, { url = "https://files.pythonhosted.org/packages/20/3b/35645157a7590891038b077db170d6dd04335cd2e82a63bdaa78c3297dfe/libcst-1.8.6-cp314-cp314-win_amd64.whl", hash = "sha256:fea5c7fa26556eedf277d4f72779c5ede45ac3018650721edd77fd37ccd4a2d4", size = 2193917, upload-time = "2025-11-03T22:33:02.354Z" }, { url = "https://files.pythonhosted.org/packages/b3/a2/1034a9ba7d3e82f2c2afaad84ba5180f601aed676d92b76325797ad60951/libcst-1.8.6-cp314-cp314-win_arm64.whl", hash = "sha256:bb9b4077bdf8857b2483879cbbf70f1073bc255b057ec5aac8a70d901bb838e9", size = 2078748, upload-time = "2025-11-03T22:33:03.707Z" }, { url = "https://files.pythonhosted.org/packages/95/a1/30bc61e8719f721a5562f77695e6154e9092d1bdf467aa35d0806dcd6cea/libcst-1.8.6-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:55ec021a296960c92e5a33b8d93e8ad4182b0eab657021f45262510a58223de1", size = 2188980, upload-time = "2025-11-03T22:33:05.152Z" }, { url = "https://files.pythonhosted.org/packages/2c/14/c660204532407c5628e3b615015a902ed2d0b884b77714a6bdbe73350910/libcst-1.8.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ba9ab2b012fbd53b36cafd8f4440a6b60e7e487cd8b87428e57336b7f38409a4", size = 2074828, upload-time = "2025-11-03T22:33:06.864Z" }, { url = "https://files.pythonhosted.org/packages/82/e2/c497c354943dff644749f177ee9737b09ed811b8fc842b05709a40fe0d1b/libcst-1.8.6-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c0a0cc80aebd8aa15609dd4d330611cbc05e9b4216bcaeabba7189f99ef07c28", size = 2225568, upload-time = "2025-11-03T22:33:08.354Z" }, { url = "https://files.pythonhosted.org/packages/86/ef/45999676d07bd6d0eefa28109b4f97124db114e92f9e108de42ba46a8028/libcst-1.8.6-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:42a4f68121e2e9c29f49c97f6154e8527cd31021809cc4a941c7270aa64f41aa", size = 2286523, upload-time = "2025-11-03T22:33:10.206Z" }, { url = "https://files.pythonhosted.org/packages/f4/6c/517d8bf57d9f811862f4125358caaf8cd3320a01291b3af08f7b50719db4/libcst-1.8.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a434c521fadaf9680788b50d5c21f4048fa85ed19d7d70bd40549fbaeeecab1", size = 2288044, upload-time = "2025-11-03T22:33:11.628Z" }, { url = "https://files.pythonhosted.org/packages/83/ce/24d7d49478ffb61207f229239879845da40a374965874f5ee60f96b02ddb/libcst-1.8.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6a65f844d813ab4ef351443badffa0ae358f98821561d19e18b3190f59e71996", size = 2392605, upload-time = "2025-11-03T22:33:12.962Z" }, { url = "https://files.pythonhosted.org/packages/39/c3/829092ead738b71e96a4e96896c96f276976e5a8a58b4473ed813d7c962b/libcst-1.8.6-cp314-cp314t-win_amd64.whl", hash = "sha256:bdb14bc4d4d83a57062fed2c5da93ecb426ff65b0dc02ddf3481040f5f074a82", size = 2181581, upload-time = "2025-11-03T22:33:14.514Z" }, { url = "https://files.pythonhosted.org/packages/98/6d/5d6a790a02eb0d9d36c4aed4f41b277497e6178900b2fa29c35353aa45ed/libcst-1.8.6-cp314-cp314t-win_arm64.whl", hash = "sha256:819c8081e2948635cab60c603e1bbdceccdfe19104a242530ad38a36222cb88f", size = 2065000, upload-time = "2025-11-03T22:33:16.257Z" }, ] [[package]] name = "librosa" version = "0.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "audioread" }, { name = "decorator" }, { name = "joblib" }, { name = "lazy-loader" }, { name = "msgpack" }, { name = "numba" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "pooch" }, { name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "soundfile" }, { name = "soxr" }, { name = "standard-aifc", marker = "python_full_version >= '3.13'" }, { name = "standard-sunau", marker = "python_full_version >= '3.13'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/36/360b5aafa0238e29758729e9486c6ed92a6f37fa403b7875e06c115cdf4a/librosa-0.11.0.tar.gz", hash = "sha256:f5ed951ca189b375bbe2e33b2abd7e040ceeee302b9bbaeeffdfddb8d0ace908", size = 327001, upload-time = "2025-03-11T15:09:54.884Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b5/ba/c63c5786dfee4c3417094c4b00966e61e4a63efecee22cb7b4c0387dda83/librosa-0.11.0-py3-none-any.whl", hash = "sha256:0b6415c4fd68bff4c29288abe67c6d80b587e0e1e2cfb0aad23e4559504a7fa1", size = 260749, upload-time = "2025-03-11T15:09:52.982Z" }, ] [[package]] name = "librt" version = "0.13.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/2f/3908645ddddab7120b46295e541ead308109fa48dbec7d67d7a778870d60/librt-0.13.0.tar.gz", hash = "sha256:1d2a610c14ac0d0750ee0a3ab8548e83155258387891caaca04def4bf7289781", size = 211402, upload-time = "2026-07-08T12:26:29.834Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/89/2f/ec5241c38e7fa0fe6c26bfc450e78b9489a6c3c08b394b85d2c10e506975/librt-0.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:34e47058fcc69a313293d6dee94216a4f30c929ae6f2476e58c5ba635aa639d5", size = 148654, upload-time = "2026-07-08T12:24:30.622Z" }, { url = "https://files.pythonhosted.org/packages/a5/1a/d651e18d3ee7aa2879322368c4f278bb7ecaa6b90caadfdec4ebfa8389f3/librt-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dbdd5b6509d0c2a8fe72cf494c299a61dbd58142a90a4190664ae159e4a7b547", size = 153537, upload-time = "2026-07-08T12:24:31.773Z" }, { url = "https://files.pythonhosted.org/packages/45/18/10bff2122577246009d9619b6569596daf69b7648812f997ca9ca0426f60/librt-0.13.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e56ea4ee4df77585a6b5c138f6538680886024fa559f5b55bd14b12e98e67b2", size = 494336, upload-time = "2026-07-08T12:24:33.079Z" }, { url = "https://files.pythonhosted.org/packages/67/69/87dfee871b852970f137fdeae8e2ca356c5ab38e6f21d2a3299535fc3159/librt-0.13.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f1f9cc4d09a46d9cb3c2063ae100629d3f52a6517c3c08c2f4c9828261883929", size = 485393, upload-time = "2026-07-08T12:24:34.324Z" }, { url = "https://files.pythonhosted.org/packages/e9/d5/625447a8c0441ff5f15f4ac5e1d323fb9d4d256ebfde7a3c8e003f646057/librt-0.13.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f125f5d46b20f89dc5587a55cc416b4ba2a5b2ffda36d048ee120e17598a653a", size = 515382, upload-time = "2026-07-08T12:24:35.575Z" }, { url = "https://files.pythonhosted.org/packages/8d/d8/1c8c49ea04235960426444deece9092a6b3a9587a850a81bae2335317411/librt-0.13.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2608d3b39f9e0b4a66a130d9150c615cba40a5090d25eeeaa225e0e46de8c0ac", size = 509483, upload-time = "2026-07-08T12:24:36.923Z" }, { url = "https://files.pythonhosted.org/packages/6f/65/f1760fc48050e215201a03506c32b7270159088d01f64557b53e39e74a45/librt-0.13.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fd35e95ab5e45c3901d37110263c7db85a961110f5460588fe37f8c131f88a7", size = 532503, upload-time = "2026-07-08T12:24:38.203Z" }, { url = "https://files.pythonhosted.org/packages/18/1b/793e281dcf494879eff99f642b63ebc9c7c58694a1c2d1e93362a22c7041/librt-0.13.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5f31b0aa13c9b04370d4da6be1ab7779776b3a075cceb6747a39a4be85fe1e40", size = 537027, upload-time = "2026-07-08T12:24:39.34Z" }, { url = "https://files.pythonhosted.org/packages/69/45/0801bbb40c9eea795d3dd3ce91c4c5f3fe7d42d23ec4be3e8cb283bcc754/librt-0.13.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0b795f5fc70fbbb787ceaf79bb3a0d627bcc33c53de51741755263ec406b775a", size = 517100, upload-time = "2026-07-08T12:24:40.907Z" }, { url = "https://files.pythonhosted.org/packages/a1/6c/eb5f514f8e29d4924bc0ff4601dd7b4175557e182e7c0721e84cffa39b8a/librt-0.13.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36b306a623aaad96fe4b378692b54f9c0789fccd833b9851753d5fbf6138cfde", size = 558653, upload-time = "2026-07-08T12:24:42.359Z" }, { url = "https://files.pythonhosted.org/packages/b4/bf/f140100d1b59fe87ff40b5ecbb4e27924335b189a784e230ee465452f6c2/librt-0.13.0-cp310-cp310-win32.whl", hash = "sha256:a3762e75fcac8c9e4dacaaf438bffd9003e2ca2c531b756f3c0035deefa674c8", size = 104402, upload-time = "2026-07-08T12:24:43.668Z" }, { url = "https://files.pythonhosted.org/packages/22/7c/57e40fef7cfb61869341cb28bdcefe8a950bebcbecca74a397bae14dce4a/librt-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:d63bae12a8aeb51380be3438e4dc4bd27354d0f8e19166b2f44e3e94d6f552dc", size = 125002, upload-time = "2026-07-08T12:24:44.793Z" }, { url = "https://files.pythonhosted.org/packages/89/25/a6498964cfeec270c468cffdc118f69c29b412593610d55fa1327ca51ff4/librt-0.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1b5a7bbff495baedbd9b916c367d66854008f8f3b575908ded477c499dc60082", size = 148029, upload-time = "2026-07-08T12:24:45.961Z" }, { url = "https://files.pythonhosted.org/packages/78/59/dc86d1bffd8e0c2818bace29d9f7783cfbb8e0673bf3673b5bbd5bbe0420/librt-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34bc7938b9fdf14fe32a406c19c71faf894c5cee7e7474bd0be2f17200b82d14", size = 153036, upload-time = "2026-07-08T12:24:47.257Z" }, { url = "https://files.pythonhosted.org/packages/29/3f/b923826660f02f286186cd9303d52bb05ced0a13708edc104dc8480920e3/librt-0.13.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f40e56b61b41be5f7dec938cfeffd660668cf4b5e72c78e7bd671d66b7bc2c79", size = 493062, upload-time = "2026-07-08T12:24:48.483Z" }, { url = "https://files.pythonhosted.org/packages/88/87/6c0980a9c9b1302cb68d108906697b89eceb55889bb1dcf77c109aa56ca5/librt-0.13.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:9c5d02b89de5acd0379a51ec44a89476fb03df6145442e1c8ecd6bee2f91b176", size = 485510, upload-time = "2026-07-08T12:24:49.727Z" }, { url = "https://files.pythonhosted.org/packages/32/81/795ae3b9df5dd94079fb807e38191855e023e8c6249014ae6bc3f0d9a490/librt-0.13.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7db9a3ff32ef5f7d1703d93831a3316cdf0b537de6a1cc03cc8fdd09b9194e89", size = 515909, upload-time = "2026-07-08T12:24:51.135Z" }, { url = "https://files.pythonhosted.org/packages/20/e5/182de15abce8907108a6fdb41487de65beb5099b74dc5841b19b099168db/librt-0.13.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3dbb2a31882456cadc7053378e81ad7ed7693db4ac9f98ab5f81ef034aa8ec9f", size = 508620, upload-time = "2026-07-08T12:24:52.358Z" }, { url = "https://files.pythonhosted.org/packages/32/03/33978d32db76e1f66377e8f78e42a2ca3c162143331677d1f50bbad36cfb/librt-0.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c6014e3c80f9c1fe268ef8b0e0ef113bac672cc032f2f93866e7ddad4f3e663d", size = 530363, upload-time = "2026-07-08T12:24:53.503Z" }, { url = "https://files.pythonhosted.org/packages/e6/f5/b291fbd2d00f7d8287bcbf67b5aa0c6afed4bc26cef23e079629c47a2c04/librt-0.13.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:091b60a4d2174fc1ec5c34cdc0b72efb6224753d76b7da61ebeab7a191aec8bd", size = 534209, upload-time = "2026-07-08T12:24:55.138Z" }, { url = "https://files.pythonhosted.org/packages/3e/03/6f41f17939d191bc21609f220da8509316bc62797f078545fe83be522e78/librt-0.13.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:66cb1138f384a191a6d75f986064841fcfdc0cea98f7bd9c9ab9b38049917588", size = 514254, upload-time = "2026-07-08T12:24:56.276Z" }, { url = "https://files.pythonhosted.org/packages/af/c2/2e4befa5410a7443019c14abccc94ff619797171f6b72013635fb87f31d7/librt-0.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:17221a7569f8f292aa0014226e48aa25b8c2b08da18088cd230953d0ea0f9cd1", size = 557611, upload-time = "2026-07-08T12:24:57.561Z" }, { url = "https://files.pythonhosted.org/packages/ab/54/8b69f81448417adbc040a2185f4e2eece1e1994b7dcfaeed4662b30f98a5/librt-0.13.0-cp311-cp311-win32.whl", hash = "sha256:fc67741da44c6eaa90e01eafb586bbba9b51eb5b6ed381ee6f5ae72eb3316d21", size = 104906, upload-time = "2026-07-08T12:24:58.806Z" }, { url = "https://files.pythonhosted.org/packages/76/5a/f4aaf37b50f2fde12c8c663b83fdd499cdc24f957f19543d7414bfcc9e25/librt-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:cc99dfb62b23c9207c33d0be8a2e2af7a42e21e6ea388b380a0c948c7b88953b", size = 125852, upload-time = "2026-07-08T12:25:00.065Z" }, { url = "https://files.pythonhosted.org/packages/f2/99/bf1820e6feeabc2f218c24450ec0c995d6a91e8ba0fd3caf042c9e8adb2a/librt-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:40ccd13c252d3fe473ffc8a57be7565abc8b64cf1b108344c859d5164f7f3e0c", size = 111832, upload-time = "2026-07-08T12:25:01.148Z" }, { url = "https://files.pythonhosted.org/packages/f0/f4/b2933ddae222dac338476abb872641169a5cfed2c2bb5444a5b07b32b0c3/librt-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30536798f4504c0fad0885b1d371b0539abb081e4570c9d7c641cb51141b49f0", size = 150990, upload-time = "2026-07-08T12:25:02.42Z" }, { url = "https://files.pythonhosted.org/packages/90/ef/db98f744ca50e6efc9c95c70ee49b77aefac31f6a3fc7c83754a42d6a74f/librt-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93d24ebb82aa4420b1409c389e7857bc35bd0b668007ac8172427d5c73cc8cc5", size = 155238, upload-time = "2026-07-08T12:25:03.681Z" }, { url = "https://files.pythonhosted.org/packages/03/e7/a197e7bc72baf2c61ce7fdc6906a5054dc05bd8da0819aa894e4857bf87e/librt-0.13.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb8a1adce42d8b75485a5d56a9623a50bcab995b6079f1dac59fc44034dd93d9", size = 503073, upload-time = "2026-07-08T12:25:05.049Z" }, { url = "https://files.pythonhosted.org/packages/f8/e7/7887712e27da7c1ab80fcabb1de6eb24243964f6557cae530d4b70706dbd/librt-0.13.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0763ca2ab66058174f9dee426dc64f5e0a89c24a7df8d3fe3f1836c04e25de4b", size = 496528, upload-time = "2026-07-08T12:25:06.26Z" }, { url = "https://files.pythonhosted.org/packages/94/f0/f2283385bb6b950b26a1410f4ce51ec27231e0b3a4b925c46366d218b198/librt-0.13.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b222493da6e7b6199db9bd79502436cf5a27da3c1f7fa83c7e285444fc93fd03", size = 531786, upload-time = "2026-07-08T12:25:07.658Z" }, { url = "https://files.pythonhosted.org/packages/36/11/69ac3b54766ffba5fd7e5acebfb048d66dbe1f9f2d14516c2b3edc59cf87/librt-0.13.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fadc63331f4388c3dc90090448f682a7e9feafc11481391c1e94f2f907a3976e", size = 524393, upload-time = "2026-07-08T12:25:09.121Z" }, { url = "https://files.pythonhosted.org/packages/61/5f/d72f95fd444a926a3c14b4e24979474116988dd57a45be242077c45d3c22/librt-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:70d9c62a4cffd9f23396cd5ef93fc5d11b31596b9b7d6306074abe3d5fcf09bd", size = 543026, upload-time = "2026-07-08T12:25:10.459Z" }, { url = "https://files.pythonhosted.org/packages/c4/08/dcd9993ad192737a004ba263d549f8ea605b326b952e7d6205c7d4170b76/librt-0.13.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66c0e7e6b02a155576df2c77ec933a70b72da726e248c494abf690923e624348", size = 546829, upload-time = "2026-07-08T12:25:11.716Z" }, { url = "https://files.pythonhosted.org/packages/96/d5/6d9bb2f54e4109a956b7128836529653eb9d740f784bc47ed10a02c1000e/librt-0.13.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ac04bcd3328eb91d99dfedf6a60d9c1f15d3434e6f6daf922f0420f7d90b85c7", size = 535700, upload-time = "2026-07-08T12:25:13.144Z" }, { url = "https://files.pythonhosted.org/packages/8c/f2/10946922503858a359492fa27f13e86228bde702116a740ac7b3cd185f24/librt-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db327e7271e653c32040b85ae6188059c924b57d7e1e29f935523fa017cd4e82", size = 573566, upload-time = "2026-07-08T12:25:14.336Z" }, { url = "https://files.pythonhosted.org/packages/48/a8/94f00e3c99479a18088af3685ea016c42f3c7d5d1964d8dbb40c08d7f1aa/librt-0.13.0-cp312-cp312-win32.whl", hash = "sha256:860bd1d8ba48456ce08feaf8d343a8aaeb2fa086f2bcaa2a923fa3f7a3ff9aa3", size = 106099, upload-time = "2026-07-08T12:25:16.159Z" }, { url = "https://files.pythonhosted.org/packages/c9/7b/2da9c74c1ed25a89cc4e1c8e007ea2eb4a0f1fafa3e70d757fe3242c5c5c/librt-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:e54a315caf843c8d77e388cadc56ea9ded569935ee2d2347d7ea94992e5aa6fa", size = 126934, upload-time = "2026-07-08T12:25:17.275Z" }, { url = "https://files.pythonhosted.org/packages/d0/65/aead61bbf3b5358593f9d4779d2a0e88eaf6ec191a6342dde36dd1df6371/librt-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:c718e99a0992127af84385378460db624103b559ab260435abcfe77a4e4ed1c1", size = 112236, upload-time = "2026-07-08T12:25:18.425Z" }, { url = "https://files.pythonhosted.org/packages/67/3b/18e7b63255297a2bdc9c25c8d6d4ca8eca9f63aceb1252c0f7427ac7099e/librt-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a468951af16155824e88bdd8326ebe5bdb371f3ec0ac04642994b98201d914f3", size = 151027, upload-time = "2026-07-08T12:25:19.638Z" }, { url = "https://files.pythonhosted.org/packages/4d/68/e2248452c00d1a03b45fee1752cdc8f790a476efd2402b75181da88a9e61/librt-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ae01d8512cc17079e53425635327dbf3f7ff57a42c00dec348bf79791c56444c", size = 155152, upload-time = "2026-07-08T12:25:20.851Z" }, { url = "https://files.pythonhosted.org/packages/0e/16/52b1c99bf19057a062aac39c900cbb81499f6f75d6c537c14463d247ba78/librt-0.13.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32c26893cd085c1efe83219e78d866da23fb20a066101b8f68210004361d224c", size = 502499, upload-time = "2026-07-08T12:25:22.055Z" }, { url = "https://files.pythonhosted.org/packages/9f/54/b811151805c795f55e0dedee6ec687b75f9982a8105d240ea3910737a77b/librt-0.13.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5929da1981a46bcf4b28b1b9499905f0ff58e2419da402a048234e9783acbc4b", size = 496108, upload-time = "2026-07-08T12:25:23.296Z" }, { url = "https://files.pythonhosted.org/packages/8f/f8/094d6b2bd93f3fdaa54db54cc788c4a365333bddad65ab02e04da0b1d004/librt-0.13.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b85d664d777bab6c0d709416cb42938251fda9e221b79e3a2215d85df5f4f9", size = 531576, upload-time = "2026-07-08T12:25:24.648Z" }, { url = "https://files.pythonhosted.org/packages/2e/40/541733d5755824f968f7ec39d78ffbd75d145964157ae5e69a09ec6d7326/librt-0.13.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:531b2df3e9fe96b1fcf73a6d165921e4656be5f58d631d384ebce344298368db", size = 524390, upload-time = "2026-07-08T12:25:25.898Z" }, { url = "https://files.pythonhosted.org/packages/c6/b5/255673cfdbf5ba663339d36cd863c897289ab4337577e19f9405ce059f36/librt-0.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:109b84a9edf69ad89dc1f66358659e14a031baca95e3e5b0060bd903ede8efd6", size = 543053, upload-time = "2026-07-08T12:25:27.436Z" }, { url = "https://files.pythonhosted.org/packages/9e/11/ab5005e9c9850710f21e354201bf090646349d3fabf5f951eaf70235729e/librt-0.13.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1304368a3e7ffc3e9db986796cc5326fdb5943a3567ecc137cff318e4240c0e7", size = 546387, upload-time = "2026-07-08T12:25:28.65Z" }, { url = "https://files.pythonhosted.org/packages/a2/04/a5d7ce1d1df1afd15ca283dcdf7530ac073e12d69ae8c40879dda96f7868/librt-0.13.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e4f9b472e7d308d94b62c801982065661158c6ed02790d6c7ddb4337cea0f9c1", size = 535970, upload-time = "2026-07-08T12:25:30.171Z" }, { url = "https://files.pythonhosted.org/packages/5a/76/927e267a6daa290174ac281b23c9804c8829b042ade9c6f24a065f540958/librt-0.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f836c37478f167a81200d8c8b2c920a22224564bed2c23d7aeec760965c367a", size = 573582, upload-time = "2026-07-08T12:25:31.507Z" }, { url = "https://files.pythonhosted.org/packages/10/24/b6c5213efe39c19f9e13605644d0cf063b4ddaa33ac2e45b088e23a70e2e/librt-0.13.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:4000d961ff9598ac6ea603c6c836a5ed49bc205ade5fc378b998dfe1e2c36628", size = 82189, upload-time = "2026-07-08T12:25:32.675Z" }, { url = "https://files.pythonhosted.org/packages/4c/00/d29736be177a906ac0b84a5b04b4fbfa22c776dc2f366de4172b0f968c08/librt-0.13.0-cp313-cp313-win32.whl", hash = "sha256:79e44cff71750d299d61a678e49995b0d5935a9cda238c2574daeca3ba536927", size = 106193, upload-time = "2026-07-08T12:25:33.692Z" }, { url = "https://files.pythonhosted.org/packages/c8/ac/aff6fb45393cb8912f39dfb156ef6b2d1cadb207ff465fc8f66141054be8/librt-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:54dab44a847d5ad1acd05c8a83fe518ae685516ecf4d3f7cc6e3df2a66767650", size = 126962, upload-time = "2026-07-08T12:25:34.769Z" }, { url = "https://files.pythonhosted.org/packages/d9/3a/d68cb2b334d53fd30fac81d3a489ce4ba0d9506f4df43fcf676b68352b19/librt-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:d4cb6fbfdf874340ab5e51450753c0f817b6958a3621125ee695bbc3de866566", size = 112127, upload-time = "2026-07-08T12:25:35.981Z" }, { url = "https://files.pythonhosted.org/packages/7b/66/f49ae0d592bd45b6941e9a8bafcb6a87cddcd501ee7874707e767f01b585/librt-0.13.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:25218d94b1d2cbc0ba1d8a3f9dc9af578d9646e5ed16443a70cde1dfdcce6d71", size = 149818, upload-time = "2026-07-08T12:25:37.203Z" }, { url = "https://files.pythonhosted.org/packages/3d/50/51c76d74014d04fb95b6506d286808984b78a2f7a41039094e6b2194ac48/librt-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f26629539d4893c2957a16c41bb058e1e135c1f150f6a2e25ed047f64cf3f5c6", size = 154071, upload-time = "2026-07-08T12:25:39.399Z" }, { url = "https://files.pythonhosted.org/packages/b8/fe/f19b0f5f82d5a1f2da736586bc840abd00ce07d6388136ae80b7333883fc/librt-0.13.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4517d47b2b8af26975a406fba7d314de9696d864252e0257c6ea90238cfe27f", size = 494168, upload-time = "2026-07-08T12:25:40.641Z" }, { url = "https://files.pythonhosted.org/packages/94/bc/b8550c75775127fd31a5f20e8775997f7b527ad661fc8ddccd7497c064f7/librt-0.13.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f19e181de5b3a1148bb3420b8c4b0b0ea0fce6950099724ad151d6cea5acc180", size = 491054, upload-time = "2026-07-08T12:25:41.905Z" }, { url = "https://files.pythonhosted.org/packages/30/14/4d0204867623df3f33f86efd3d3692ba5e01321443f4d6eab35a22697618/librt-0.13.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22034924f5b42d5a56371cf271771bfeaabf235a7a8b6264bef2d20013f786c6", size = 523006, upload-time = "2026-07-08T12:25:43.327Z" }, { url = "https://files.pythonhosted.org/packages/19/0a/c45fc9a260934696bace1ac5df1e148ac92bd71767aee3bf7cd7a4534f4c/librt-0.13.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7897db4e95e22468bdda33d8e012ceacd0182abf001e6389d763f0def6286b9", size = 515058, upload-time = "2026-07-08T12:25:44.541Z" }, { url = "https://files.pythonhosted.org/packages/13/0a/50c5ce45b326854ef8fa6ae4c36cf5142e5c55315eaf9e51d0ae73ac4da3/librt-0.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1ce61b3746545029d4f5c17d6bd74b676254ad98433086c846ffb5e8fa73f007", size = 534025, upload-time = "2026-07-08T12:25:45.825Z" }, { url = "https://files.pythonhosted.org/packages/89/2d/08c413c8f93fc13b8103624fce38e5caa86cd08cbbc8465870ab287af54b/librt-0.13.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:46c330e82565962c761dbce7941be2cff7db674ee807455a8d0cadc5f9b759b0", size = 540557, upload-time = "2026-07-08T12:25:47.059Z" }, { url = "https://files.pythonhosted.org/packages/b3/c1/93af71fb4a364952210051811dd4e40174e79656b050c89cacac18af3330/librt-0.13.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:375f5af8f99cbaa99dd293af986e3d57caabc9ba81a5d3f021603764854197a1", size = 523201, upload-time = "2026-07-08T12:25:48.392Z" }, { url = "https://files.pythonhosted.org/packages/c1/6e/9766f07b676a4889d9f8bc2864e9ba5fff165653143ef4dda7df6aa34d16/librt-0.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9320d34c3376ae204b2cd176e8d4883a013934e0aef822f1aed9c536490c275d", size = 565740, upload-time = "2026-07-08T12:25:49.678Z" }, { url = "https://files.pythonhosted.org/packages/a2/1e/664e3472ce2b6e10e9b83f29d4a36eb982ff6b5a169ae7567bba3a4c4ff5/librt-0.13.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:9af313c66157a69dc69ea0059a66961692250e0dc95af9c385a48ffb770a0d16", size = 81611, upload-time = "2026-07-08T12:25:50.857Z" }, { url = "https://files.pythonhosted.org/packages/2f/d4/8582a4d65e2234673685e07309d02c230b28a85724eb0acbf13f019b7f6e/librt-0.13.0-cp314-cp314-win32.whl", hash = "sha256:f2a7253458e34f33543551394ae4fe104b497ec2a65ac266074de64c1df82e37", size = 100106, upload-time = "2026-07-08T12:25:52.03Z" }, { url = "https://files.pythonhosted.org/packages/63/ce/0cb99efe6086b46cd985dc26672166fae312a239690e75871f7fafbd3fc5/librt-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:a3dfe4edf10e8ed7e55b026a8bfc2c2a8704218b659cd4bffdf604fab966dc39", size = 121209, upload-time = "2026-07-08T12:25:53.166Z" }, { url = "https://files.pythonhosted.org/packages/26/85/4f3ccb083a3c9b0d42e223acdb3c3f507953324a59cdcab4826e8e2e3b89/librt-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:68a5faee4bba381cb93b5961f684a514cf0053cb92308ff9c792c2fea0b174c6", size = 106404, upload-time = "2026-07-08T12:25:54.253Z" }, { url = "https://files.pythonhosted.org/packages/b2/77/333191499538c8e8189de7a4cba8e6f49ee949fd6d6e6324b21fd1522466/librt-0.13.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a38fb81d8376dfa2f8963b265fec07637802b0d01e2a127c19c66cb070fb24f5", size = 159231, upload-time = "2026-07-08T12:25:55.432Z" }, { url = "https://files.pythonhosted.org/packages/7a/9e/2aa83758f22c278b837a1d8025898434ce2b8bff36678d5330ecaef56dff/librt-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d4c8d9bd5abce34b2e75edb3bf37ab0f34e49b1f915a40ae8468eb7c85bc5b46", size = 161300, upload-time = "2026-07-08T12:25:56.585Z" }, { url = "https://files.pythonhosted.org/packages/bb/c0/86791e936553ca763d6b3c2fb4d31d596cd00e14fa631c283a40ba01559a/librt-0.13.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:387e2f1d27e89bffe0d3f520f0da0662c973fd607ca16c1808f8a5085419485e", size = 582056, upload-time = "2026-07-08T12:25:58.144Z" }, { url = "https://files.pythonhosted.org/packages/a8/d3/a9ec15984a185e000c4d2a16ba28bd623124ad4c38a10974c7ff78e3a893/librt-0.13.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:4f6db193d2e5e0ed60359b9a5a682cd67205d0d3b1e459a867dd4b5c4e7eaa7a", size = 562758, upload-time = "2026-07-08T12:25:59.544Z" }, { url = "https://files.pythonhosted.org/packages/3c/af/dbe36b78b19c06a55097f99305e4ea9458e2273e6ae16a3cbecaad7ee978/librt-0.13.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d38604854e8d22faadf683ec6c02bb0f886e2ba56ef981a1c36ee275f21ea22", size = 602095, upload-time = "2026-07-08T12:26:00.991Z" }, { url = "https://files.pythonhosted.org/packages/2a/a8/2966891b4dd2830f5203fbee92ac2c4947653a2390ba73dfa44244fad025/librt-0.13.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:371f7ce73026815dafd51c50ce38416e91428b28c4b2ec97cd39271164b0045c", size = 593452, upload-time = "2026-07-08T12:26:02.352Z" }, { url = "https://files.pythonhosted.org/packages/61/f5/4df8bfc8405ecf8c0d525b4d69636f694bdd8620b313ec8b76e54a5926cc/librt-0.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3aaedf52171bee90860704c560bc798fe83b76247df47568e0197e9b13c735a0", size = 623729, upload-time = "2026-07-08T12:26:04.294Z" }, { url = "https://files.pythonhosted.org/packages/d6/13/9ac202dffc8db06f75d06c08c2f9f6ff054be67d21272dcc078fa1cc0c57/librt-0.13.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:96bad8725a4f196a798366c25ce075d1f7543a4ec045ffc13e6a7ec095cdab04", size = 617077, upload-time = "2026-07-08T12:26:05.845Z" }, { url = "https://files.pythonhosted.org/packages/6e/f0/ebe38610716aee5cb28efd95089bb90192096179802779381e1c5dcf239c/librt-0.13.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:6bf6a559ffe4a93bbea6cf31ddf01a7fd9ba342ef51f27beb178e318b74acd61", size = 599561, upload-time = "2026-07-08T12:26:07.21Z" }, { url = "https://files.pythonhosted.org/packages/4f/5c/c2e72e236fff7abc716d5b1753b8b8cd3ea85ac46fe17d2e7c51d4e1c723/librt-0.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:301067672387902c55f94b51d5022304b36c966ea9fe1f21caab99a9bef487c9", size = 645511, upload-time = "2026-07-08T12:26:08.562Z" }, { url = "https://files.pythonhosted.org/packages/0c/99/6203ce619dee940d6bfbe099ec3fe4be00a68e9d60f70abf906cf124fe66/librt-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:5fdcf34f86de8fb66d7dc7589f96ba91c4aa46671200d400e6fd6f109a483f18", size = 104357, upload-time = "2026-07-08T12:26:09.828Z" }, { url = "https://files.pythonhosted.org/packages/52/dd/843b6314087c41657c7036d7914d8f294bdf9b580aa8513ea0588c8e9a3d/librt-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:260c33e92263fa629b4f6d3c51967a1c2158fe6c33237aaa3ebeac586b085259", size = 126998, upload-time = "2026-07-08T12:26:10.975Z" }, { url = "https://files.pythonhosted.org/packages/5f/5d/3dcec2884ba1b0806d1408612555c38dd5d68e90156b59f75f6e36435c3a/librt-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2f281549a4c52ac7bb97997f14353f8bd0e53a34ca0dad1c905cfd0b4a58ae99", size = 110771, upload-time = "2026-07-08T12:26:12.303Z" }, ] [[package]] name = "llvmlite" version = "0.48.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/a0/acc8ffcd5bdc63df0097e22c719bfcd61b604358343089313a8aebbb24ab/llvmlite-0.48.0.tar.gz", hash = "sha256:543b19f9ef8f3c7c60d1468191e4ee1b1537bf9f8a3d56f64c0ddd98de92edd2", size = 184016, upload-time = "2026-07-02T20:20:05.308Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a2/4e/32543c42568fb321b3bdfcf9106e4116ab8f5a7bbcfd9ecf5569b0c07d83/llvmlite-0.48.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:614aad57df707e3172efd5165f2aa7da6a0c6897e40dce590bf756396815ba76", size = 40480650, upload-time = "2026-07-01T18:41:01.945Z" }, { url = "https://files.pythonhosted.org/packages/a9/0d/6aa48abd423067139a129d1434b77bbcc56080db51d12a88510bb491ca3d/llvmlite-0.48.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:13532f248960ba888ad5ab8150494e2f3a3d20e5f59f264e63741ea5b0ba844c", size = 59890118, upload-time = "2026-07-01T18:41:10.608Z" }, { url = "https://files.pythonhosted.org/packages/5a/c7/aa917444d871a79608af49149de1b28764e87d2ab41f933c5cd02431d03d/llvmlite-0.48.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ee0c77685a18f5fca994ae21d0763007fca5c5c64b41de37accc78b69079176", size = 58343459, upload-time = "2026-07-01T18:41:06.21Z" }, { url = "https://files.pythonhosted.org/packages/c5/2b/ceee1cdc263617109d514ac4d1b31f10a282662740ff7d5777baae25b3b5/llvmlite-0.48.0-cp310-cp310-win_amd64.whl", hash = "sha256:02853fe4214acb3780fc920c3fee10564b61d58a35e1b78afcc8a546c2deaba3", size = 41864734, upload-time = "2026-07-01T18:41:14.746Z" }, { url = "https://files.pythonhosted.org/packages/9a/55/595981f14fbae9ba966feb12af552b1fe69889e44e64ac883a731ed335e0/llvmlite-0.48.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:56a7e24607d3f02d7b1bae8d29c7e1e423d53143d68b072999777f19678fe77b", size = 40480651, upload-time = "2026-07-01T18:41:18.438Z" }, { url = "https://files.pythonhosted.org/packages/26/08/0109d1b9cb3f4603f3890e30bc66c65332b79185f12a045343b2ae431f67/llvmlite-0.48.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6fa532d6bb3fd3f0803567c736401c54aecfe1a396d3ad25d2440d220e09f0e7", size = 59890118, upload-time = "2026-07-01T18:41:28.184Z" }, { url = "https://files.pythonhosted.org/packages/02/eb/c5281be180c789cdffbf45b671884c57d7e61345ef3b0f643a4965e108e8/llvmlite-0.48.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:979a66a3f28a02565383ff463527dce78e9b856298872a361283132488e83591", size = 58343458, upload-time = "2026-07-01T18:41:23.397Z" }, { url = "https://files.pythonhosted.org/packages/aa/f7/b3222b13f2d424dae3c9e63fde476af25ebccf1f3faf0b52d1b79fc15c70/llvmlite-0.48.0-cp311-cp311-win_amd64.whl", hash = "sha256:efaee0276e5e17c2b99b92e0c974bd484ef5977cf5dbc9168e82b71578edb47f", size = 41864734, upload-time = "2026-07-01T18:41:31.932Z" }, { url = "https://files.pythonhosted.org/packages/92/a2/28696a9e61e245d1a79816d29d106692a90a2b6e7d78c98b326db70827af/llvmlite-0.48.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:d66c3beb4209087ddd4cf4ed2a0856b6887e6a913bdcf1aacfec9851cf2cba4e", size = 40480651, upload-time = "2026-07-01T18:41:35.694Z" }, { url = "https://files.pythonhosted.org/packages/80/f2/72409351db66d0a317ec5087e076f31fb7b773a640db8a90ce6b5cac9edd/llvmlite-0.48.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:416fa4c2c66c2c6dc6d0a402648c19206e548efa0aa1eff01ad5cdad0af8217d", size = 59890118, upload-time = "2026-07-01T18:41:44.886Z" }, { url = "https://files.pythonhosted.org/packages/3a/27/5ae2f3722606360480707adb47f001ad89df8251d06b14ee80336e660b66/llvmlite-0.48.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f5e5a5131045b72345c71062ea1a91910dde913792b6c9b28ebb2c1c0a712e98", size = 58343459, upload-time = "2026-07-01T18:41:40.306Z" }, { url = "https://files.pythonhosted.org/packages/16/78/d824ffff7521cd140dc2006e44ce2bc82e64b48d1b32e90e956308c85a74/llvmlite-0.48.0-cp312-cp312-win_amd64.whl", hash = "sha256:d45c7541a80934ec6d8ab0defe67439494ecd2193cbf852a44ba827808976ac1", size = 41865022, upload-time = "2026-07-01T18:41:48.663Z" }, { url = "https://files.pythonhosted.org/packages/9c/23/fe9316d14626b42c73ef0b502e724705a6ee9450afe53759c0a99c37c2d7/llvmlite-0.48.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a83a99ef0c05b4ccddf9b6218ed9fe84b653a0caf7c1d9dbe148d6d16c67f518", size = 40480652, upload-time = "2026-07-01T18:41:52.216Z" }, { url = "https://files.pythonhosted.org/packages/1b/4a/90715fa12006d681270b08d881195b6fab3ec39572e048764a1f7f59fed7/llvmlite-0.48.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8761b9e522f55207e24424fcd98370289eec2710bf8e915c82d1053f642450dc", size = 59890120, upload-time = "2026-07-01T18:42:00.748Z" }, { url = "https://files.pythonhosted.org/packages/70/5e/7b3e20d64650ca3c80af0cdb664ec4b575ec83d9d4dd05bea8bd31f9bbb6/llvmlite-0.48.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2fe5cb59b2063bfa039dcb8ca6481c0181bf552f340d10dcf61d7996a665556e", size = 58343457, upload-time = "2026-07-01T18:41:56.41Z" }, { url = "https://files.pythonhosted.org/packages/17/97/5a430055d1838cf1fb7a01cfa943300f5e4c026fc6333a522c5e4a03b0c1/llvmlite-0.48.0-cp313-cp313-win_amd64.whl", hash = "sha256:91c7e24e74cde3f02b88aa5acca678373f9e069f3b98531b3dbb3a142d9d10bb", size = 41865022, upload-time = "2026-07-01T18:42:04.57Z" }, { url = "https://files.pythonhosted.org/packages/8d/8e/8170f2e0c217f88069c333d85bb976e536b332aecfcce606ddbdb249385f/llvmlite-0.48.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:321f1ac39b462603f0b589751aecf2d237d056f6d005749c1752b6f23ec3f074", size = 40480650, upload-time = "2026-07-01T18:42:07.935Z" }, { url = "https://files.pythonhosted.org/packages/d6/e1/05b50692b647cac3c18200ac485b04f342f00ed173c9cc46767274469a15/llvmlite-0.48.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:05f0103c8f2f96a37441337e3643863c01b8e83e530aff38960dcb383c54a065", size = 59890115, upload-time = "2026-07-01T18:42:17.805Z" }, { url = "https://files.pythonhosted.org/packages/f7/c3/470b8c4ff9ae2db2f9cf5c3e73de76ed908a32788ae9eb5602d43e6a476b/llvmlite-0.48.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:37d66fae72802175b0bfe1ea06e624b51e2d7aee6c3c34bbd09739b8f88e8e0b", size = 58343457, upload-time = "2026-07-01T18:42:13.217Z" }, { url = "https://files.pythonhosted.org/packages/c9/2d/6a5171fb7236ac0895e1a02ccba3735bf291e8597239aa6421894d3c0ba8/llvmlite-0.48.0-cp314-cp314-win_amd64.whl", hash = "sha256:966dcab0a598e2bd8fb5f2cc082cf7b07bae564fc485a3a8692393caf986facf", size = 42986372, upload-time = "2026-07-01T18:42:21.483Z" }, { url = "https://files.pythonhosted.org/packages/94/e3/7a93e09c9f94e637ca90209ceef0334a9a1d45b0bdb7c92ff922d25d6187/llvmlite-0.48.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7a5c413317050a1d67c34708bde97707f9b2257ef1017f7532d21fe7d9a9ff30", size = 40480654, upload-time = "2026-07-01T18:42:25.076Z" }, { url = "https://files.pythonhosted.org/packages/27/98/a29133b4728671a175f7d616fab8b1c6e1d8c269d1523581d3160697bfb1/llvmlite-0.48.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d9f952dff6c350c529997423d4fa43abae9722a884ac7ffafc37a3af676e7db", size = 59890119, upload-time = "2026-07-01T18:42:33.88Z" }, { url = "https://files.pythonhosted.org/packages/1a/cf/7aac11a1f1c7ec54b60c7f6814e87561fb6b55b2f290455d7941eb113420/llvmlite-0.48.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:054aa7d46595935565f276cf0c1659b4f10929c996dd4a606875fae26fba2a23", size = 58343460, upload-time = "2026-07-01T18:42:29.545Z" }, { url = "https://files.pythonhosted.org/packages/db/41/b96f440c7df5ebba07872cad4e30fbc3560387755b1ea0b629adb76d5ca8/llvmlite-0.48.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d0b3c61aac83b42fb48cc96bffbf57c81b82b2aa92276b7ed6420c814629a99a", size = 42986383, upload-time = "2026-07-01T18:42:37.544Z" }, ] [[package]] name = "lxml" version = "6.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40", size = 4197430, upload-time = "2026-05-18T19:19:06.424Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:09dd5b7075dc2f7709654a46543ba1ea3c2e217b2ed8fbd413a8a945a0f40f60", size = 8541124, upload-time = "2026-05-18T19:17:11.589Z" }, { url = "https://files.pythonhosted.org/packages/78/20/f7095ed9fc2c025f9cfe71cc6ec9f1feb05624edc1812423b5f1aecf3d4b/lxml-6.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f6ac4ef4d82dff54670227a69c67782ae0b811b5cf6b17954f1e8f7502fc0d1d", size = 4602783, upload-time = "2026-05-18T19:17:20.888Z" }, { url = "https://files.pythonhosted.org/packages/4a/a4/65c63ca98bd129f6cff7b8c2fa48953ab058cc6005b541354e7dd54d8000/lxml-6.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:556e94a63c9b04716f8e4de2abb65775061f846e89331b6c5be79183a24f98ea", size = 5002687, upload-time = "2026-05-18T19:17:01.738Z" }, { url = "https://files.pythonhosted.org/packages/96/1d/ab7a5c4b5a394d98a94e2d0fc67bab8297597426770dd4978370fbdaf531/lxml-6.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6bf403fbb3b3e348a561a5f4f0b9961835657981c802a1df03653eef8a9074", size = 5155099, upload-time = "2026-05-18T19:17:05.159Z" }, { url = "https://files.pythonhosted.org/packages/d0/b1/07603bfeeb891a2596d5c2a68f7d2f70f7d11c841ebe391412c69c2857b0/lxml-6.1.1-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1dde6131244bba38a17c745836ba190bc753fd73c9291666287fd0a3fa3dcf30", size = 5057225, upload-time = "2026-05-18T19:17:08.117Z" }, { url = "https://files.pythonhosted.org/packages/7a/16/cb391ee4b90186fa16d9ebcbe3ea96c71b8da3b0686386c8dcbcc3c67d44/lxml-6.1.1-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98fc784c2c1440667aeedf8465bdfe10208acf0ead656a2c68627299f546b315", size = 5287643, upload-time = "2026-05-18T19:17:11.507Z" }, { url = "https://files.pythonhosted.org/packages/eb/d6/b619717f918fd76747448fdbaee0e769edbc70e659b5b5d0112b7020b7a3/lxml-6.1.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:add8cf6ddf9a65116119a28ece0f7886e30af27ba724a7594305f1d1b58a92a1", size = 5412445, upload-time = "2026-05-18T19:17:22.182Z" }, { url = "https://files.pythonhosted.org/packages/c6/80/12bc5390ac0a3edeb579d9535e5049a5dda663438728e179d52fb319c33a/lxml-6.1.1-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:cf9d57306d848218f3601fee7601fab1a327c942d56e2e97610583cb4dd74206", size = 4770864, upload-time = "2026-05-18T19:17:26.851Z" }, { url = "https://files.pythonhosted.org/packages/0b/59/6500c09da3137f54f020e908d81cfc5ee3e8888e908fd380207afad7c2e6/lxml-6.1.1-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88136950da4d13c318bde414ce10219931937851327f44328f2df4d2c4614067", size = 5359594, upload-time = "2026-05-18T19:17:32.527Z" }, { url = "https://files.pythonhosted.org/packages/f2/9b/f64b4cc6b7ebcf75d95af3cde934d254b5f2f10d4163928d838d86b6eb48/lxml-6.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cecdd5dfdc87b1fd87dbf81d4b037a544f47f4c744200a67013771682d67686a", size = 5107713, upload-time = "2026-05-18T19:17:04.402Z" }, { url = "https://files.pythonhosted.org/packages/16/19/c7388ad5d3a72315d2832dc1458cbf4f2af7f2b990b606ff4876efd04511/lxml-6.1.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd312b9692e831d2ffcad61eab31d91d4b4655a962e61de8fb410472cbcd37aa", size = 4803973, upload-time = "2026-05-18T19:17:06.545Z" }, { url = "https://files.pythonhosted.org/packages/3f/22/76197f0bbf165f0b9e75be59be4997e5259cde973f12f098c1b54c7f5d60/lxml-6.1.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5b7328b46d49fc9477d91ae8f6d55340347d827b7734ba3ea33faae0efef1383", size = 5349925, upload-time = "2026-05-18T19:17:09.743Z" }, { url = "https://files.pythonhosted.org/packages/24/52/d2a0cfeccb9bcdc47c7ee05cdae5d69b48c9acf20997790a6338bb0d0b3b/lxml-6.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37a58976370f36d9329d118ad0b953c5aeb9119ac9c6a4e258942a225d0573a1", size = 5309825, upload-time = "2026-05-18T19:17:13.831Z" }, { url = "https://files.pythonhosted.org/packages/19/4a/b30944266776c2f49749ef2445aa7e78898194134b80ad776386f61b56ae/lxml-6.1.1-cp310-cp310-win32.whl", hash = "sha256:cea3f4c1af79af13cdb2da0c028111d8f8522d4f22a000c82385535f24e5cf3a", size = 3598402, upload-time = "2026-05-18T19:17:08.21Z" }, { url = "https://files.pythonhosted.org/packages/9e/97/33691c66a4d7ec1a5a98e7c909a5b83ee45c7f7ba4cf92b1c4cf26e98079/lxml-6.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:3abf332af33a74288675d936fe861fd4344da0dd6622193fbc4f2bfbb35536b5", size = 4021295, upload-time = "2026-05-18T19:17:28.638Z" }, { url = "https://files.pythonhosted.org/packages/d0/5f/26a4dd0e12b9456ff7b12a21af5b491eb6629680d1edd73f4140fd386bcf/lxml-6.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:8dadbe5b217ff35b6a8d16610dd710219b59b76d13f0e3f0d9f36786206e4485", size = 3667717, upload-time = "2026-05-19T19:22:44.474Z" }, { url = "https://files.pythonhosted.org/packages/62/b0/83f481780d1548750b8ce2ec824073deef2f452d9cd1a6faff8507e3d16d/lxml-6.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:53b7d2b7a10b1c35c0a5e21e9224accf60c1bbfba523990732e521b2b73adef2", size = 8526461, upload-time = "2026-05-18T19:17:25.862Z" }, { url = "https://files.pythonhosted.org/packages/b9/d5/30fa0f808002c7329397bfbb24e306789c0b29f04aa5842c07b174b4216f/lxml-6.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ff3f333630ab480244a1bff72043e511a91eb22e7595dead8653ee5612dd8f3d", size = 4595375, upload-time = "2026-05-18T19:17:34.555Z" }, { url = "https://files.pythonhosted.org/packages/4f/d2/edb71cf0e561581a7c5eb2626244320eb04e9f8ce6d563184fd668b45073/lxml-6.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a4bbea04c97f6d78a48e3fbc1cb9116d2780b1b39e03a23f6eb9b603fd61f510", size = 4923654, upload-time = "2026-05-18T19:17:42.917Z" }, { url = "https://files.pythonhosted.org/packages/4c/77/1bc7eeb0de4577d783fb625aa092cc9357883bba35845a3666bf1259f3dc/lxml-6.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db1d75f6617a49c1c01bc7023713e0ff59ab32c9579ae62a7674c0e34f3b0b0a", size = 5067921, upload-time = "2026-05-18T19:17:49.175Z" }, { url = "https://files.pythonhosted.org/packages/1b/3c/c0690d74bd2bc17bc03b5b0d093569ead597dd0bfa088bf99eef8c24e19c/lxml-6.1.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a12689be69a28ddaa0ab99a5a1137da2afd5f8f16df7b5680b66f616d3eda1d", size = 5002456, upload-time = "2026-05-18T19:17:59.715Z" }, { url = "https://files.pythonhosted.org/packages/66/8d/d1b3271af0c0f1e27e8472a849e4d2c65bc7766884b9ad2da9e76e145c88/lxml-6.1.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b73c339ae29b90fd2d06e58ebd555a751bde9cd6bbd36cc0281b9a2c94e9d8", size = 5202776, upload-time = "2026-05-18T19:18:08.924Z" }, { url = "https://files.pythonhosted.org/packages/7a/45/689824ffb237fd10125ad273f32b28ff04dc6203c2822c85ff65a93df65e/lxml-6.1.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:752d3bbfe874715ccd0aec7f88d7fc623c0f1fd7aa7b3238a084e017bad2a009", size = 5329945, upload-time = "2026-05-18T19:18:13.673Z" }, { url = "https://files.pythonhosted.org/packages/5d/c0/ef73af53767e958fd87d437c170f272e2f6e6c0f854939f133a895f1e711/lxml-6.1.1-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:6b1761fbf9ec984e2e9d9c589ef5f5fd684b7c19f92aadd567a26c5224958db6", size = 4659237, upload-time = "2026-05-18T19:18:18.657Z" }, { url = "https://files.pythonhosted.org/packages/a0/5e/e1158e40397585e91cb0472374a1f63d0926a1ddeaa92f13d1a1ffe306d5/lxml-6.1.1-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d680fbcb768404c601ecb43519ecd8461f6954cb11c06a78962f666832ccfca8", size = 5265904, upload-time = "2026-05-18T19:18:24.883Z" }, { url = "https://files.pythonhosted.org/packages/a0/16/8687e5d1400ed1c0bc41dace232ebb7553952b618ea1f2e5fb6e2cfbbe23/lxml-6.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:162af1091cd785f2f27e62d3547ae9bc58ec5c86dd314d67021fd02463708d83", size = 5045225, upload-time = "2026-05-18T19:17:20.073Z" }, { url = "https://files.pythonhosted.org/packages/ca/18/d877bd1ae2e5ffdfd4836565aba350db31feb2f2656d6ce70316ed66a05e/lxml-6.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e9308ff8241c532df3f3e570f9a5aeed6c853f888512ba4b75638d7c11c95ef6", size = 4712721, upload-time = "2026-05-18T19:17:40.512Z" }, { url = "https://files.pythonhosted.org/packages/44/4d/1f44fd1d770b10dacbf6b5c6e520f4d6e0708744930f719dc04e67cab981/lxml-6.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5f6994074ebae6ffb04447268e37dc16edc304f9859cf91acb86e0af6c1b395c", size = 5252549, upload-time = "2026-05-18T19:17:51.236Z" }, { url = "https://files.pythonhosted.org/packages/64/5d/1d66b84f850089254c230ef6ea6b267a5a54e2e179a5d960036a05d501d7/lxml-6.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80c2dfadb855da477cf73373ad29a333535dedb9b12bad02c9814c8e2b43bf08", size = 5226877, upload-time = "2026-05-18T19:18:00.875Z" }, { url = "https://files.pythonhosted.org/packages/ad/00/84c4b5302d42a2d0184f38d538c8a197f33b52a50bd4f7bcfe990bce3036/lxml-6.1.1-cp311-cp311-win32.whl", hash = "sha256:30a89d3ac8faec007453fb541f3f46807eeec88edd5826f6e3fe001752a2c621", size = 3594072, upload-time = "2026-05-18T19:17:12.714Z" }, { url = "https://files.pythonhosted.org/packages/61/9d/2e2f7d876349f45e0f3e29f72da311668853d59b58d473a2dea4f0160135/lxml-6.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:abbefa31eee84842140f67acef1c828e28bba8bbf0c3bc6e5492a9af88152c28", size = 4025469, upload-time = "2026-05-18T19:17:50.566Z" }, { url = "https://files.pythonhosted.org/packages/b0/d5/570e6390e4110331e6208b2ba83d1482cc9146808ee118b22824a34c1070/lxml-6.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:dcb292aa7fe485ceff7af4f92e46c5af397daec5dff64871a528f0fc47a3cc5b", size = 3667640, upload-time = "2026-05-19T19:22:48.293Z" }, { url = "https://files.pythonhosted.org/packages/6a/6e/c4add832b6fc1e887125b96f880d7b9b70aae5248718e046b1704bcac4b9/lxml-6.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7", size = 8570821, upload-time = "2026-05-18T19:17:42.068Z" }, { url = "https://files.pythonhosted.org/packages/22/00/ff3009c88e65de8011630acf8ab5a09cb2becd2aaf47fba2f3449f6224e9/lxml-6.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1", size = 4624252, upload-time = "2026-05-18T19:17:47.897Z" }, { url = "https://files.pythonhosted.org/packages/42/95/bb63f0fd62e554fe078e1fb3c8fe9083c14ddc7ad7fa178d10e57e071ac7/lxml-6.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc", size = 4930746, upload-time = "2026-05-18T19:18:29.637Z" }, { url = "https://files.pythonhosted.org/packages/eb/99/0013e8d9b5960f4f041cf0b73e2f80c23eb5205b1f7bfb20203243651359/lxml-6.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc", size = 5093723, upload-time = "2026-05-18T19:18:34.168Z" }, { url = "https://files.pythonhosted.org/packages/29/91/317b332636bfc7bddcff828d41b3307f50043f4b237e40849c333d80fa1a/lxml-6.1.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383", size = 5005557, upload-time = "2026-05-18T19:18:39.798Z" }, { url = "https://files.pythonhosted.org/packages/42/2f/cc9bf06afe70f9c9093ae60855d9759da9db601ec4080f7473319666ffd7/lxml-6.1.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b", size = 5631036, upload-time = "2026-05-18T19:18:44.858Z" }, { url = "https://files.pythonhosted.org/packages/08/f6/af32e23e563971ffb0fb86be52bc5be5c2c118858ffc119bf6a9039b173d/lxml-6.1.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818", size = 5240367, upload-time = "2026-05-18T19:18:49.217Z" }, { url = "https://files.pythonhosted.org/packages/78/83/8555d40948b09ce86f1bd0c68a7ac31d07b1929f92cc1b074006c97ef2d2/lxml-6.1.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740", size = 5350171, upload-time = "2026-05-18T19:18:52.779Z" }, { url = "https://files.pythonhosted.org/packages/63/75/5d92da93729b7bad783689e6496049fa40927b45bec7bf183c981de3ca70/lxml-6.1.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f", size = 4694874, upload-time = "2026-05-18T19:18:55.139Z" }, { url = "https://files.pythonhosted.org/packages/c5/b5/3aad415a9a25b822e783f15deeb4dffccf5113030f1afa2222dd929313d9/lxml-6.1.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2", size = 5244492, upload-time = "2026-05-18T19:19:01.28Z" }, { url = "https://files.pythonhosted.org/packages/f1/a1/5fcf7eb9904b80086aa47dcf0027de07b1bb990afad2e6823144c368ae04/lxml-6.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635", size = 5048232, upload-time = "2026-05-18T19:18:12.67Z" }, { url = "https://files.pythonhosted.org/packages/77/74/1f601b63c7a69fcdf10fa9b148c81da8442204194f6c55509cc485c786b9/lxml-6.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf", size = 4777023, upload-time = "2026-05-18T19:18:15.928Z" }, { url = "https://files.pythonhosted.org/packages/a2/b9/7a78f51aec95b1bf780d78e12705a9f6533284f8693dc5c0e6724fa53d3f/lxml-6.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc", size = 5645773, upload-time = "2026-05-18T19:18:23.223Z" }, { url = "https://files.pythonhosted.org/packages/a5/6e/98a7b7ad54e4e74fa1f20fff776913980619d0ebe5558232d7da6580bdd8/lxml-6.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955", size = 5233088, upload-time = "2026-05-18T19:18:31.433Z" }, { url = "https://files.pythonhosted.org/packages/65/d1/bc0ed2427bf609f2ee10da303a6a226f9c8bce94f945dc29a32ce55de6e4/lxml-6.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a", size = 5260995, upload-time = "2026-05-18T19:18:37.091Z" }, { url = "https://files.pythonhosted.org/packages/69/8b/6772e1a4b513fc50a8d931f19edde0e13ae6918510a1e13ff67864f3e5ed/lxml-6.1.1-cp312-cp312-win32.whl", hash = "sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a", size = 3596382, upload-time = "2026-05-18T19:17:18.37Z" }, { url = "https://files.pythonhosted.org/packages/1b/89/45198e9624762af2dfd2cb8782598477ceb29f6e59caab560388ae1f4ec1/lxml-6.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77", size = 3997255, upload-time = "2026-05-18T19:17:56.781Z" }, { url = "https://files.pythonhosted.org/packages/90/a9/7a54b6834088d9ae528a7b780584ba6a39a9457b0ac330479f20ffbc9449/lxml-6.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f", size = 3659610, upload-time = "2026-05-19T19:22:50.843Z" }, { url = "https://files.pythonhosted.org/packages/a5/eb/7e6f37c5584ccbb2ff267f56fd0339016938c1c8684cfefab9b33ffc2f36/lxml-6.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:68a9198d0fc122d14bb76837de9aa80cf84caed990b5b237f532ed87d3706736", size = 8559780, upload-time = "2026-05-18T19:17:57.661Z" }, { url = "https://files.pythonhosted.org/packages/a1/36/587c2521cf23a2cd6c9c22108aa7528f683a1f195ed7ccd23a4b1786ad36/lxml-6.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7d47866cb32fb503450b6edc9df355d10dc49836af2e89901bd6ac6b0896d9d9", size = 4618006, upload-time = "2026-05-18T19:18:04.452Z" }, { url = "https://files.pythonhosted.org/packages/6e/ca/ab7bfe2bf4c972af5e7878262845ead3a24a929a9b04bc11c7c1ece6c82a/lxml-6.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb7c9811bfaa8b1ed5ed319f5d370dfbcaa59d52ea64be2a5a85e18195930354", size = 4924139, upload-time = "2026-05-18T19:19:04.873Z" }, { url = "https://files.pythonhosted.org/packages/6b/55/a0c72851dfee5ecc689f949723a73dea457758912542cb955b108eaf0d8f/lxml-6.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:762ff394d5bd56da0cf034a23dcce4e13923f15321a2adfa2ac00201dc6d3fca", size = 5082329, upload-time = "2026-05-18T19:19:09.728Z" }, { url = "https://files.pythonhosted.org/packages/f0/b6/0608f7d61a3b96cc67e5648a3d906e31a5082093e10e7be65b3886289938/lxml-6.1.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a088f287f7d8275a33c07f2cac6c50b9319309a0200a39e7e75d80c707723099", size = 4993564, upload-time = "2026-05-18T19:19:13.608Z" }, { url = "https://files.pythonhosted.org/packages/4c/66/ae227524b066d29d55bf0b453d93d2d793c40218657d643dcbbca13b8faf/lxml-6.1.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e902da4b04e6b52e5893900d4b8ab46068f75f3561f01bf1080957f9fd932ed6", size = 5613467, upload-time = "2026-05-18T19:19:16.228Z" }, { url = "https://files.pythonhosted.org/packages/a6/76/dbe4a00b50385e40194231dcfe5a12c059de7cf90e89c83407d2b085b719/lxml-6.1.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d4962d4c66bf830a7e59ed6cfc17d148149898a3aefa8ec6e59763e6e3ed085", size = 5228304, upload-time = "2026-05-18T19:19:19.354Z" }, { url = "https://files.pythonhosted.org/packages/1c/01/00b1b8442ed2041793336868ba0b9ea4b13d7da7c085c6404c207a63bf79/lxml-6.1.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:581d4c8ae690a6609e64862dd6b7c2489635c2d13907fc2b20f2bc200ff1d21e", size = 5341607, upload-time = "2026-05-18T19:19:22.297Z" }, { url = "https://files.pythonhosted.org/packages/63/36/1ad29931e9a4638bb707869f01d423a6c815f82152138d1a40dfcfde2b95/lxml-6.1.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:876e1ff5930ed8bf295ec5ef9a8155e9b6b1876bbf1deed8b3a8069311875a8f", size = 4700168, upload-time = "2026-05-18T19:19:25.133Z" }, { url = "https://files.pythonhosted.org/packages/3c/d1/a9536cecf9be18a0dc72d32bead283a2332d1ffebd2dd3ac70ce444686e5/lxml-6.1.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9eb9b5a968f6e0f6d640092a567e14529ff8cea2e29d00da6f78a79fa49f013c", size = 5232487, upload-time = "2026-05-18T19:19:28.603Z" }, { url = "https://files.pythonhosted.org/packages/0e/77/b4fb1e03bf5d130e879214d3100092e386418807fb74dd0adc4b0a48f351/lxml-6.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:aa49e06d94aba782c6a02eecb7e507969e7e7a41b267f1b359bb35585f295d5b", size = 5044231, upload-time = "2026-05-18T19:18:42.246Z" }, { url = "https://files.pythonhosted.org/packages/26/4c/d00daeeb0a5530c4028a9232aa1b93db3ef4ed2158c116ea73c79a9765b3/lxml-6.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:70cdfd80589d59e43e18005dd7244e8895e93db8ab6a620b7e23df5445a4e3d2", size = 4769450, upload-time = "2026-05-18T19:18:48.013Z" }, { url = "https://files.pythonhosted.org/packages/ed/6a/715a3a8d156ce42f29cf014706f5410c2ff3b02267774110fc23266409fe/lxml-6.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:aad9aa39483ed8ec44d6d2e59e5b98a0d80676ef0d92f44bfc374836111f62f5", size = 5635874, upload-time = "2026-05-18T19:18:51.914Z" }, { url = "https://files.pythonhosted.org/packages/45/37/0544bc21dde2a88f3a17b504e6fc79c0e01d25a33c2f6079724e9e72b9c7/lxml-6.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d49514be2f28d895c38cf9d2b72d7b9a07d00314519f456c0b50b53cfcf4c785", size = 5223987, upload-time = "2026-05-18T19:18:59.715Z" }, { url = "https://files.pythonhosted.org/packages/4d/f8/f6a5e8185bcb28c2befae3d31f8e3df3b811cb0f47746517a81279fcafe1/lxml-6.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:47402e62c52ff5988c1e8c6c63177f5708bccf48e366dea4e3dcf1e645e04947", size = 5250276, upload-time = "2026-05-18T19:19:03.834Z" }, { url = "https://files.pythonhosted.org/packages/c7/f2/1a2b9f1b7a49d45495369be7ef9ad05b262930f2eab3e3145706fca8083f/lxml-6.1.1-cp313-cp313-win32.whl", hash = "sha256:3483644525531e1d5762b0c44a8e18b6efba321b6dcf8a8952de10b037618bca", size = 3596903, upload-time = "2026-05-18T19:17:29.863Z" }, { url = "https://files.pythonhosted.org/packages/e6/99/f4ffb024f238eec2131aaa09f3278fb6129cf892741bf68e1fc1afb8c100/lxml-6.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:a10bd2fd62e8ce916ececb342f348f190724a098c1faa056fdfb2a22ad5e8660", size = 3995869, upload-time = "2026-05-18T19:18:02.596Z" }, { url = "https://files.pythonhosted.org/packages/d1/53/70eb8c5c6037f27448f1e3c54ebede9545a801ae63f0a7254afca4fe8e45/lxml-6.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:424aa57aca0897eb922aef34395bd1289b3b6f04e6bae20ea123c0c7e333cffc", size = 3658490, upload-time = "2026-05-19T19:22:53.846Z" }, { url = "https://files.pythonhosted.org/packages/13/e2/2e325795566de01d0d7c3bb57d3c370616b2d07b01214e84eec5d3b10963/lxml-6.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:19b7ab10b210b0b3ad7985d9ac4eb66ab09a90b20fe6e2f7ba55d01a234345d0", size = 8577146, upload-time = "2026-05-18T19:18:17.765Z" }, { url = "https://files.pythonhosted.org/packages/93/cf/5630b5e4be7d2e6bee8efe83865c925221103cf0221303b104ce134b01e2/lxml-6.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c08e5c694306507275f2290073350c4f32e383db15213b2c69e7ff39c1193840", size = 4623866, upload-time = "2026-05-18T19:18:30.669Z" }, { url = "https://files.pythonhosted.org/packages/d2/51/3904907c063451cf8d4a5c9fe0cad95fa1f4ec57f4e3884fa0731bd7a305/lxml-6.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:74a9717fd0d82effef5c2854f0d917231d5324b5a3eb7275c43ac9fa32f97a14", size = 4950022, upload-time = "2026-05-18T19:19:31.958Z" }, { url = "https://files.pythonhosted.org/packages/94/cd/9c7611a51c37a2830928405817cc5d56a97f64fab83cc3f628748b135749/lxml-6.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efe0374196335f93b53269acd811b944f2e6bdc88e8894f214bd636455484909", size = 5086695, upload-time = "2026-05-18T19:19:34.764Z" }, { url = "https://files.pythonhosted.org/packages/da/d6/24e3b5906abb0b674ff2ae195bc3ce59708df2bcd17cf17703b2d7dd643a/lxml-6.1.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac931cdc9442c1763b8a8f6cd62c0c938737eafc5be75eff88df55fc73bc0d00", size = 5031642, upload-time = "2026-05-18T19:19:37.771Z" }, { url = "https://files.pythonhosted.org/packages/2d/db/6ec54f99019838bff54785c51da07f189eb4676861c5f2730962b0d8d665/lxml-6.1.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:aee395f5d0927f947758b4ec119fd5fc8ec71f07a1c5c52077b30b04c0fa6955", size = 5647338, upload-time = "2026-05-18T19:19:40.553Z" }, { url = "https://files.pythonhosted.org/packages/42/3d/ef4dcfffd22d27a61805d8ed9f7fb888495bc6aa88648fa07c1eaa5586b6/lxml-6.1.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9395002973c827b3ed67db77e6ec09f092919a587022174554096a269378fb13", size = 5239528, upload-time = "2026-05-18T19:19:43.657Z" }, { url = "https://files.pythonhosted.org/packages/62/bb/37fb3f0dff146bdcfa78eec47879273820b2a0bf350ec236ce14bd0b1c26/lxml-6.1.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:73bc2086f141224ebddb7fc5c6a36ca58b31b94b561e1dfe8e073e3270fad1e7", size = 5350730, upload-time = "2026-05-18T19:19:46.307Z" }, { url = "https://files.pythonhosted.org/packages/90/42/43253f168388df4fae1f38c01df36ddb9bee39e2048167b54cdcbae85ea3/lxml-6.1.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:3779def59032b81e44a5f70096ef6bf2082f8d901937dca354474ba09782e245", size = 4697530, upload-time = "2026-05-18T19:19:49.889Z" }, { url = "https://files.pythonhosted.org/packages/eb/a8/c5a8504f81bbdfc8e7094c2c850cdb4ed6777fc4d5ddd9e5ab819f3b0d54/lxml-6.1.1-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:86c89b9d55ebf820ad7c90bc533410f0d098054f293351f10603c0c46ff598f5", size = 5250670, upload-time = "2026-05-18T19:19:53.199Z" }, { url = "https://files.pythonhosted.org/packages/77/b7/c7e76ab18744d75e21f320ebf9ff9d1ceae2b54dd431ea5a64caf26c9672/lxml-6.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19607c6bbff2a44cf3fe8250abccd20942d3462473e0a721d01d379ed017e462", size = 5084485, upload-time = "2026-05-18T19:19:08.422Z" }, { url = "https://files.pythonhosted.org/packages/31/31/b35c53f8ef7b7c31cacd23d3638652fff7bcd1deb6eedb709ab43b685908/lxml-6.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c6ed5141a5c7507cf3ee76bd363b0d6f801e3321adc35b5d825a23115faa5465", size = 4737635, upload-time = "2026-05-18T19:19:12.321Z" }, { url = "https://files.pythonhosted.org/packages/d9/06/31f23c813a7fe8e0cb1b175e915b08c9bf4e86d225b210feadbdbe519667/lxml-6.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:62aeb7e85b5d60320b9d77eef2e773994e2c0ce10121b277e0a19804e1654a5a", size = 5670681, upload-time = "2026-05-18T19:19:15.001Z" }, { url = "https://files.pythonhosted.org/packages/1a/bc/ce619bccc89b1fd9ad8a8e1330ee3f3beff9f2ff95b712d7bbcdd6e22fc3/lxml-6.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b1b963fd8f5caa68e99dfae060d54de1fe9cba899b8718b44a00cdca53c3e590", size = 5238229, upload-time = "2026-05-18T19:19:18.131Z" }, { url = "https://files.pythonhosted.org/packages/2f/5d/b329acbbedc0b619ebc2be6cf7ee9ed07e80892c88d4dfd612c33805789a/lxml-6.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63876be28efefa04a1df615b46770e82042cce445cfdce55160522f57b231ccb", size = 5264191, upload-time = "2026-05-18T19:19:21.118Z" }, { url = "https://files.pythonhosted.org/packages/d6/85/be36fb1425b30db3c3f9df75fe86343ebffb79e6320bd7f588e25bfeac39/lxml-6.1.1-cp314-cp314-win32.whl", hash = "sha256:7f7a92e8583f06b1fd49d01158143b8461cfcd135dcb10ec807270a3051bd603", size = 3657202, upload-time = "2026-05-18T19:17:39.509Z" }, { url = "https://files.pythonhosted.org/packages/b8/ce/3cf9a827342269f54d405a6202397de63f07c69cbd6ce7d183a3f0cba1e9/lxml-6.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:b2d444f2e66624d68e9c6b211e28a76e22fff5fcabcfff4deac18b529b7d4137", size = 4064497, upload-time = "2026-05-18T19:18:14.662Z" }, { url = "https://files.pythonhosted.org/packages/d9/3e/1a957bde8f0760039e627f94699f82caa782c9d838d86c3d28245ee67212/lxml-6.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:3fd9728a2735fda14f4e8235830c86b539e9661e849665bf926d3f867943b4bf", size = 3741991, upload-time = "2026-05-19T19:22:59.111Z" }, { url = "https://files.pythonhosted.org/packages/78/b2/00ed55b3a2efa4658fb795c38d1090ec9b3e8a6c3683d4441fa517f09c3b/lxml-6.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:787b2496d0dbe8cd180984e8d29e3a6f76e7ea34db781cb3bd55e4ba1ef8b4ee", size = 8827545, upload-time = "2026-05-18T19:18:41.193Z" }, { url = "https://files.pythonhosted.org/packages/c0/73/74573db19baa618d5f266f2407898b087ff6927115b00b71e5fc1b700847/lxml-6.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2c8daa471358dc2d6fcf02165e80ec68f77871a286df95bc5cc3816153b0fd2c", size = 4735736, upload-time = "2026-05-18T19:18:46.761Z" }, { url = "https://files.pythonhosted.org/packages/16/02/6f7061f4f95f51e545d48e87647c54791d204a4e881be4156e7a26ba5338/lxml-6.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:acd7d70b64c0aae0c7922cca83d288a16f5f6da523637697872253415269baef", size = 4970291, upload-time = "2026-05-18T19:19:56.215Z" }, { url = "https://files.pythonhosted.org/packages/b0/02/55fc057d8283427dea7d6edb102e7a840239c77a64a983d92f62a304c0e9/lxml-6.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4f0dd2f01f9f8a89f565d000e03abcf0a13d692a346c8d22f628d49af098777a", size = 5102822, upload-time = "2026-05-18T19:19:59.223Z" }, { url = "https://files.pythonhosted.org/packages/e4/48/8e1cf78d89d66850121d9255a2a24414c98f775da93b90cf976956c24b14/lxml-6.1.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b7e8a14c8634bf6f7a568634cb395305a6d964aeb5b7ee32248094bed3a7e2c", size = 5027923, upload-time = "2026-05-18T19:20:01.549Z" }, { url = "https://files.pythonhosted.org/packages/ed/00/0632a0647612c8af24d26997b3b961397daa9d5b2581444805933629a4cb/lxml-6.1.1-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:86281fbdd6a8162756f8d603f37e3435bfa38043adb79c6dc6a2dfee065e7525", size = 5595843, upload-time = "2026-05-18T19:20:03.93Z" }, { url = "https://files.pythonhosted.org/packages/bc/86/ab008a7dc360711b66858d61c80a5979a70a09f2aa2b05d9698df80b803d/lxml-6.1.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5d7152ec39ca7c402d8fb9bad86140a15b9503bd0c54484e3f1bbe3dd37ceca", size = 5224515, upload-time = "2026-05-18T19:20:06.381Z" }, { url = "https://files.pythonhosted.org/packages/75/c6/2702ff375e728e34f56d9a45339a9cf7e4427e917f542225242d63a05afa/lxml-6.1.1-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:88d8cb75b9d82858497a5393e3c63cfbf03035225e4b35a49ed7ccb151e4dc0e", size = 5312511, upload-time = "2026-05-18T19:20:09.308Z" }, { url = "https://files.pythonhosted.org/packages/b7/57/a5807c98f87a86f10ef9ffab35516df7c0f0c4b6d5d33e9f608ab9c04a31/lxml-6.1.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f64ec5397ea6a41fc1b4af0380d79b44a755b5531dcaccd9940fb260dca93038", size = 4639206, upload-time = "2026-05-18T19:20:11.704Z" }, { url = "https://files.pythonhosted.org/packages/1f/e1/8a0a2c35734812395f4da4eaf33748a7e5705bfb2a58b128da764339d5ec/lxml-6.1.1-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d34bbf07dbc7ca5970671b1512e928991fb5e9d95365636c9b2d8b4f53af405e", size = 5232404, upload-time = "2026-05-18T19:20:14.064Z" }, { url = "https://files.pythonhosted.org/packages/c2/e2/0e6a4dd5ad84d01d99aa7bae7cfefd4a760a0e0f8176818241de17d9b6c0/lxml-6.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:17e0e18d4ad8adbd0399291bc44845b69d9dd68439a3cdebdf35ff902ec05072", size = 5083769, upload-time = "2026-05-18T19:19:23.758Z" }, { url = "https://files.pythonhosted.org/packages/a0/7e/161f33d463f6ffc1c7679104b65086dea120080d49dde4d238f015aaee2f/lxml-6.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:3ab541146f1f6968c462d6c2ac495148e8cdba2f8347700b2141b6ec5a75bf52", size = 4758936, upload-time = "2026-05-18T19:19:27.256Z" }, { url = "https://files.pythonhosted.org/packages/f1/fb/2369825e3f6ca99305bf9f7b7085fda91c8b0922a89e54d900974aa3ef85/lxml-6.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2a0217714657e023ef4293500f65aa20fce6164c8fd6b08fa5bd4a859fb14b9b", size = 5620296, upload-time = "2026-05-18T19:19:29.993Z" }, { url = "https://files.pythonhosted.org/packages/30/90/d61e383146f74c5ab683947ea14dc7b82778838ab9b95ea73a23b60d0191/lxml-6.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:05a82eb6e1530a64f26225b55cbd178113bd0b5af1c2b625f25e5296742c26d2", size = 5228598, upload-time = "2026-05-18T19:19:33.523Z" }, { url = "https://files.pythonhosted.org/packages/76/2d/2dafd8149e94b05bb070690efd5bb2680720681e03ff03fc57d2b70a1105/lxml-6.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9e36f163528fc50cbef305f02a5fd66d404edf7049cdaff211dbc2cba5a7013e", size = 5247845, upload-time = "2026-05-18T19:19:36.649Z" }, { url = "https://files.pythonhosted.org/packages/ce/68/b30e913340c380ddac9580c6e6230991fc37240ec4f64704833e4f3e2769/lxml-6.1.1-cp314-cp314t-win32.whl", hash = "sha256:649dda677cf3bd6ac9ae14007ba0c824ded8ce5808b53fc7431d9140399118c1", size = 3897345, upload-time = "2026-05-18T19:17:33.562Z" }, { url = "https://files.pythonhosted.org/packages/3c/4e/9eb2af5335545f9fbcd7af57bcf87c6025d31eaa31b14ec184a6c8675328/lxml-6.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:793033d6c5cdf33a573f910d9bea14ef8f5771820411d118da8e1182edb53d5e", size = 4393350, upload-time = "2026-05-18T19:18:10.076Z" }, { url = "https://files.pythonhosted.org/packages/7f/2c/0f1e93c636720e8a3eb59af2bfda99d98b55891e1c53bc30c2e0e865f01b/lxml-6.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c", size = 3817223, upload-time = "2026-05-19T19:22:56.823Z" }, { url = "https://files.pythonhosted.org/packages/b5/32/86a3f0f724a3a402d4627937a7fc27b160e45e7012b4adf47f6e1e844511/lxml-6.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:31033dc34636ea6b7d5cc11b1ddbda78a14de858ba9d3e1ed4b69a3085bc521e", size = 3930127, upload-time = "2026-05-18T19:19:02.27Z" }, { url = "https://files.pythonhosted.org/packages/40/44/d832e82af08723761556d004b1d04d281c09f9a8cecd7d3148548c9941a3/lxml-6.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3893c14c4b6ac5b2d54ba8cf03e99fe5104e592de491f19bd6b82756c09f8004", size = 4210769, upload-time = "2026-05-18T19:20:41.427Z" }, { url = "https://files.pythonhosted.org/packages/6d/39/0dc5949f759ed7d951e0bb8c2f2d9d7aca1908d22352fa84a8afd2ea54af/lxml-6.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c07da4cebf6889f03ebac8d238f62318e29f495de0aa18a51ea14e61ae907e2e", size = 4318163, upload-time = "2026-05-18T19:20:44.702Z" }, { url = "https://files.pythonhosted.org/packages/e6/fb/8ab3845fe046ba4cbf74536bcf6801a774b7caf4350de1c5d37f1f0a9e90/lxml-6.1.1-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6f0ce10945fab9c4c06ce14e22af9059d1a87493a9af4501a5b0b9187e21cf2", size = 4250945, upload-time = "2026-05-18T19:20:47.385Z" }, { url = "https://files.pythonhosted.org/packages/68/1b/7553ab136894374ffae8851ec06f98f511cd8e66246e41b6be059d0a7289/lxml-6.1.1-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f8844cd288697c6425c9beba919302241e3278871dc6519515e72b04e987abcf", size = 4401664, upload-time = "2026-05-18T19:20:50.489Z" }, { url = "https://files.pythonhosted.org/packages/db/a4/441aee36c6f6b249823d20fd91f9be9ab89d7c5a8ae542a4a4ca6d342d56/lxml-6.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:ed21202aec73cda4d55d1ce57b389aadb90ffb044e6cd1080b8347efe1b1ec84", size = 3508989, upload-time = "2026-05-18T19:18:38.158Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] [[package]] name = "mediafile" version = "0.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filetype" }, { name = "mutagen" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/02/460b31c20833036d8f171b991ff2f46c7f1dc85c6219e8bf7efca4a9aa5a/mediafile-0.17.0.tar.gz", hash = "sha256:80c9003fd25d7096a7237e3b58e6ff018ef67f9c39900feafacabac1742c7d3a", size = 24612, upload-time = "2026-04-24T19:06:31.028Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/58/c4389f744b64fa81c5380cf2b0bed7e67b5789443860e5d51d31206b8e9d/mediafile-0.17.0-py3-none-any.whl", hash = "sha256:1bba387527d474f4d93a1c4033ecaff4700e9e311cfac334b9232e409a222a59", size = 29889, upload-time = "2026-04-24T19:06:29.74Z" }, ] [[package]] name = "msgpack" version = "1.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/31/f9/c0a1c127f9049db9155afc316952ea571720dd01833ff5e4d7e8e6352dbb/msgpack-1.2.1.tar.gz", hash = "sha256:04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647", size = 183960, upload-time = "2026-06-18T16:13:52.594Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5b/16/f70100614b69feb3ade7285f08c9c52d6cda0a5c03f3f5e2facd63acb211/msgpack-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c7b398c56ff125feae96c2737abfec5595f1fa0aa186df60c56040b8accb95c", size = 82926, upload-time = "2026-06-18T16:12:31.531Z" }, { url = "https://files.pythonhosted.org/packages/e4/3c/08ecd5cdfe4e2de43aec79062028ad0f7b2d9b1fea5430068c198ba570da/msgpack-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1548006a91aa93c5da81f3bdcebc1a0d10cea2d25969754fbe848da622b2b895", size = 82730, upload-time = "2026-06-18T16:12:32.894Z" }, { url = "https://files.pythonhosted.org/packages/19/9f/a70c9cb1a04ecc134005149367dcfe35d167284e8f65035a1e4156ad17b5/msgpack-1.2.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1dabedcd0f23559f3596428c6589c1cd8c6eaed3a0d720795b07b0225d769203", size = 400729, upload-time = "2026-06-18T16:12:34.052Z" }, { url = "https://files.pythonhosted.org/packages/fa/7f/5ce020168cf0439041526e95aa068c722c016aee21624e331aeabeee2e8e/msgpack-1.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83efa1c898e0fc5380fc0cabbf75164c52e3b5cbb45973710d75821928380c73", size = 407625, upload-time = "2026-06-18T16:12:35.239Z" }, { url = "https://files.pythonhosted.org/packages/79/70/fb7668ce0386819303047057aef6fc1da73b584291d9cff82b821744e2ef/msgpack-1.2.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01e2dd6c9b19d333a00282330cc8a73d38d8dabc306dc5b42cd668c3ac82e833", size = 377891, upload-time = "2026-06-18T16:12:36.684Z" }, { url = "https://files.pythonhosted.org/packages/3d/dc/9ebe654a73c3aed2e40aa6b52e3c2a02b5f53ef0085fa235a45d5b367f87/msgpack-1.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:350cb813d0af6e65d2f7ef0d729f7ff5be5a8bce03665892f43e5883d4ecc1b8", size = 391987, upload-time = "2026-06-18T16:12:37.839Z" }, { url = "https://files.pythonhosted.org/packages/42/eb/b67cf64218a2fa25e1c671fe1d3dbb06cbeb973e71bc4b822da079862d0b/msgpack-1.2.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ee1d9ed27d0497b848923746cf762ed2e7db24f4be7eec8e5cbe8c766aa707b7", size = 374603, upload-time = "2026-06-18T16:12:39.221Z" }, { url = "https://files.pythonhosted.org/packages/a2/2e/9ee200cde32fd1a0101b4006202fde554c1860adfb9bf7bff31ea4c08df8/msgpack-1.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:633727297ed063441fd1cda2288865487f33ad14eeb8831afb5f0c396a62cfce", size = 405121, upload-time = "2026-06-18T16:12:40.524Z" }, { url = "https://files.pythonhosted.org/packages/43/b6/f10117be7ca7a51e8feed699a907b8e663a8cd66e115ae6b4fb30cc7945c/msgpack-1.2.1-cp310-cp310-win32.whl", hash = "sha256:298872ecf9e61950f1c6af4ca969b859ee91783bb920ef6e6172697d0c8aad74", size = 64088, upload-time = "2026-06-18T16:12:41.762Z" }, { url = "https://files.pythonhosted.org/packages/ba/93/89976c696fb0224662239d952c47b4d1661b34d79a332ef5584facaa8579/msgpack-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2ff164c1b0bcb740b073b99e945234d0212852fa378e44a208c425379140dbeb", size = 70113, upload-time = "2026-06-18T16:12:42.78Z" }, { url = "https://files.pythonhosted.org/packages/f4/6b/e9b1cdc042c4458801d2545ed782a95f3d6ba8e270cce8745b8603c7f748/msgpack-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29a3f6e9667868429d8240dfd063ea5ffdc1321c13d783aa23827a38de0dcb22", size = 82812, upload-time = "2026-06-18T16:12:45.022Z" }, { url = "https://files.pythonhosted.org/packages/0c/3a/dd518a1bf78ed1e9ad8afe57307c079a00eafe4b3068932a27ca1ea56b4f/msgpack-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aded5bdf32609dc7987a49bbbd15a8ef096193f96dd8bbeb791de729e650acf5", size = 82739, upload-time = "2026-06-18T16:12:46.025Z" }, { url = "https://files.pythonhosted.org/packages/70/e0/7ba9e1542bf0771a27b8b37c1316e3f95ae9d748fd765284655c476ad4ef/msgpack-1.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:146ee4e9ce80b365c6d4c47073da9da7bcec473e58194ceee5dd7620ace77e06", size = 414233, upload-time = "2026-06-18T16:12:47.029Z" }, { url = "https://files.pythonhosted.org/packages/03/8d/671d81534ea0e2b0e8a121be100020da09eb78861fe3aa8f3ef7dcd3bed1/msgpack-1.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a28d076ca7c82b9c8728ad90b7147489449557038bed50e4241eb832395169b4", size = 423843, upload-time = "2026-06-18T16:12:48.19Z" }, { url = "https://files.pythonhosted.org/packages/d2/b6/e5c737515ed1f166664b87601b532f58cbb73d8aa6a90b99f7c2c5037e8e/msgpack-1.2.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7d31c0ac0c640f877804c67cb2bc9f4e23dc2db97e96c2e67fa27d38283b41f8", size = 390772, upload-time = "2026-06-18T16:12:49.624Z" }, { url = "https://files.pythonhosted.org/packages/a8/46/62ed8c2e87d7021eab19921594d961ef3aa3794eec76c716dc30f3bfd433/msgpack-1.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ff92d7feeaf5bc26c51495b69e2f99ed97ab79346fb6555f44be7dd2ac6503b", size = 409559, upload-time = "2026-06-18T16:12:50.936Z" }, { url = "https://files.pythonhosted.org/packages/70/ff/59aa3887b860bbf43532835e192b1c388a17590d6068ae4f8b2bc74c906e/msgpack-1.2.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:779197a6513bab3c3632265e3d0f7cb3227e62510841a6f34f1eaa37efbb345e", size = 387838, upload-time = "2026-06-18T16:12:52.161Z" }, { url = "https://files.pythonhosted.org/packages/09/11/f8563e471093420cf6478cb3271a0175d8402b82d879783d4035d2d03360/msgpack-1.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:67f6dd22fa72a93752643f07889796d62739a13415ee630169a8ce764f86cf9f", size = 421732, upload-time = "2026-06-18T16:12:53.556Z" }, { url = "https://files.pythonhosted.org/packages/57/cf/e673683c4c6c90c1022b24c65af4b03eda72b182a1176ef6449069d66acc/msgpack-1.2.1-cp311-cp311-win32.whl", hash = "sha256:91054a783328e0ea7954b8771095705c8d2243b814743fbaadf14552c9c52c5d", size = 64091, upload-time = "2026-06-18T16:12:54.821Z" }, { url = "https://files.pythonhosted.org/packages/3f/07/ca212739d179f9083bff2c7c08c24101c3555a334fadc2b876b18768a3ae/msgpack-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2eda0b7ebb1283a98d3e4492ac933c8af6aff59fd3df1c3ed024f536af4b1dc8", size = 70462, upload-time = "2026-06-18T16:12:55.898Z" }, { url = "https://files.pythonhosted.org/packages/6d/be/6798347b425e26f35db82e69dd83c09716c856a3714e7bffc4c0860fd830/msgpack-1.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ee967f7c7e1df2890c671ff2ee51a28ded0efc95da3e507176dee881ce36c66", size = 65059, upload-time = "2026-06-18T16:12:57.053Z" }, { url = "https://files.pythonhosted.org/packages/bc/dd/9e8cbd8f5582ca4b590336f2b91ee5662f6a6ca562b565abaf696a0f81ff/msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35", size = 83531, upload-time = "2026-06-18T16:12:58.249Z" }, { url = "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c", size = 82657, upload-time = "2026-06-18T16:12:59.396Z" }, { url = "https://files.pythonhosted.org/packages/26/aa/753ad8b007b464e1d8aa0c8e650b9c5f4f725e658fc5ac8a7635c55b7f6e/msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0", size = 410634, upload-time = "2026-06-18T16:13:00.383Z" }, { url = "https://files.pythonhosted.org/packages/6a/fd/6adabd4f6d5e686f97dd02ce7fce3fe4cf672cbac36b8f67ff4040e8ad8b/msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a", size = 419989, upload-time = "2026-06-18T16:13:01.776Z" }, { url = "https://files.pythonhosted.org/packages/5a/cc/85039b7b0eb168aaad7383a23c97e291a11f08351cb45a606ce865e4e3f1/msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6", size = 377544, upload-time = "2026-06-18T16:13:03.637Z" }, { url = "https://files.pythonhosted.org/packages/ed/bf/35963899493b32030c85fc513b723ae66144ac70c11ebc52e889e16e3d99/msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a", size = 400842, upload-time = "2026-06-18T16:13:05.012Z" }, { url = "https://files.pythonhosted.org/packages/a6/df/8e2ac970c8f99264cd9997d1c73df5466bc19da3301d7dc5500862a9b089/msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1", size = 374108, upload-time = "2026-06-18T16:13:06.232Z" }, { url = "https://files.pythonhosted.org/packages/17/dd/fa8bd265110dfa51c20cb529f9e6d240a16fafe7e645004c6af2d01353ba/msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64", size = 414939, upload-time = "2026-06-18T16:13:07.478Z" }, { url = "https://files.pythonhosted.org/packages/2e/b9/8377a5ad8953fc0437c70cc98d9ae29f27fe5ac5109fbec0812085865735/msgpack-1.2.1-cp312-cp312-win32.whl", hash = "sha256:0c0d9802354507bcba62af19c17918e3eb437cc25e6f50657d511b5856a77aac", size = 64504, upload-time = "2026-06-18T16:13:08.822Z" }, { url = "https://files.pythonhosted.org/packages/57/7f/ce1e377df7e62461fefd9eb23bfb93a4a523f40a517b377b8f844d836828/msgpack-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c24aa15d5963051e1a5c62b12c50cd705992502b5ec1f3bece6046f33c9fc24", size = 71421, upload-time = "2026-06-18T16:13:09.828Z" }, { url = "https://files.pythonhosted.org/packages/8f/32/ebfe84c9929f08f188d56c7a2fd913406a9ddad76a634697c1c43b8112e6/msgpack-1.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:4227224aaec8f7fbcbfbd4272319347b2bb4030366502600f8c45588c5187b07", size = 64775, upload-time = "2026-06-18T16:13:11.056Z" }, { url = "https://files.pythonhosted.org/packages/b0/ac/dcddcab6f6c20ecb387ca5e980371cdb3f87ff69aeca388be97eebc4c074/msgpack-1.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a70e3cf2804a300d921bb0940426e35f4e489a23adfb77a808892241db0a064", size = 83151, upload-time = "2026-06-18T16:13:12.173Z" }, { url = "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:491cc39455ca765fad51fb451bf2915eb2cf41192ab5801ce8d67c1d614fe056", size = 82351, upload-time = "2026-06-18T16:13:13.194Z" }, { url = "https://files.pythonhosted.org/packages/e3/10/ddf7b06db879e8792d13934ddda09ff20bd2a583fd84c9b59aae9b0e650b/msgpack-1.2.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f310233ef7fb9c14e201c93639fe5f5260b005f56f0b29048e999c30935596cc", size = 407518, upload-time = "2026-06-18T16:13:14.233Z" }, { url = "https://files.pythonhosted.org/packages/79/d3/36a46a8ed992b781acbc05928bd5bee3c810cb0c3563bf81a7b0c04a1a76/msgpack-1.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:787c9bebb5833e8f6fc8abca3c0597683d8d87f56a8842b6b89c75a5f3176e2d", size = 416405, upload-time = "2026-06-18T16:13:15.435Z" }, { url = "https://files.pythonhosted.org/packages/f9/84/e8e9598b557c0ba6ddae901a73780a4c75ac667dddf59414b1e56a42fb34/msgpack-1.2.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc871b997a9370d855b7394465f2f350e847a5b806dd38dcc9c989e7d87da155", size = 376257, upload-time = "2026-06-18T16:13:17.022Z" }, { url = "https://files.pythonhosted.org/packages/40/16/738fe6d875ad7e2a9429c165322a4ec088f4f273cdfae63d96a89c467961/msgpack-1.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85f57e960d877f2977f6430896191b04a21f8901b3b4baf2e4604329f4db5402", size = 397469, upload-time = "2026-06-18T16:13:18.287Z" }, { url = "https://files.pythonhosted.org/packages/ca/be/6d5952df75a7f24f35833af764c3a6860780364cb3a0030beb8099e1b2b4/msgpack-1.2.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1233ee2dd0cefba127583de50ea654677277047d238303521db35def3d7b2e7c", size = 372802, upload-time = "2026-06-18T16:13:19.685Z" }, { url = "https://files.pythonhosted.org/packages/e1/39/e2ef7dbf0473bcb8dc7c50bf782a892d67414877b63e47fc88eb189ef5e6/msgpack-1.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e3dc2feb0876209d9c38aa56cb1de169bd6c4348f1aa48271f241226590993e6", size = 411273, upload-time = "2026-06-18T16:13:21.028Z" }, { url = "https://files.pythonhosted.org/packages/ef/c5/133f4512a56e983a93445c836c9d94d88f3bc2e0980ff4b9e577bd8416ce/msgpack-1.2.1-cp313-cp313-win32.whl", hash = "sha256:6d09badf350af2be9d189184e04e64cf54ad93569ab3d96fca58bd3e84aad707", size = 64471, upload-time = "2026-06-18T16:13:22.293Z" }, { url = "https://files.pythonhosted.org/packages/e2/98/577e10b055096a7dd40732358cabaf7180a20c79ed1dcdbb618e4b9deac7/msgpack-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:33f14fba63278b714efe6ad07e50ea5f03d91537aa6a1c5f1ceca4cf44013ca9", size = 71274, upload-time = "2026-06-18T16:13:23.455Z" }, { url = "https://files.pythonhosted.org/packages/ba/ee/0c0048e7cfbef23c6a94791b8959ab28155232e7956de8a305b5ff588f05/msgpack-1.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:afc5febcd4c99effbc02b528e49d6fd0760b2b7d48c05239e345a5fa6e743d9a", size = 64795, upload-time = "2026-06-18T16:13:24.687Z" }, { url = "https://files.pythonhosted.org/packages/77/58/cce442852c6b9e1639c7c8ac8fd9143121cb32dab0f308df4d1426a8eb9c/msgpack-1.2.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:05f340e47e7e47d2da8db9b53e1bb1d294369e9ef45a747441309f6650b8351d", size = 83610, upload-time = "2026-06-18T16:13:25.724Z" }, { url = "https://files.pythonhosted.org/packages/60/5c/15b4c7a0182f75ffa90751958ba36a9c01cafee367d49a3edc10ed140b01/msgpack-1.2.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:810b916696c86ef0deb3b74588480224df4c1b071136c34183e4a2a4284d7ac7", size = 83138, upload-time = "2026-06-18T16:13:26.781Z" }, { url = "https://files.pythonhosted.org/packages/b8/a6/99e58722feaffc5f2fbcc0c8c0d1451ab9f84097f7af87291b46af2390f4/msgpack-1.2.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca0dacff965c47afdc3749a8469d7302a8f801d6a28758d55120d75e66ce6889", size = 406090, upload-time = "2026-06-18T16:13:28.072Z" }, { url = "https://files.pythonhosted.org/packages/19/03/8c63e8cf52958534ef688625965ab04c269a6cadd8caef16758b380a821a/msgpack-1.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e2bf9280bceb5efca998435904b5d3e9fdbcc11d90dc9df30aec7973252b720", size = 412106, upload-time = "2026-06-18T16:13:29.427Z" }, { url = "https://files.pythonhosted.org/packages/63/d2/155d9e71b40e41fd934bc0c48b9b2770f22263e1ac20aad8e29fdca7be3f/msgpack-1.2.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6c4be5d1c02a42b066ca6ddb71adf36432868fdcdb6ee87e634e86e0674190", size = 374851, upload-time = "2026-06-18T16:13:30.631Z" }, { url = "https://files.pythonhosted.org/packages/98/48/deaf2326262a8d5ea3295ce9649912ecd3f551ba7ec8e33c665d2ba583f3/msgpack-1.2.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec0e675d59150a6269ddc9139087c722292664a37d071a849c05c473350f1f2d", size = 396168, upload-time = "2026-06-18T16:13:31.977Z" }, { url = "https://files.pythonhosted.org/packages/10/2a/b4410f906c2ec0008f1608d3ab5143afc3ad3f4e6da0fed3ea2231d0bef4/msgpack-1.2.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:dd3bfe82d53edfe4b7fc9a7ec9761e23a7a5b1dac22264505af428253c29ed24", size = 371959, upload-time = "2026-06-18T16:13:33.282Z" }, { url = "https://files.pythonhosted.org/packages/59/86/1edc67270099a528fa2093ea60fe191233cd238e4bd30cfacf7db79fc959/msgpack-1.2.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5ad5467fc3f68b5468e06c5f788d712e9f8ffc8b0cd1bcb160c105c1ee92dae7", size = 408457, upload-time = "2026-06-18T16:13:34.567Z" }, { url = "https://files.pythonhosted.org/packages/82/90/8b630fef07d8c5ab457b71ff2c217910c83d333c7a68472c186e87cc504a/msgpack-1.2.1-cp314-cp314-win32.whl", hash = "sha256:98b58bdb89c46190e4609bb36abe17c6d4105ad13f9c5f8f6f64d320f8ced3fb", size = 65942, upload-time = "2026-06-18T16:13:36.056Z" }, { url = "https://files.pythonhosted.org/packages/16/f1/467b81e98b24dd3885d7b1857728797b4ffc76a7a7483af4fb321a07de3c/msgpack-1.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:74847557e28ce71bd3c438a447ca90e4b507e997ddbdef8a12a7b283b86c156b", size = 72627, upload-time = "2026-06-18T16:13:37.079Z" }, { url = "https://files.pythonhosted.org/packages/a7/1d/5d8c4c89985feb6acefb82a09e501c60392261856d2408d20bfe4f0360b1/msgpack-1.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:b50b727bd652bdc37d950336c848ef20ec54a4cafc38dce19b1cd86ad625d0f7", size = 66908, upload-time = "2026-06-18T16:13:38.23Z" }, { url = "https://files.pythonhosted.org/packages/1b/02/ad2afb678b4de94496cd432b581759b756a92c1192d8c767edd6b132efdc/msgpack-1.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8d00f177ca88a77c1cf848d204a38f249751650b601cb6532acc68805d8a8273", size = 86000, upload-time = "2026-06-18T16:13:39.44Z" }, { url = "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5bb9c386f0a329c035ddbab4b72d1028bf9627add8dda41070288563d57ed1b1", size = 86544, upload-time = "2026-06-18T16:13:40.447Z" }, { url = "https://files.pythonhosted.org/packages/a9/b4/b774d7eb95561739907fec675582f83203cf41c597a418c2589b4bfb8e9d/msgpack-1.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20466cca18c49c7292a8984bc15d65857b171e7264bdcb5f96baf8be238791fc", size = 427661, upload-time = "2026-06-18T16:13:41.574Z" }, { url = "https://files.pythonhosted.org/packages/b2/f9/3243191dc9937e00756c8bc1b0272fed8f23758e43df2a3b46f533e5090f/msgpack-1.2.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:196300e7e5d6e74d50f1607ab9c06c4a1484c383cd22defd727902591f7e8dde", size = 426375, upload-time = "2026-06-18T16:13:42.936Z" }, { url = "https://files.pythonhosted.org/packages/23/c7/1693111db9944ba4ad4b67a1e788400d78a0b6af7a6523dc7e4e58f8274b/msgpack-1.2.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575957e79cd51903a4e8495a242442949641e08f1efd5197b43bebd3ea7682b4", size = 380495, upload-time = "2026-06-18T16:13:44.306Z" }, { url = "https://files.pythonhosted.org/packages/3e/2b/92f86956a0c13e8662f7e2ad630c4eb4db07497b967589bd5245e018b2c1/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8c2ed1e48cc0f460bf3c7780e7137ff21a4e18433451916f2442c1b21036cd7d", size = 410897, upload-time = "2026-06-18T16:13:45.629Z" }, { url = "https://files.pythonhosted.org/packages/da/ea/1479f72d200313a76fc2f823a79d1e07ed052ab7b8a0280640aa7b95de42/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5f6277e5f783c36786a145e0247fc189a03f35f84b251646e53592d2bc12b355", size = 378519, upload-time = "2026-06-18T16:13:46.998Z" }, { url = "https://files.pythonhosted.org/packages/f5/4d/fa006060ffa1011d32bfae826fe766fe73e02982183601633b7121058ab3/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9389552ecf4784886345ead0647e4edc96bee37cbab05b75540f542f766c48c", size = 419815, upload-time = "2026-06-18T16:13:48.205Z" }, { url = "https://files.pythonhosted.org/packages/2f/e1/aab6c946570496b78e67804721f3d5e2d62a93081b9b37df77764ef56347/msgpack-1.2.1-cp314-cp314t-win32.whl", hash = "sha256:c1c79a604a2969a868a78b6ebd27a887e00c624f14f66b3038e0590cb23332d1", size = 70914, upload-time = "2026-06-18T16:13:49.385Z" }, { url = "https://files.pythonhosted.org/packages/13/0a/e608956488a2af014cfe6e3d665e090b8ee42aa14b07f8f95b8880d66b09/msgpack-1.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f12038a35fabd52e56a3547bab42401af49a45caa6dd00b34c44de235bc93ee2", size = 77999, upload-time = "2026-06-18T16:13:50.467Z" }, { url = "https://files.pythonhosted.org/packages/d2/8a/27e2e57055176e366a46b85d02d68e7a5bcfbdd8474c9706375d965f24d3/msgpack-1.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:0adcf06ffde0777c0e1a9b771a2b1c4226ba1bbf748c8efcc02fcdeca3299107", size = 71160, upload-time = "2026-06-18T16:13:51.498Z" }, ] [[package]] name = "multivolumefile" version = "0.2.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/50/f0/a7786212b5a4cb9ba05ae84a2bbd11d1d0279523aea0424b6d981d652a14/multivolumefile-0.2.3.tar.gz", hash = "sha256:a0648d0aafbc96e59198d5c17e9acad7eb531abea51035d08ce8060dcad709d6", size = 77984, upload-time = "2021-04-29T12:18:39.882Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/22/31/ec5f46fd4c83185b806aa9c736e228cb780f13990a9cf4da0beb70025fcc/multivolumefile-0.2.3-py3-none-any.whl", hash = "sha256:237f4353b60af1703087cf7725755a1f6fcaeeea48421e1896940cd1c920d678", size = 17037, upload-time = "2021-04-29T12:18:38.886Z" }, ] [[package]] name = "mutagen" version = "1.48.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/df/70/1675da133ea92227da41bf5b24e1c66be597ff736a1533ade41da986852f/mutagen-1.48.1.tar.gz", hash = "sha256:8f95637ab9f6f305cec6bd1294e197debe207998e3e068596563c74f86b0a173", size = 1276978, upload-time = "2026-06-25T09:47:32.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/47/d8/a29e4e3991765e7ce4ed1f7e4074fe1ba9da03e0048639734de60f9cadb9/mutagen-1.48.1-py3-none-any.whl", hash = "sha256:4f077fe87d3fc7fba259aa63d8c026b18382ca6a42ef37c61e16f1b1b5b82fe7", size = 195706, upload-time = "2026-06-25T09:47:30.296Z" }, ] [[package]] name = "mypy" version = "2.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ast-serialize" }, { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, { name = "mypy-extensions" }, { name = "pathspec" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/af/4e516a05d3ca2eb9283e9ec45b2c02225c1514dd6da49fd3c9eaa6639370/mypy-2.3.0.tar.gz", hash = "sha256:465965d41cd9a2726694e983e8ce7113259327bec798115d1e1dfa2a52fb666e", size = 3988104, upload-time = "2026-07-13T11:34:53.387Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a9/09/f2f5f45dae0c9a0891e4751a73312730e009395102e5d72a22a976cca41f/mypy-2.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1fa8d916ac3b705af733c4c1e6c9ebe38fd0d52beb15b105c3e8355b55e6ecdc", size = 14927774, upload-time = "2026-07-13T11:28:38.224Z" }, { url = "https://files.pythonhosted.org/packages/56/b9/345367effd3a6877275a94d481614bfca983f45e028c6290e2cc54603811/mypy-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:28e1e2af8cd8fff551fd30f2fe4b03fb76764ac8b1ba6c6a1bd00ad32b412db3", size = 14000127, upload-time = "2026-07-13T11:30:19.57Z" }, { url = "https://files.pythonhosted.org/packages/99/6c/a10b7a7b9f0a755fb94e27ae834d4cea9ad6c5221f9325eef8f182641feb/mypy-2.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e77244df3843048c3f927182916730e40c124cbaa43905c1fb86cb382aa0805", size = 14229437, upload-time = "2026-07-13T11:28:17.765Z" }, { url = "https://files.pythonhosted.org/packages/d9/bd/a26a602acb1bbf849fa4bdac4bc657ee2f11c0c2a764a2cc87a5304e865c/mypy-2.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9559ab18a9c9957dfa3004ab57cd4bac5f26a724329a9584e583367f0c2e1117", size = 15171457, upload-time = "2026-07-13T11:29:01.834Z" }, { url = "https://files.pythonhosted.org/packages/7f/14/124f462bef69bcbc90b9358088460b6091954a3e004852fcd9948db617a5/mypy-2.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:09abd66d8685e73f8f7d17b847c3e104d9a7b164a8706ea87d6c96a3d45816d5", size = 15478281, upload-time = "2026-07-13T11:32:23.413Z" }, { url = "https://files.pythonhosted.org/packages/db/a4/8bdca6a8ac8d856d82ed049144af2721245a135c2e8001d3890c93975852/mypy-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e91adad1ca81742ac7ef9893959911df867752206b37135185e88dfb3c89494", size = 11148008, upload-time = "2026-07-13T11:34:17.332Z" }, { url = "https://files.pythonhosted.org/packages/83/41/490eea348e60ba50decec20bc750605444149a5d7a8cc560042f90ba2c75/mypy-2.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:6f99ec626e3c3a2f7c0b22c5b90ddb5dabb1c18729c971e9bdaca1f1766d2cee", size = 10142329, upload-time = "2026-07-13T11:32:52.116Z" }, { url = "https://files.pythonhosted.org/packages/e6/b9/d75b3082b05f1b3028828aeb18e74ae5ab0a0936051bbf1f32f59f654747/mypy-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3419d00717afbc5265b50dd14b1278f29ea4884dd398ab67873489ac093fd329", size = 14838725, upload-time = "2026-07-13T11:32:44.655Z" }, { url = "https://files.pythonhosted.org/packages/a9/50/79a65c6ea6e115bc73296038a4543b2d5c91f07912b918a2c616a2514bba/mypy-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cfca8ee88544090f86b6dcce05ec55d66eb48a762412ac2507810ba4bd793b6f", size = 13911128, upload-time = "2026-07-13T11:32:02.021Z" }, { url = "https://files.pythonhosted.org/packages/90/48/e11ed7716c26953ca321f726e452e374dbf81a6f2b8b212ec02af29b6b8f/mypy-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75cbb4b9ef04a0c84a957f07abc4504fbf64b8dcc145675101f2d3a78a4b1d6a", size = 14146742, upload-time = "2026-07-13T11:33:03.313Z" }, { url = "https://files.pythonhosted.org/packages/06/72/6807565b1c4861ef66f7fdd98b51c61556356eab80235717b46c53bb8627/mypy-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:982e3d53dd23d0a4cef67dd66791fdbede0cf38f9eb617bf47663554c51e1e36", size = 15081418, upload-time = "2026-07-13T11:31:13.899Z" }, { url = "https://files.pythonhosted.org/packages/00/80/1ea14c5d80e589e415973db3e47c78c2219a305b808b2b506395342c1d79/mypy-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85c5385b93012ffa3b31479ab579aef5415f4f3a32c6cf1ae07a984d2a0ff461", size = 15328164, upload-time = "2026-07-13T11:31:35.723Z" }, { url = "https://files.pythonhosted.org/packages/37/28/8223157404a3d51920078459c37f80fbdc590e1d8ea049dc5ce48643022a/mypy-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:13b1b16e2fa39f3b2e33fb1c468abc7a69369fa2e886b4b87b5afc81472325cd", size = 11136472, upload-time = "2026-07-13T11:27:37.018Z" }, { url = "https://files.pythonhosted.org/packages/6f/cc/ea27e5959c5f258585a756b252031f3b313583d81b5064b2bebc41d3706b/mypy-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:b5cd2f027a972a4a5f2278a11fac9747f5f81a53a30b714d74950b6807e55568", size = 10135800, upload-time = "2026-07-13T11:30:08.92Z" }, { url = "https://files.pythonhosted.org/packages/dc/94/0e7e592619e2133596a47cdd642534b0456545c218430bd3b9d8fefdd1b1/mypy-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d53fc67b9d28a43c6199077f49fea0f05839e36cf6158500331c9549225e5a5", size = 15026523, upload-time = "2026-07-13T11:34:49.206Z" }, { url = "https://files.pythonhosted.org/packages/f6/d2/1e1731df090a857df2807177a4626863e5ac0f0256513c35780efe53986f/mypy-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fbc00cee7bdbb9291979ddc9d08034a29dfcda4932628c9bbc28c1edd589df0c", size = 14032189, upload-time = "2026-07-13T11:33:57.168Z" }, { url = "https://files.pythonhosted.org/packages/44/95/cab921f4a806e171f34113e6181dd23c55358ccf6a80741269ef594a410e/mypy-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04e617030eca5221909c8b7d8d7fd1c637948199aa2100b2ad9813feb07e1491", size = 14198696, upload-time = "2026-07-13T11:32:12.767Z" }, { url = "https://files.pythonhosted.org/packages/66/80/e6d008bb19fe446e3662d85e0e2717bf9f2d611a2164fb29d6e067dbf46c/mypy-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56c184d2c20ca6b6378d58d1960270a767f41f5e44acbbd27f05effef4f4e1d7", size = 15286904, upload-time = "2026-07-13T11:34:27.594Z" }, { url = "https://files.pythonhosted.org/packages/db/83/94397c9293608a364aa03e8084fb34ede4ae976a260384b9b52929308135/mypy-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3961a4a34b05f7c74b0f05aa51fbfe99a2d1e126038df40318d15c8f558b7ef3", size = 15528342, upload-time = "2026-07-13T11:34:07.819Z" }, { url = "https://files.pythonhosted.org/packages/cf/96/d8b37d819adec6cfccfb1fd3afc1735d94717ddeafb45536db9c6943e09b/mypy-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b1942b9314d4c784b8ea1dbab4972603290e5dd5630f06675f13aec97526bc4c", size = 11218346, upload-time = "2026-07-13T11:28:27.745Z" }, { url = "https://files.pythonhosted.org/packages/2b/cd/cd9f725b19b19e5b530a154cf9bcf9e94279c5d55b3c34fb42b3aa48ea1b/mypy-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:be51653d7669d7d7955d613b8d0bb57d5b652eaf71a873ddf65ac87254dd2595", size = 10204525, upload-time = "2026-07-13T11:31:02.552Z" }, { url = "https://files.pythonhosted.org/packages/6e/ae/f7d056eb0294586a572d0d0d89580ec633c064db520f11d37d5a2fb833bd/mypy-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:91ad22a52ae2c7e621c2f67c94d5a17f66b3209a4cff5cf8a573579835c69e97", size = 14947298, upload-time = "2026-07-13T11:27:47.734Z" }, { url = "https://files.pythonhosted.org/packages/32/d5/db3e7af01e7844d21662c6ddc1f7825ec7cb4053f0391ac02faf3638396f/mypy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:99ac767cc5d3b64c8d0ae226ead10c96694f94e4e7da1668642225dcd4e75aac", size = 13950768, upload-time = "2026-07-13T11:27:57.726Z" }, { url = "https://files.pythonhosted.org/packages/d9/fb/43c031f0190513d1ec248ed037eceb742ddd2a4d74bbf406658a28173837/mypy-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de6d2c484742a4d7b0ed6d07b143375624d3b899c5749c7b3c947f56261f48a6", size = 14151586, upload-time = "2026-07-13T11:29:18.615Z" }, { url = "https://files.pythonhosted.org/packages/ec/c3/f8b2ffc60883084da91be51af58e88a7ffd4ff9795acb7d902ff88d31eb1/mypy-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7da939dd335cfd2ad788bdfd081c9f4e47634ab995e5a45eb15fd1e5bc052f8b", size = 15227411, upload-time = "2026-07-13T11:30:29.904Z" }, { url = "https://files.pythonhosted.org/packages/83/2e/16b917fc7adcf03f1aadddfc93aab804ffb234b1ab09c0ffd6d92a5d34a2/mypy-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7247eb2824f996722a949530183394921ca71deb9680052a338cf53cff7925c2", size = 15478790, upload-time = "2026-07-13T11:33:14.686Z" }, { url = "https://files.pythonhosted.org/packages/c0/88/aaa65a93c73d0cdae7e42f8adb302bf6885bb281302084f99d0290a35347/mypy-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:75b0984bb3cbd76bb5c9291a8671f7ae66ca3b51c7584c358fc2e923259f0757", size = 11234919, upload-time = "2026-07-13T11:33:39.28Z" }, { url = "https://files.pythonhosted.org/packages/35/19/b40de63f1a80e63bc2d40f0679a6a8dbd34e95176c8122119bdf406aa552/mypy-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:d78fcf900b59cb7e82cb7e3a235e31b462d9333d92285bd1e4952d355b8ffba1", size = 10201510, upload-time = "2026-07-13T11:31:52.619Z" }, { url = "https://files.pythonhosted.org/packages/a4/58/fa0ae047da911f540284009b4f44b96fe09d83c076d7c103e9d645f46303/mypy-2.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ea317b060ce83e26050f8f9e4d7d6bf44ed7597c8ff9990bccffbb9d1d8522db", size = 14941909, upload-time = "2026-07-13T11:32:34.332Z" }, { url = "https://files.pythonhosted.org/packages/15/14/2ba1d61452d7c2a7fe12741e8d374e52b183476b07aa7f9e2a0d02b0720a/mypy-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:094af99f92638aa92852326188b85a89e50f4a472f44827c03362228482f0762", size = 13967581, upload-time = "2026-07-13T11:30:00.587Z" }, { url = "https://files.pythonhosted.org/packages/ed/5a/483fb9e5ffbbb1a28dccc7b0a13d141b17ac769b6c9f488c0a0c63698962/mypy-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de121747278144fc9ae7caa2e978cf5df12aebc82933182f5b3b86081a30baef", size = 14168807, upload-time = "2026-07-13T11:28:48.6Z" }, { url = "https://files.pythonhosted.org/packages/ae/77/70d7a10732063beb74ad713682cf871e88f5c5fa39bfc8beff8a524bf9cb/mypy-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37fa4de896a84e2dc9200d91e614c22563b43d1a266789d4bbac7b22ebe6192b", size = 15200144, upload-time = "2026-07-13T11:31:25.283Z" }, { url = "https://files.pythonhosted.org/packages/56/72/766218ac783be4fdfcd699b90037b63017348a3e86fb2c1fbfb18302637d/mypy-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f1b3a98dfd21058bc759bb3337d5d1f61d0fdf9f3cf9c00f4291790fb5427bff", size = 15460389, upload-time = "2026-07-13T11:29:29.077Z" }, { url = "https://files.pythonhosted.org/packages/38/4e/8a9db7411ecb8ec0cb1fd05dba432f28bafffcd38b4e887714a4a0506689/mypy-2.3.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:944c665d984157cb96a679dfb7a4a81dd1d36b24b9c284b699514e6e626b82d4", size = 7753664, upload-time = "2026-07-13T11:29:08.147Z" }, { url = "https://files.pythonhosted.org/packages/65/4c/c3f8bfd6ed0e5e38b5a244403b27f821d433443df5a15a278417c10a3a3c/mypy-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:4359424140d985192c778c1ce2c114a10c1ca58a381ed79cfa70d37df94b299f", size = 11417237, upload-time = "2026-07-13T11:33:47.467Z" }, { url = "https://files.pythonhosted.org/packages/3c/00/89a32eaf5ccf174bc4f90db0eaea5d70636c01b8d49f384bdab2e8834390/mypy-2.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:3dd0bed92c4bdec57c42505b96416fb9e6a5aa7be84d2809bcd5f2ecec2860d7", size = 10389252, upload-time = "2026-07-13T11:31:43.81Z" }, { url = "https://files.pythonhosted.org/packages/31/56/104f93d69aa9f339b6b9d3b0a7faa699b8b466c942cf3ae86cc2a2ec0915/mypy-2.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:691fdc37132b1ae628d834f672e74de83462d9fb4aff621835767fb43a8dd373", size = 16385495, upload-time = "2026-07-13T11:29:49.818Z" }, { url = "https://files.pythonhosted.org/packages/d2/03/f1d2123313f55efafdd27706960f43a771c62f1b68426c76043f3ab9ebf3/mypy-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:aec15d465d477558fd842757b487849007311cf3897849cdda0e3162ac0ac556", size = 15098155, upload-time = "2026-07-13T11:30:40.301Z" }, { url = "https://files.pythonhosted.org/packages/e5/5d/d5f9200399b445e81726c4f23becee33f233aee81c72680b1ef3a258b641/mypy-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b352b7e49f5e6576009e8df730e1ff4f915cb565b851b396d2ffe2f5a6f5da88", size = 15514155, upload-time = "2026-07-13T11:34:38.569Z" }, { url = "https://files.pythonhosted.org/packages/cd/ce/69977c555f08faa3190cfde44189b89dbd56861b1ab97aa18fc5f3a2e4a3/mypy-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c6c6bf687b17f90dbfcad95b960d32eaa0154c00da45f03ab50bf8952e047fe", size = 16766351, upload-time = "2026-07-13T11:33:29.195Z" }, { url = "https://files.pythonhosted.org/packages/bc/92/6648b6caa3ab9e00f9ac0c2a78307805f873dd48139b24a6f6f7c3667bbf/mypy-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f4ed18f111bfe2d599bca7468e7f9251042c1c2118f762c8de2766a56d773c60", size = 17043490, upload-time = "2026-07-13T11:30:53.927Z" }, { url = "https://files.pythonhosted.org/packages/7c/ab/0dc91d80f3f016634c68d451f294a97320fe903a9b6f90b9e57b3f7f1717/mypy-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0b025a93cffb9781d231f232be07a17912f35f10a313c24f301c81e842870654", size = 12146869, upload-time = "2026-07-13T11:29:38.874Z" }, { url = "https://files.pythonhosted.org/packages/85/b5/4c964d02634ba81f4d1c84838e5c5b18ab06d13ed568960f5d6318495ccc/mypy-2.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:adebc76aab4f3495a88b41d48aa4aff0c03f2822501da76625afcca5975f19e5", size = 10965113, upload-time = "2026-07-13T11:28:07.056Z" }, { url = "https://files.pythonhosted.org/packages/2c/fa/fdc54fe583ba3cafbcedfb70eeeaf03849f75b1827a07096c7bd996f582d/mypy-2.3.0-py3-none-any.whl", hash = "sha256:6b1cdb579446b60432432b2b2403a6201b4b475a004d7f488511c9ba177c9e88", size = 2753292, upload-time = "2026-07-13T11:33:18.48Z" }, ] [[package]] name = "mypy-extensions" version = "1.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] [[package]] name = "narwhals" version = "2.24.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2b/1d/58946e5aab18393e793bd4add6985b95d0e01c3a2d832f38f54468b10dcd/narwhals-2.24.0.tar.gz", hash = "sha256:b5c0f684ccd9d7475b564111e319a4964abcf2baf79d3cf6b1003d06ac9b828d", size = 661143, upload-time = "2026-07-13T10:49:19.086Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/85/a5bfaebfd305ac18b57b0854d74e37e586809061a91fda62f0bd50c8518e/narwhals-2.24.0-py3-none-any.whl", hash = "sha256:42fdedf44e5b2ca7505630d45b4ac3058f38d8485cba9fe1652ca23152df7489", size = 461030, upload-time = "2026-07-13T10:49:17.571Z" }, ] [[package]] name = "natsort" version = "8.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e2/a9/a0c57aee75f77794adaf35322f8b6404cbd0f89ad45c87197a937764b7d0/natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581", size = 76575, upload-time = "2023-06-20T04:17:19.925Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c", size = 38268, upload-time = "2023-06-20T04:17:17.522Z" }, ] [[package]] name = "numba" version = "0.66.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "llvmlite" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/a0/570e3dc53e5602b49108f62a13e529f1eec8bfc7ef37d49c825924dcf546/numba-0.66.0.tar.gz", hash = "sha256:b900e63a0e26c05ea9a6d5a3a5a0a177cb64c5011887bf43edb8c3ed2c38d363", size = 2806181, upload-time = "2026-07-01T23:12:46.36Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/48/d139bde40f2359351bfe26ee1b261937f458ac177ab810d4f045ae1c9d92/numba-0.66.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:27951c47e0def9bf8afe580eb961102902e2fd23cb77924b7d9d7cc0f8b444cb", size = 2727368, upload-time = "2026-07-01T23:12:04.282Z" }, { url = "https://files.pythonhosted.org/packages/36/e4/b780bfa9191410da50ba249cb3248a75014e17f611e72709cbddcb21f42d/numba-0.66.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc408c54b450f41582f4be1608f8981c1dcc44c7f40355cc150dd93015753407", size = 3803554, upload-time = "2026-07-01T23:12:06.379Z" }, { url = "https://files.pythonhosted.org/packages/1c/b2/a051b96626bdf5c4d8fa6b8d450605c09638d85dc872ab63ef9a67096dca/numba-0.66.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c14c044c06b453ec3fa7715dfe75425e2ba72c73377a7ffde6d9ec511dfd94c", size = 3510065, upload-time = "2026-07-01T23:12:08.051Z" }, { url = "https://files.pythonhosted.org/packages/34/01/24dcdc3e919522e2efbd92969c281ff40deb1d5f8a994bcd0057081c158c/numba-0.66.0-cp310-cp310-win_amd64.whl", hash = "sha256:2338cc0d43609fe448930848fd35a5bc688761b986f81b597a6f45cc0f8c9577", size = 2780379, upload-time = "2026-07-01T23:12:09.772Z" }, { url = "https://files.pythonhosted.org/packages/9e/02/970796b4daa709604cde22e87a7cda9bde473c278ea4a75f59fe38cee47f/numba-0.66.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:bbd531c327557a9004507fa6bff06c53ab51a7a5776b75261bb9cef1efe2b2ea", size = 2727049, upload-time = "2026-07-01T23:12:11.296Z" }, { url = "https://files.pythonhosted.org/packages/8c/99/33a6ed9c1a0b5e42efa98eb0edf617d61dca576c82625947377b1d4540c9/numba-0.66.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc6629becb21a867d85401ec89f426dd24c484a4193ade8a38309debfd1529ca", size = 3808870, upload-time = "2026-07-01T23:12:12.944Z" }, { url = "https://files.pythonhosted.org/packages/04/20/8c51126025211659235b8de2866dfa226984ae0c8273461a3cf374716741/numba-0.66.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aac69f3ccb8af100f5913c1241edc9692bad1cdd2508721713f426eb06c9a659", size = 3514498, upload-time = "2026-07-01T23:12:15.307Z" }, { url = "https://files.pythonhosted.org/packages/5e/c9/9476940bc6d5caf5c0cf2e4c5feecbf01244bbe6f914614082dd7a3e520e/numba-0.66.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb601841d9e02e6237bb6522e36d0741614be3cfe2b482a6f00a41b5ba209443", size = 2780225, upload-time = "2026-07-01T23:12:16.924Z" }, { url = "https://files.pythonhosted.org/packages/62/a3/70deb7f88461c1cd5d16aa990c2380604102661a427667b8950dcdccc27f/numba-0.66.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:53ca5900b7cab15109796030113a6b28576bae5ad7bb507ad6dd1360ddd81ba4", size = 2727264, upload-time = "2026-07-01T23:12:18.669Z" }, { url = "https://files.pythonhosted.org/packages/2d/55/25c319845e9a4e08f16611ddbda56a192eb7b6ed13e1a2bff2da272ffb97/numba-0.66.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0999e3ee1b18c48e1fb51d11af35ef59852c7f4f50569c9550c25faef0616ad1", size = 3866252, upload-time = "2026-07-01T23:12:20.429Z" }, { url = "https://files.pythonhosted.org/packages/71/ef/a82d6fd6bf1b0fe461651e924d3647eeec9ac17f8eee4896264bf7480930/numba-0.66.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efe0d2d5099790df945e0cb6e1b3104bd965d7bbfac50d62f1d5d1d6ade0825d", size = 3566974, upload-time = "2026-07-01T23:12:22.116Z" }, { url = "https://files.pythonhosted.org/packages/fc/eb/9e6171e378822ab191c7abcfd3d8cfc8644516f6c7834c22e210e4acc070/numba-0.66.0-cp312-cp312-win_amd64.whl", hash = "sha256:b075a4e7ebc43dc6294f223e2821659656209fd5e0ce53245877c23d66d6e1a9", size = 2797403, upload-time = "2026-07-01T23:12:23.724Z" }, { url = "https://files.pythonhosted.org/packages/03/52/176c02d005c5c5143cde10a85bbcdcb6236d9e34c3aac089380e0506cd1d/numba-0.66.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:380b2556a2019ccd1e956ae77dd257eaa39403f7520768b626d44b755112785e", size = 2727084, upload-time = "2026-07-01T23:12:25.434Z" }, { url = "https://files.pythonhosted.org/packages/44/b5/e930010965568fe7f2c6c962fd2849d458cb9f62c3ab7584af8a19a2b40a/numba-0.66.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:939316d5d8619751207b8972a67852b5a7646665298cb4de693cd6bf135152f4", size = 3873663, upload-time = "2026-07-01T23:12:27.308Z" }, { url = "https://files.pythonhosted.org/packages/d0/ec/5b51457cbe96e4831141d83e892e65191b23a1b78728456c62909d231ace/numba-0.66.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cdf506775d9f02eb92a87bf5c5b1e0d25506fd18cafd769f4ed914a8feac73e7", size = 3573529, upload-time = "2026-07-01T23:12:28.944Z" }, { url = "https://files.pythonhosted.org/packages/83/7e/cea7710e96913d3c7f2999f16db1b28e6c5be5171cbf40f77f98333a7243/numba-0.66.0-cp313-cp313-win_amd64.whl", hash = "sha256:c5bfe5350284509ab0474390321454c3a8627a188af5b68c910e83df3e2db4a7", size = 2797247, upload-time = "2026-07-01T23:12:30.774Z" }, { url = "https://files.pythonhosted.org/packages/96/7a/7e0e73550eb4e41ede6e72fb5371f4539537a4d770a3b73fa9b61aea0622/numba-0.66.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:46ae5f2b19e2af3c33c2df100306a90ea2f981c8158b0390f8bf6c20eee7357e", size = 2727296, upload-time = "2026-07-01T23:12:32.39Z" }, { url = "https://files.pythonhosted.org/packages/0f/26/885774c006de6620ed3d10f45d8e20fe0b8e6aad6d573211a2cbc8b3e528/numba-0.66.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e2b101f23b8b63978d334574d2039f27f0dccfe1d891756f33a2e2f3e4c88cf4", size = 3842720, upload-time = "2026-07-01T23:12:33.938Z" }, { url = "https://files.pythonhosted.org/packages/93/99/edebf7de890b73973d839dd971cf73734adfb81ffa1b4504f84b9059c3e5/numba-0.66.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63b943eb2c9ba371908ce2cd6dfc643db51fc40f7966993376a1701bc922f537", size = 3543537, upload-time = "2026-07-01T23:12:35.566Z" }, { url = "https://files.pythonhosted.org/packages/66/c5/b46ad28ac3681d035ea21365c5e052149062e1a0a9affd0563d2760ea6ff/numba-0.66.0-cp314-cp314-win_amd64.whl", hash = "sha256:bd57790acd20f6a468e0ad333ef6b82355e309a92310fb7dff80e919f01a21a9", size = 2799250, upload-time = "2026-07-01T23:12:37.154Z" }, { url = "https://files.pythonhosted.org/packages/10/6f/5e77a7397a37dd16f57a7b72e7e470db5227b68e3639df0d13a8e674883d/numba-0.66.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:db7735d15ea17a283d6485b9fa3504769f78fd86e5146638ad5e8da57c031b9e", size = 2730342, upload-time = "2026-07-01T23:12:38.758Z" }, { url = "https://files.pythonhosted.org/packages/39/fd/e9c9680a3813f3d781c20e5d53c1074801b787d4feecca0472fdd7c05ce1/numba-0.66.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:651a2b53298340956db26ecbe7ab043106b50a40c2807e66d617a4917245a4ab", size = 3878695, upload-time = "2026-07-01T23:12:40.302Z" }, { url = "https://files.pythonhosted.org/packages/61/3a/9b363287b85fcd4537ea3878793822878b2ac1008a78159d2096fea628de/numba-0.66.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c1144ba1720ea59ad79f4f488ed54d149b2613b357f7e445678b7d0739c70e9", size = 3596323, upload-time = "2026-07-01T23:12:42.805Z" }, { url = "https://files.pythonhosted.org/packages/4c/f2/dca53d50b8f2289dd01954ace9da261e0487d5b74b188b4304e4ecc3492c/numba-0.66.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d426178fb991a85714c43112a8ea7b9d9579ea856ad8dcdb9c1c3941903ba5be", size = 2804772, upload-time = "2026-07-01T23:12:44.399Z" }, ] [[package]] name = "numpy" version = "2.2.6" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, ] [[package]] name = "numpy" version = "2.4.6" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" }, { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" }, { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" }, { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" }, { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" }, { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" }, { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" }, { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" }, { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" }, { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" }, { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" }, { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" }, { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" }, { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" }, { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" }, { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" }, { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" }, { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" }, { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" }, { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" }, { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" }, { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" }, { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" }, { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" }, { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" }, { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" }, { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" }, { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" }, { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" }, { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" }, { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" }, { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" }, { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" }, { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" }, { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" }, { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" }, { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" }, { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" }, { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" }, { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" }, { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" }, { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" }, { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, ] [[package]] name = "oauthlib" version = "3.3.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, ] [[package]] name = "packaging" version = "26.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, ] [[package]] name = "pathspec" version = "1.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] [[package]] name = "pillow" version = "12.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/25/c2/669d88644cddb1485bd9534e63e8cf476c8e51cb3c3a1297677023505c0e/pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a", size = 5392418, upload-time = "2026-07-01T11:53:27.808Z" }, { url = "https://files.pythonhosted.org/packages/6b/ba/3762f376a2948e3036488d773a146e0ae6ecc2ca03ac20e2615bd0b2ba02/pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7", size = 4785287, upload-time = "2026-07-01T11:53:29.761Z" }, { url = "https://files.pythonhosted.org/packages/07/50/b5d688cc9c52d4482f3d5bcab6ce20bc2a74a85d2343841c907444a3be2c/pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f", size = 6253754, upload-time = "2026-07-01T11:53:32.298Z" }, { url = "https://files.pythonhosted.org/packages/4e/89/36f4cd76cf4baf05c50ababb976249153f18c959171c7f6ba09a6f217260/pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec", size = 6925605, upload-time = "2026-07-01T11:53:34.487Z" }, { url = "https://files.pythonhosted.org/packages/eb/c0/4de58cf6633b9e3a6061ef4be6fb91fc3c90b812ece886f531e3c523d777/pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468", size = 6327788, upload-time = "2026-07-01T11:53:36.433Z" }, { url = "https://files.pythonhosted.org/packages/87/3c/14d53682a19550dbbaf3b598f807d5457646c510805a44c7d7891cd1cd1a/pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed", size = 7036288, upload-time = "2026-07-01T11:53:38.712Z" }, { url = "https://files.pythonhosted.org/packages/38/1d/36279e3c77efe034e4cc2b0393ee74ffdb5a62391dacbf9b916154f5f0b8/pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1", size = 6472396, upload-time = "2026-07-01T11:53:40.781Z" }, { url = "https://files.pythonhosted.org/packages/48/7c/8fa0039574c476d7c6fa57dd7c32a130436877c6ec1e5ce1cc8ec44878c1/pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb", size = 7226887, upload-time = "2026-07-01T11:53:42.764Z" }, { url = "https://files.pythonhosted.org/packages/fa/17/e324be141d173c1c919428066c3259f21c1b8982e564e01a4a81e96dbdcf/pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f", size = 2568039, upload-time = "2026-07-01T11:53:45.372Z" }, { url = "https://files.pythonhosted.org/packages/fb/c8/0a78b0e02d7ac54bc03e5321c9220da52f0c2ea83b21f7c40e7f3169c502/pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756", size = 5392415, upload-time = "2026-07-01T11:53:47.162Z" }, { url = "https://files.pythonhosted.org/packages/b2/5b/a02d30018abd97ced9f5a6c63d28597694a00d066516b9c1c6de45859fc9/pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6", size = 4785266, upload-time = "2026-07-01T11:53:49.079Z" }, { url = "https://files.pythonhosted.org/packages/c8/98/766667a4be768150a202836acd9fad19c06824ca86c4286d3cf6b274964e/pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd", size = 6263814, upload-time = "2026-07-01T11:53:51.32Z" }, { url = "https://files.pythonhosted.org/packages/3b/2d/ede717bc1144f63886c21fd349bb95860b0d1a21149ff16f2bb362b612b6/pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd", size = 6934408, upload-time = "2026-07-01T11:53:53.487Z" }, { url = "https://files.pythonhosted.org/packages/a3/48/9c58b685e69d49c31af6c8eb9012055fab7e665785165c84796e2c73ce72/pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c", size = 6337160, upload-time = "2026-07-01T11:53:55.457Z" }, { url = "https://files.pythonhosted.org/packages/ff/fa/dc2a5c0ba6df93f67c31d34b808b7ce440b40cdbf96f0b81cde1d1e6fa93/pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5", size = 7045172, upload-time = "2026-07-01T11:53:57.736Z" }, { url = "https://files.pythonhosted.org/packages/86/a5/444817a4d4c4c2417df00513086ca196f388d8f9ef40c2e4ccd1ad1af54b/pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b", size = 6472232, upload-time = "2026-07-01T11:53:59.767Z" }, { url = "https://files.pythonhosted.org/packages/63/c6/4bad1b18d132a50b27e1365e1ab163616f7a5bb56d330f66f9d1d9d4f9d4/pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a", size = 7233653, upload-time = "2026-07-01T11:54:02.066Z" }, { url = "https://files.pythonhosted.org/packages/fd/16/00f91ab7760dc842f5aad55217e80fc4a7067a0604535249bc8a2d6d9870/pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26", size = 2568195, upload-time = "2026-07-01T11:54:04.622Z" }, { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" }, { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" }, { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" }, { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" }, { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" }, { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" }, { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" }, { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" }, { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" }, { url = "https://files.pythonhosted.org/packages/9d/ac/31fb64e1e7efb5a4b50cd3d92049ba89ac6e4d8d3bb6a74e15048ca3353e/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89", size = 4161684, upload-time = "2026-07-01T11:54:25.934Z" }, { url = "https://files.pythonhosted.org/packages/87/b4/9805e23d2b4d77842b468513841fda254ee42f0289d25088340e4ff46e2d/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace", size = 4255487, upload-time = "2026-07-01T11:54:27.935Z" }, { url = "https://files.pythonhosted.org/packages/df/39/ecf519435a200c693fe053a6ee4d835b41cf963a4dfc2551c4e637cb2a71/pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec", size = 3696433, upload-time = "2026-07-01T11:54:29.813Z" }, { url = "https://files.pythonhosted.org/packages/42/92/2fc3ffad878ae8dd5469ec1bc8eb83b71f48e13efdf68f02709003982a32/pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66", size = 5345889, upload-time = "2026-07-01T11:54:31.97Z" }, { url = "https://files.pythonhosted.org/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35", size = 4780109, upload-time = "2026-07-01T11:54:34.026Z" }, { url = "https://files.pythonhosted.org/packages/1f/01/e18aff37cb0b4aac47ac90f016d347a49aca667ef97f190b06ac2aabc928/pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65", size = 6263736, upload-time = "2026-07-01T11:54:36.131Z" }, { url = "https://files.pythonhosted.org/packages/f7/62/de5bdd77d935331f4f802edc11e4d82950f642caad6cb2f949837b8560e2/pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3", size = 6937129, upload-time = "2026-07-01T11:54:38.216Z" }, { url = "https://files.pythonhosted.org/packages/70/4d/105627a13300c5e0df1d174230b32fd1273062c96f7745fd552b945d1e1d/pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a", size = 6339562, upload-time = "2026-07-01T11:54:40.354Z" }, { url = "https://files.pythonhosted.org/packages/6b/1d/f13de01a553988ab895ba1c722e06cf3144d4f57656fd5b81b6d881f1179/pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e", size = 7049439, upload-time = "2026-07-01T11:54:42.489Z" }, { url = "https://files.pythonhosted.org/packages/c9/f9/066794cca041b969964f779ee5fa66a9498bbf34248ac39c5d7954e4198f/pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f", size = 6473287, upload-time = "2026-07-01T11:54:44.9Z" }, { url = "https://files.pythonhosted.org/packages/a6/9b/7a58e61d62be561da3a356fe2384d4059a6345fc130e23ef1c36a5b81d24/pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8", size = 7239691, upload-time = "2026-07-01T11:54:47.141Z" }, { url = "https://files.pythonhosted.org/packages/aa/b0/c4ed4f0ef8f8fa5ee8351537db6650bb8189f7e118842978dd6589065692/pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b", size = 2568185, upload-time = "2026-07-01T11:54:49.137Z" }, { url = "https://files.pythonhosted.org/packages/dc/01/001f65b68192f0228cc1dbbc8d2530ab5d58b61037ba0587f946fea607cd/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330", size = 4161736, upload-time = "2026-07-01T11:54:51.156Z" }, { url = "https://files.pythonhosted.org/packages/1a/d2/0219746d0fd16fc8a84498e79452375be3797d3ce4044596ce565164b84f/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217", size = 4255435, upload-time = "2026-07-01T11:54:53.414Z" }, { url = "https://files.pythonhosted.org/packages/c8/02/8d0bc62ef0302318c46ff2a512822d2610e81c7aa46c9b3abe6cbaca5ad0/pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930", size = 3696262, upload-time = "2026-07-01T11:54:55.739Z" }, { url = "https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8", size = 5350344, upload-time = "2026-07-01T11:54:57.657Z" }, { url = "https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0", size = 4780131, upload-time = "2026-07-01T11:54:59.713Z" }, { url = "https://files.pythonhosted.org/packages/b1/9d/8b2c807dbef61a5197c047afe99823787eb66f63daf9fb2432f91d6f0462/pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321", size = 6263757, upload-time = "2026-07-01T11:55:01.778Z" }, { url = "https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b", size = 6936962, upload-time = "2026-07-01T11:55:03.93Z" }, { url = "https://files.pythonhosted.org/packages/18/7e/e483414b35800b86b6f08dbbc7803fb5cd52c4d6f897f47d53ea2c7e6f65/pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198", size = 6339171, upload-time = "2026-07-01T11:55:05.989Z" }, { url = "https://files.pythonhosted.org/packages/f0/f4/68c491844841ede6bed70189546b3ee9731cf9f2cbad396faff5e1ccba45/pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130", size = 7048116, upload-time = "2026-07-01T11:55:08.131Z" }, { url = "https://files.pythonhosted.org/packages/a3/34/77f3f793fed8efc7d243f21b33c5a3f0d1c97ee70346d3db855587e155ff/pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a", size = 6467209, upload-time = "2026-07-01T11:55:10.408Z" }, { url = "https://files.pythonhosted.org/packages/f1/e0/492879f69d94f91f60fc8cd05ba03650e9520afebb2fb7aa12777d7c7f38/pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d", size = 7237707, upload-time = "2026-07-01T11:55:12.745Z" }, { url = "https://files.pythonhosted.org/packages/c9/ac/6b11f2875f1c2ac040d84e1bbf9cf22a88038f901ca1037898b280b38365/pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838", size = 2565995, upload-time = "2026-07-01T11:55:14.736Z" }, { url = "https://files.pythonhosted.org/packages/52/69/c2208e56af9bfc1913afb24020297a691eb1d4ef688474c8a04913f65e04/pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e", size = 5352503, upload-time = "2026-07-01T11:55:17.076Z" }, { url = "https://files.pythonhosted.org/packages/07/70/e5686d753e898a45d778ff1718dba8516ead6ab6b95d85fc8c4b70650cf2/pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17", size = 4782956, upload-time = "2026-07-01T11:55:19.448Z" }, { url = "https://files.pythonhosted.org/packages/d5/37/25c6692f06927ee973ff18c8d9ee98ad0b4d84ee67a09610c2dd1447958e/pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385", size = 6322855, upload-time = "2026-07-01T11:55:21.613Z" }, { url = "https://files.pythonhosted.org/packages/cc/91/420637fcb8f1bc11029e403b4538e6694744428d8246118e45719f944556/pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c", size = 6989642, upload-time = "2026-07-01T11:55:24.006Z" }, { url = "https://files.pythonhosted.org/packages/10/08/b94d7811281ccf0d143a1cf768d1c49e1e54af63e7b708ab2ee3eb87face/pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d", size = 6391281, upload-time = "2026-07-01T11:55:26.252Z" }, { url = "https://files.pythonhosted.org/packages/d2/87/24233f785f55474dc02ce3e739c5528a77e3a862e9333d1dd7a25cc31f70/pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931", size = 7096716, upload-time = "2026-07-01T11:55:28.318Z" }, { url = "https://files.pythonhosted.org/packages/23/26/fcb2f6e37175b04f53570b59937867e2b80ee1685e744023153028fc14f9/pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7", size = 6474125, upload-time = "2026-07-01T11:55:30.956Z" }, { url = "https://files.pythonhosted.org/packages/90/de/3634abee5f1c9e13c56787b7d5517b0ba8d6de51700b95578cf338349c9f/pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c", size = 7242939, upload-time = "2026-07-01T11:55:34.044Z" }, { url = "https://files.pythonhosted.org/packages/ce/2a/fd13f8eb24de5714a6eb444a3d67e2842c6c576e159a43793adf23051351/pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45", size = 2567506, upload-time = "2026-07-01T11:55:35.988Z" }, { url = "https://files.pythonhosted.org/packages/75/18/2e8b40223153ccbc60df07f9e8928dc0c76202aa4e55ae9f53962b6510d6/pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468", size = 5302510, upload-time = "2026-07-01T11:56:25.736Z" }, { url = "https://files.pythonhosted.org/packages/46/3e/51fabf59d5ab801ceab709453d3ab6b180083496579549de4c45ced6528a/pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94", size = 4736058, upload-time = "2026-07-01T11:56:28.041Z" }, { url = "https://files.pythonhosted.org/packages/bf/20/22fe9384b7949e25fb1293bcfc84fb82590ff4ea6b37c95b24d26d793d86/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e", size = 5237776, upload-time = "2026-07-01T11:56:30.263Z" }, { url = "https://files.pythonhosted.org/packages/08/14/f6ba68107680ffa74b39985f3f30884e41318fbc4250caa423c79b4788bb/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3", size = 5860358, upload-time = "2026-07-01T11:56:32.68Z" }, { url = "https://files.pythonhosted.org/packages/36/54/0169bc772ec491108b62f644f8ecf1fe5d8ae5ebafde2ee2142210166903/pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a", size = 7231786, upload-time = "2026-07-01T11:56:35.046Z" }, ] [[package]] name = "platformdirs" version = "4.11.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/78/9b/560e4be8e26f6fd133a03630a8df0c663b9e8d61b4ade152b72005aec83b/platformdirs-4.11.0.tar.gz", hash = "sha256:0555d18370482847566ffabcaa53ad7c6c1c29f195989ae1ed634a05f76ea1e0", size = 31953, upload-time = "2026-07-21T13:09:36.565Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7d/68/d8d58938dfb1370b266a1a729e6d77a985be23689a0496498ee17b2cbf90/platformdirs-4.11.0-py3-none-any.whl", hash = "sha256:360ccded2b7fce0af0ff80cc8f5942a1c5d99b0e856033acb030bfc634709e74", size = 23247, upload-time = "2026-07-21T13:09:35.422Z" }, ] [[package]] name = "pluggy" version = "1.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] [[package]] name = "polib" version = "1.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/10/9a/79b1067d27e38ddf84fe7da6ec516f1743f31f752c6122193e7bce38bdbf/polib-1.2.0.tar.gz", hash = "sha256:f3ef94aefed6e183e342a8a269ae1fc4742ba193186ad76f175938621dbfc26b", size = 161658, upload-time = "2023-02-23T17:53:56.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl", hash = "sha256:1c77ee1b81feb31df9bca258cbc58db1bbb32d10214b173882452c73af06d62d", size = 20634, upload-time = "2023-02-23T17:53:59.919Z" }, ] [[package]] name = "pooch" version = "1.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, { name = "platformdirs" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/83/43/85ef45e8b36c6a48546af7b266592dc32d7f67837a6514d111bced6d7d75/pooch-1.9.0.tar.gz", hash = "sha256:de46729579b9857ffd3e741987a2f6d5e0e03219892c167c6578c0091fb511ed", size = 61788, upload-time = "2026-01-30T19:15:09.649Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/2d/d4bf65e47cea8ff2c794a600c4fd1273a7902f268757c531e0ee9f18aa58/pooch-1.9.0-py3-none-any.whl", hash = "sha256:f265597baa9f760d25ceb29d0beb8186c243d6607b0f60b83ecf14078dbc703b", size = 67175, upload-time = "2026-01-30T19:15:08.36Z" }, ] [[package]] name = "psutil" version = "7.2.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, { url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" }, { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" }, { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" }, { url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" }, { url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" }, { url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" }, { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, ] [[package]] name = "py7zr" version = "1.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "backports-zstd", marker = "python_full_version < '3.14'" }, { name = "brotli", marker = "platform_python_implementation == 'CPython'" }, { name = "brotlicffi", marker = "platform_python_implementation == 'PyPy'" }, { name = "inflate64" }, { name = "multivolumefile" }, { name = "psutil", marker = "sys_platform != 'cygwin'" }, { name = "pybcj" }, { name = "pycryptodomex" }, { name = "pyppmd" }, { name = "texttable" }, ] sdist = { url = "https://files.pythonhosted.org/packages/59/3f/ac248f25f3901d3d6cf80ac99d5bac6fd1e5e6543c1812c79b02b6074c60/py7zr-1.1.3.tar.gz", hash = "sha256:8d51894abb38355bf14881088bb97f01fe4cb5b14ebe22f66d6297668c7e1a74", size = 71695, upload-time = "2026-06-19T09:28:29.339Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/88/40/dc7f804abd0ea167ea8d4d9b3f5455321aaf671d040fcef647e9e952e714/py7zr-1.1.3-py3-none-any.whl", hash = "sha256:17934a35089e026dec6c72ee275d9b841e646881ef822d618e805c3006661d9a", size = 72242, upload-time = "2026-06-19T09:28:27.512Z" }, ] [[package]] name = "pyacoustid" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "audioread" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/95/fb31647f36c33097d3fbfcb1f145977b52d841382f5e5b1f72be1f76b659/pyacoustid-1.3.1.tar.gz", hash = "sha256:bb0ecae40109c0aa80f709e33c66c83ec36b2fd84658f9fad056a34538f79e8a", size = 16424, upload-time = "2026-04-09T18:05:59.429Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/cb/87/23e9467c89f7b013481cfc0991af27cc4bb267e4524f8d78cf29d8b8ded7/pyacoustid-1.3.1-py3-none-any.whl", hash = "sha256:4436732937ac40e4b2fec4808fc81934c0e07ad9e3f0ef5f2b225517c99bb1e4", size = 13491, upload-time = "2026-04-09T18:05:58.18Z" }, ] [[package]] name = "pybcj" version = "1.0.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/14/c9/e2de4f98c21f2ff9e58047395b6a8e17701a0f2977f0e63f80948f61647f/pybcj-1.0.8.tar.gz", hash = "sha256:6818270692912d47e81ccd777b7d0ed2ad3a19ef7aaead3735b38048c80bf368", size = 31763, upload-time = "2026-07-16T22:47:24.705Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c2/72/d5b4bdf521ef8064a810a823ea45765a9001e23c0ae41aa8b3204765d087/pybcj-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d0bb3b8ca2c16aa05c4919bea35141f02c500a79d7e4eb6c34065e10b81a7f15", size = 32731, upload-time = "2026-07-16T22:46:16.901Z" }, { url = "https://files.pythonhosted.org/packages/de/f8/985a43365d980bdaf09ba28c7cbdd753b035986be94d0e72aa2ad375012f/pybcj-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3253ef9c93ea59b0d6fcac451dd7970cbc815d9e19d0af9ceb151b20975364f1", size = 24629, upload-time = "2026-07-16T22:46:18.467Z" }, { url = "https://files.pythonhosted.org/packages/f9/f0/955a527db47f3c090abf034c46c28e40f255004e5a1b76e3b3165a16a0df/pybcj-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be7a84e93d7bf22a7f89cb958dc16b6a5e8bf2d3422eb52030d41afc76fa3d23", size = 24932, upload-time = "2026-07-16T22:46:19.736Z" }, { url = "https://files.pythonhosted.org/packages/a3/35/d1adea3772829080b538d481f9e5f473fae1a5add68cf88b68098876c261/pybcj-1.0.8-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a63c91adcffb229a79f8884e36d22cc341f323c0056f3affd478d986815b157", size = 51484, upload-time = "2026-07-16T22:46:20.927Z" }, { url = "https://files.pythonhosted.org/packages/89/25/40fe93322b33685ac7b8ebdcb15b93d3a9d0707abefcab393032e27a6570/pybcj-1.0.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b68d66941fca641865b579b516a4599a346a2aad860dcd411cb5179808d88b3f", size = 50323, upload-time = "2026-07-16T22:46:22.16Z" }, { url = "https://files.pythonhosted.org/packages/5a/a3/8dee5070d1f99950995a9d5dea41e057d7eb5a14e6faf6f74ef0f613c7eb/pybcj-1.0.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd573565e5e214bdc738f9e2cf52dfac9cebe7220f88c76f8861534e4330c3a9", size = 50614, upload-time = "2026-07-16T22:46:23.363Z" }, { url = "https://files.pythonhosted.org/packages/1e/a6/2f86be99a646d49b9888115ef3833abe4187f52fc3d9066fbf9a28e41319/pybcj-1.0.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:62a3d31f4e5641771e75bd5c9498a057b0a550ca742a31d3db0634a0a4a0a115", size = 49978, upload-time = "2026-07-16T22:46:24.799Z" }, { url = "https://files.pythonhosted.org/packages/56/04/c9b5dee7004f9b9f7dfb12c9a14b0929cacf1a8410e783f1df98e77cd2f6/pybcj-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:b372f40aadb429de71cfc86ff7b8a52e753bd357eef5c03c3eb3b823709982fd", size = 24918, upload-time = "2026-07-16T22:46:26.341Z" }, { url = "https://files.pythonhosted.org/packages/53/54/7cdfb79a70fbac1756c378d793202991183c4bd911e2d9960c9390449e6a/pybcj-1.0.8-cp310-cp310-win_arm64.whl", hash = "sha256:56c48aecd6ab096e4955ecd39c9655847f2774878a969e8140641fb23c3f2d1c", size = 24237, upload-time = "2026-07-16T22:46:27.64Z" }, { url = "https://files.pythonhosted.org/packages/34/60/c96205182721cea0f5668cef3f6321b23a14ef0764bbc31a0e4773c84a8b/pybcj-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a5f977b14950ab26c9032784164719f16a4238115a8fe9ae3dcc82dab06cb208", size = 32732, upload-time = "2026-07-16T22:46:28.744Z" }, { url = "https://files.pythonhosted.org/packages/a3/4d/c20fd8f230f5b5ad3c7cce5e2e639478e16a0ac82c96c01452607e7a4bb2/pybcj-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da783c9e002826e6e4e4d6f92e49ab1a77bee5d8e6edc1b99cdee2e883d4cb56", size = 24629, upload-time = "2026-07-16T22:46:30.01Z" }, { url = "https://files.pythonhosted.org/packages/5b/d2/6e49e51df5aaebac83876414ddbde6ce45a5364488007fe49d4962248651/pybcj-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a039943fcd80f9924189949909beeca83910bf19c5602c0d7eb3582109f28628", size = 24934, upload-time = "2026-07-16T22:46:31.097Z" }, { url = "https://files.pythonhosted.org/packages/42/f2/fb31ae098739dd7a3ed131ca5e538703e37f6624a45b02dfe65d0fd29446/pybcj-1.0.8-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efa420a3565e381e15e6425a3b2887ddf2be6dc66eb1d68e79ce0f177229ebb8", size = 52555, upload-time = "2026-07-16T22:46:32.348Z" }, { url = "https://files.pythonhosted.org/packages/bf/6c/3b6ccd183d696435aae1dec4c62e8118907f5a2b0900845334ae061dabe1/pybcj-1.0.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0de1f6c90178f5947e4b578821aa2f1f87a78a761ae603aa33a8ad3d8b9b9cac", size = 51414, upload-time = "2026-07-16T22:46:33.679Z" }, { url = "https://files.pythonhosted.org/packages/71/3d/85aea36e36a336f0f0a72b6f0e97035c36b06efd34cace50f23c3ac100ec/pybcj-1.0.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6722171da5846d9374f2d55474ffd1298ff2e2b21dc6b81a7806bb17ee1c634d", size = 50614, upload-time = "2026-07-16T22:46:35.016Z" }, { url = "https://files.pythonhosted.org/packages/3c/e7/808083487bc8aaa369d9e93755dd76a88b9203f028a4d3018474754acf7e/pybcj-1.0.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cbca168d4d0aa75cca780b95f530f842b81ebc8d72f36d7865287b59364593a1", size = 50068, upload-time = "2026-07-16T22:46:36.577Z" }, { url = "https://files.pythonhosted.org/packages/e1/1c/386a50186383045293cd0e1e969a48143e0c073a18fed3dd0b7edec935e3/pybcj-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:090eb05fe7a2f7cd7eb42809616ce1b49437c3e995a8aae2faa92b66f218172f", size = 24917, upload-time = "2026-07-16T22:46:37.805Z" }, { url = "https://files.pythonhosted.org/packages/31/1e/abe31870216273249fd2e4724430d958ea28496825b7772a2e1a58c1fa03/pybcj-1.0.8-cp311-cp311-win_arm64.whl", hash = "sha256:077460a97a69ccd914d09d2a2ad493a48568b356fb14871ce54fb6bb7f3cccc2", size = 24233, upload-time = "2026-07-16T22:46:38.957Z" }, { url = "https://files.pythonhosted.org/packages/09/32/63b96b702fc4848834ce552302fbdccad92f67886eaf3fbbed530569f4a1/pybcj-1.0.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:748af4545040da68dfae8cdf9f902ac7c29f209aaf6450a970abe0302d1b0f58", size = 32798, upload-time = "2026-07-16T22:46:40.083Z" }, { url = "https://files.pythonhosted.org/packages/a2/21/0b501901021499e41afe7d0148c94ee26dcf045d3e1389bf1b42a61d11a6/pybcj-1.0.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:190e21c3bdb6b28c63999889668a3f80f5d7eb13b957f2dfda53c9ddeb3d946a", size = 24673, upload-time = "2026-07-16T22:46:41.288Z" }, { url = "https://files.pythonhosted.org/packages/b3/97/c05d5800d742f5162bd06ef790dfcf73128431328f16abe7a0e2109d8ca5/pybcj-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:384b25dfe66868329a3872c6eae668033e009e4e86754eba3a70b656c9eb4208", size = 24958, upload-time = "2026-07-16T22:46:42.469Z" }, { url = "https://files.pythonhosted.org/packages/05/0f/9db13432a6f8878f90c108a68fda46e832eea53585cb5dee8bdbc9472467/pybcj-1.0.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b480efcd66cfb4533ede6c3d67224ff477c8dd661613826edff9c95921a562d6", size = 53297, upload-time = "2026-07-16T22:46:43.93Z" }, { url = "https://files.pythonhosted.org/packages/76/59/5629811698e6cfaea6cf159cf86fa471904ceb60448dc8b80233bba2e392/pybcj-1.0.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a50b58f9b9d9978c55e3219b6816a1021a778b028a810b36aa754407591cb5ae", size = 52332, upload-time = "2026-07-16T22:46:45.252Z" }, { url = "https://files.pythonhosted.org/packages/b2/0a/c5bd982957b5fd785f02dffcb3f6f45a93143e1e8ccc8224e19b3915fc84/pybcj-1.0.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1997badf9e59221470f84e193ac8c1bab158acfe6b058ffdc28c331807967ff9", size = 51192, upload-time = "2026-07-16T22:46:46.674Z" }, { url = "https://files.pythonhosted.org/packages/7a/79/1d421d2d45e565a0f8eab8ce6f795e31beca96f658c1e483dac64a466a28/pybcj-1.0.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f0818cf48fbfddbae487536f3fcd69cfadfb7293630ab8658b66e89a0836d6a", size = 50849, upload-time = "2026-07-16T22:46:48.006Z" }, { url = "https://files.pythonhosted.org/packages/7b/c3/daddd6edc01689b1cb75733bd3098231bae20c9e77d7022dc0b1c40e56fd/pybcj-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:26e3e4d287f306996902289fc0e88b36d0fc817802f4fc4537b40a6518726585", size = 24956, upload-time = "2026-07-16T22:46:49.159Z" }, { url = "https://files.pythonhosted.org/packages/a7/fc/9c668e2cd1432f7ede31bc131ab336c8602659374bc731bfaca6cf208bbe/pybcj-1.0.8-cp312-cp312-win_arm64.whl", hash = "sha256:82d2e46eff6c3fe8d16f6515f9ab0598eb960af9a2218907c5e0e9f993d7a666", size = 24251, upload-time = "2026-07-16T22:46:50.33Z" }, { url = "https://files.pythonhosted.org/packages/25/c1/9d8822f1b97813f21b5907b351edb0f607c9736e21637812edf407a2dae6/pybcj-1.0.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f0e496c49dce294fb41a2221e7b3f96156bb940d8cfe359d441909f1cf241ea", size = 32799, upload-time = "2026-07-16T22:46:51.625Z" }, { url = "https://files.pythonhosted.org/packages/6f/8b/248154c815e683c0f991c471bedb7476d7c91fd8a56918f1ef66d2341ea5/pybcj-1.0.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0657c9534d480a43b11743cad4209d140d09d417adaf19213ff395686ed08812", size = 24673, upload-time = "2026-07-16T22:46:52.799Z" }, { url = "https://files.pythonhosted.org/packages/e0/f7/f168c7b091fc41fc7ef6d9ed6cde2ec10bb4814f14ad21b493881476636e/pybcj-1.0.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:784443d0c075871689692679ef01cfe85eca789cc8d091f842fa02f62dead9d5", size = 24955, upload-time = "2026-07-16T22:46:54.069Z" }, { url = "https://files.pythonhosted.org/packages/cc/a1/7b802ee7c7730521a102dadbdf944943795b3e9ca3ca665dbbdd1213f781/pybcj-1.0.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9195ce382f21e13df7ecc0df8fb42c5f391a7ac516066af16b023e6bd2f86046", size = 53344, upload-time = "2026-07-16T22:46:55.272Z" }, { url = "https://files.pythonhosted.org/packages/4b/cf/c4b0248051cdb7af7f38223db63427175e755db1f1a7905e781e923f6d53/pybcj-1.0.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e5e67ec32176985bbf941185319a3fe385527b6826d457a8ec67dd43b5f0b5fa", size = 52410, upload-time = "2026-07-16T22:46:56.541Z" }, { url = "https://files.pythonhosted.org/packages/52/77/9afed44c590a19940e04fdf38b7f55e7db3a8b35e3f6320340d99be25ca8/pybcj-1.0.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:20b657e4fe3e701a0f64a7c1224694820687334b17593d74a878f7124f10b24f", size = 51282, upload-time = "2026-07-16T22:46:57.748Z" }, { url = "https://files.pythonhosted.org/packages/10/4b/7eaf8cf0ad598cc2035a24186a3e2bf45ec798279dad58484d0eb940d4b3/pybcj-1.0.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5b4c66b5358cd241b6ff81a8fafd5806e816d378c810a796ad51865be5533f7", size = 50935, upload-time = "2026-07-16T22:46:58.94Z" }, { url = "https://files.pythonhosted.org/packages/39/f4/04d46f5059af00d2fae6086a7f47ebc23e553900ca75ea2a2e276d3a436c/pybcj-1.0.8-cp313-cp313-win_amd64.whl", hash = "sha256:e47d9c655d276200e5d08f7b550097dacc826364b44931f0fbdc0da2e4bdf448", size = 24956, upload-time = "2026-07-16T22:47:00.127Z" }, { url = "https://files.pythonhosted.org/packages/63/cc/387af6844cdc53be20a9271998bc4a15a96360f06ce8829193d4a45f6b19/pybcj-1.0.8-cp313-cp313-win_arm64.whl", hash = "sha256:f561988aef99f07e991d0708ca6fe86e766d545c0a20e58bdbd38615a615e419", size = 24249, upload-time = "2026-07-16T22:47:01.28Z" }, { url = "https://files.pythonhosted.org/packages/ff/9a/6ae6062f0a7707a6c818f69653af34be90dffec0450c6a39790a1a7d918e/pybcj-1.0.8-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:b8d80571db5f89944aced42378b208afe38339008027ec56303e11628615a906", size = 33353, upload-time = "2026-07-16T22:47:02.452Z" }, { url = "https://files.pythonhosted.org/packages/52/7d/182735114b34301326ad197daae729e1b2a67c2be8e4ee661acabb1c4e04/pybcj-1.0.8-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:07eac7a1a8804230060fe56a5d828c620ee2d70acd31aef80705a01627da5946", size = 24737, upload-time = "2026-07-16T22:47:03.754Z" }, { url = "https://files.pythonhosted.org/packages/4d/0a/0d97486364bdf079631fc9b72b9cad42579fe2f0ce575fc67208037ce041/pybcj-1.0.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:af962c96a799ee7b13b9747a73240ba7f73e8643c276492f10e1dc60b564b295", size = 24980, upload-time = "2026-07-16T22:47:04.915Z" }, { url = "https://files.pythonhosted.org/packages/b7/28/f50bbf5c154f6eebca31789228b547e135fe541d46c85a026cadb842e8f2/pybcj-1.0.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:067982ad967ce68ae28c13cc27f96d8b65b5f497819dd4ad5c4f05ffc2fb2ae3", size = 53385, upload-time = "2026-07-16T22:47:06.039Z" }, { url = "https://files.pythonhosted.org/packages/8e/4f/9f226e64cf82b59d9f803e59f32496edfcd52a40305378eb1dd1f78bb18d/pybcj-1.0.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f23a36e978f4620db473b08239ab56dc57a479c83fd5d3808bc95e5bdbc1a703", size = 52372, upload-time = "2026-07-16T22:47:07.213Z" }, { url = "https://files.pythonhosted.org/packages/fe/d7/b52cbdaee0e41fd44edcf032dbcfe5bce7a4b0a8f9fe3fb38ec402fe99a7/pybcj-1.0.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ba3b8f1efd1ebbe3ee99a599c6ea745877a41675a0ade763903b644ccd58da97", size = 51326, upload-time = "2026-07-16T22:47:08.53Z" }, { url = "https://files.pythonhosted.org/packages/52/16/cafe2644f876639ae85c0a6fbe262c11f8065dd4b806eb4f6ace190076a3/pybcj-1.0.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:09c3fe78d325a499fdd0a003b04b0009a3921666dc590d1b7a496dc365eef3a9", size = 50874, upload-time = "2026-07-16T22:47:09.752Z" }, { url = "https://files.pythonhosted.org/packages/87/c4/767af5f90007cf5b138b2b4b40cf34998ca143fb22210c9d718d04eb2b22/pybcj-1.0.8-cp314-cp314-win_amd64.whl", hash = "sha256:0074af187b1acce9e31717fc9aa42bc36b67f1a44088a8b44f4f4792af688ee6", size = 25225, upload-time = "2026-07-16T22:47:11.144Z" }, { url = "https://files.pythonhosted.org/packages/22/30/bdbe671d8156ef0f3d8a5ac4d0bccc98bf1d573e1bb10ff6225383211351/pybcj-1.0.8-cp314-cp314-win_arm64.whl", hash = "sha256:458a5bff57f36fba7af822df64da335fa1781d592dd7f802f347ae1f75939aa0", size = 24460, upload-time = "2026-07-16T22:47:12.479Z" }, { url = "https://files.pythonhosted.org/packages/c3/13/45ec85efc37d71b3def7ad755d9ab964c1a00e9ebc02fd1cd6b199f2535f/pybcj-1.0.8-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:083b41b59672d4aa893b44769bed7a41abfde43211b27d47a0d4d66a59fdafad", size = 33916, upload-time = "2026-07-16T22:47:13.599Z" }, { url = "https://files.pythonhosted.org/packages/ab/c8/0988ce2bd104c24285a967e2dbddf9c07e0055354fae6a9ccace4202ef66/pybcj-1.0.8-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:0d432a32bfc23475b7fd62a5eb1c3243a8329ff95aa0e3c941d57902dc6e7c87", size = 25026, upload-time = "2026-07-16T22:47:14.777Z" }, { url = "https://files.pythonhosted.org/packages/86/37/ba7823ed5831d656eb7e841e026492d8540b59235210b68ba885c8bd0219/pybcj-1.0.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cb1601253a15abfaba42e0bdbde4d459d2afcafdc97dee0d9b698e589167fd8d", size = 25268, upload-time = "2026-07-16T22:47:15.909Z" }, { url = "https://files.pythonhosted.org/packages/74/1e/572c7e32da9bca384aa28401c09c153eb5bf1b0c64e249e9f13fbbdfadae/pybcj-1.0.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78498748ebea7e1483f9cfdeac4a08687f6e2773e3a4223c420ab1beae95d75d", size = 59685, upload-time = "2026-07-16T22:47:17.227Z" }, { url = "https://files.pythonhosted.org/packages/67/09/737dcd04aa137c91e33b89b8d68b763419c39feff14c9cf5eeb945954a6b/pybcj-1.0.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3817997e73d60ccbc731a47e007fe02213eee816cfe6070eb8347c6286aa3cc2", size = 57872, upload-time = "2026-07-16T22:47:18.476Z" }, { url = "https://files.pythonhosted.org/packages/53/31/519a41bf9ea3c58368bd72e6bd3a2eaf735aef206e715e87e2d0c4f5bb6f/pybcj-1.0.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2a9146d8f3df70305dba6cb9c3d25f285a9a69309e4941333962f5408a244be", size = 56908, upload-time = "2026-07-16T22:47:19.85Z" }, { url = "https://files.pythonhosted.org/packages/38/6a/fdc7b48e1b27f5cd44f554ca730e1928074d51db5bc640ec92323c46a689/pybcj-1.0.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5824e498e2dfafc19a2de2bdf54e5c2857144d84983ac8e13e54b1f7b78e3f50", size = 56063, upload-time = "2026-07-16T22:47:21.1Z" }, { url = "https://files.pythonhosted.org/packages/cc/c2/3d3d99065816de8acafc77917ac4c0b8e8df74f407ec2955a26f8b641a67/pybcj-1.0.8-cp314-cp314t-win_amd64.whl", hash = "sha256:331c21f0636150d4b846e0749cb0e8d6cbd133692368b391f9ba75dc02d5c51f", size = 25481, upload-time = "2026-07-16T22:47:22.357Z" }, { url = "https://files.pythonhosted.org/packages/ed/76/0901ba3b67842dbf4263c832ab8b05d6441eabfd97bec1d77d27b90a7a4c/pybcj-1.0.8-cp314-cp314t-win_arm64.whl", hash = "sha256:935e0588be20a2b7c3554a6415d1fdb66acfde037df718b7927033b658428518", size = 24893, upload-time = "2026-07-16T22:47:23.547Z" }, ] [[package]] name = "pycairo" version = "1.29.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/22/d9/1728840a22a4ef8a8f479b9156aa2943cd98c3907accd3849fb0d5f82bfd/pycairo-1.29.0.tar.gz", hash = "sha256:f3f7fde97325cae80224c09f12564ef58d0d0f655da0e3b040f5807bd5bd3142", size = 665871, upload-time = "2025-11-11T19:13:01.584Z" } [[package]] name = "pycparser" version = "3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, ] [[package]] name = "pycryptodomex" version = "3.23.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, ] [[package]] name = "pydata-sphinx-theme" version = "0.19.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ { name = "accessible-pygments" }, { name = "babel" }, { name = "beautifulsoup4" }, { name = "docutils" }, { name = "pygments" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" } }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/7e/e3defb93f30557ae825a3b3fbc2c6728301e5e9505a85e00d8503345c42c/pydata_sphinx_theme-0.19.0.tar.gz", hash = "sha256:148ba092bd6937b3321385dc482cc69a29ad2ede36547b4f010ade782bc6a062", size = 5004933, upload-time = "2026-06-15T09:31:02.268Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/54/77/bdb5a4c0e8e33c08f31fd175a5af0bc5e29f1b43ffa9e963f4c4f9bfbc97/pydata_sphinx_theme-0.19.0-py3-none-any.whl", hash = "sha256:5d7dfe3beb0facc88b5d78ff4a4c948f214cc0e03aae27e7fc58286e963b588b", size = 6201132, upload-time = "2026-06-15T09:30:59.966Z" }, ] [[package]] name = "pydata-sphinx-theme" version = "0.20.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] dependencies = [ { name = "accessible-pygments" }, { name = "babel" }, { name = "beautifulsoup4" }, { name = "docutils" }, { name = "jinja2" }, { name = "pygments" }, { name = "requests" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/8e/add936feaaa9dade7d5b87c6852566d85e518b38ad32224dea32ef958984/pydata_sphinx_theme-0.20.0.tar.gz", hash = "sha256:0da172d41e19a66de875f4002f7054b385372ec65763852193791e658d50bb4a", size = 5004756, upload-time = "2026-07-09T09:09:14.693Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/80/08/28e2194ed1c3c3a3e86e0600e2dcc7f21dcd670bd31f3efab2e3e2cf0cbd/pydata_sphinx_theme-0.20.0-py3-none-any.whl", hash = "sha256:56744483c9d72c783e075de716ab95d486108b69605df7528078090b73f11f69", size = 6201166, upload-time = "2026-07-09T09:09:12.899Z" }, ] [[package]] name = "pygments" version = "2.20.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] [[package]] name = "pygobject" version = "3.56.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycairo" }, ] sdist = { url = "https://files.pythonhosted.org/packages/da/61/978c5fbca34f10a90df362502fbb5a005637909e7b5a0e9212349ea9d010/pygobject-3.56.3.tar.gz", hash = "sha256:12760e4a0e3d04b6eb95e06f7a27e362c826d567ea613373a92c003b6c70d2d6", size = 1411853, upload-time = "2026-05-08T20:46:39.904Z" } [[package]] name = "pylast" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx2" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5e/1d/aaf99f82be962381ac07331106c72ff201ad98da9f18e74c0ee5f74e5a41/pylast-7.1.0.tar.gz", hash = "sha256:0c1fc381d649f256842c665ede52591d3b32789e281cd9b5601c01d2dc3a2d88", size = 437205, upload-time = "2026-06-30T11:32:55.353Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/84/18/07d29ce3b5702d835a09e42e1547762021e871f5d73b3330f97b8c31da99/pylast-7.1.0-py3-none-any.whl", hash = "sha256:2cba13d489344c6d85b195a9f472976e369fdfc0a027da3fb114d3d4906d7ecd", size = 26686, upload-time = "2026-06-30T11:32:53.723Z" }, ] [[package]] name = "pyppmd" version = "1.3.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/81/d7/803232913cab9163a1a97ecf2236cd7135903c46ac8d49613448d88e8759/pyppmd-1.3.1.tar.gz", hash = "sha256:ced527f08ade4408c1bfc5264e9f97ffac8d221c9d13eca4f35ec1ec0c7b6b2e", size = 1351815, upload-time = "2025-11-27T22:08:44.175Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c4/f2/175dbdc56178d5d00caa73df79f98f72fab80f5c01a7467aff3ed245f739/pyppmd-1.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:041f46fbeb0a59888c0a94d6b9a557c652935633a104be1c31c12de491b5f448", size = 77545, upload-time = "2025-11-27T22:07:22.938Z" }, { url = "https://files.pythonhosted.org/packages/61/a0/729139273084dd574b3b529cd4b006ca9d2dc42d8bd3b65adf66ae8dffd8/pyppmd-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9512a8b39740923559c26eb16266bf8b70d4eab6ad27a9b39cd2465e60e0acfa", size = 47997, upload-time = "2025-11-27T22:07:24.437Z" }, { url = "https://files.pythonhosted.org/packages/3f/bb/eab338c9fa00ddeb3f54552360949ac503f3cd77debc71857c07263eba20/pyppmd-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8966f26b91ba7cdff3cfec5512d39d1f8bf4a8dbb75c44085e33b564566fea66", size = 48437, upload-time = "2025-11-27T22:07:25.558Z" }, { url = "https://files.pythonhosted.org/packages/96/5b/f098d68ce887d25a47e95a1aaa6443436cb21bb4bcc3cd73f332135a214d/pyppmd-1.3.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0d1cff657e85655c67426c29c90c78a6210148b207993e643fc351c72c60d188", size = 139198, upload-time = "2025-11-27T22:07:27.086Z" }, { url = "https://files.pythonhosted.org/packages/1c/1e/59757d7e3aba883b2e446baee07055a069c9e17143fd4bd297fe590dd461/pyppmd-1.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9de2cdcc3932e7c23a54beb48dfe1b5ab7b4aedd5ffaae1e4871bd213d630cb3", size = 140959, upload-time = "2025-11-27T22:07:28.817Z" }, { url = "https://files.pythonhosted.org/packages/ed/6c/4d1aeea9bcb8293dada21b51e2d20eff49d24ddf512ec611b47d2440846a/pyppmd-1.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1e1985461219c30d4576070b7e2de718dbb6f32637d1e658d25f838dfda2a4bb", size = 136301, upload-time = "2025-11-27T22:07:30.523Z" }, { url = "https://files.pythonhosted.org/packages/3c/b7/f6a46a60b092b5fb9a9631be408e447ea87cce4d656197736586ba082975/pyppmd-1.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20d9d1aa4d0f32118c8094c212c66b7af50e55f47e7c6dffa5f35a8ac391faca", size = 139126, upload-time = "2025-11-27T22:07:32.274Z" }, { url = "https://files.pythonhosted.org/packages/d4/ed/cf1f4ac5248ddcb19cf18ef8acb256d909912a5c5684fcfe400fb42d778d/pyppmd-1.3.1-cp310-cp310-win32.whl", hash = "sha256:44d25e7dede2abb614bc023fe87835365fdd5865981c2273b70bfad71b84db29", size = 42019, upload-time = "2025-11-27T22:07:33.442Z" }, { url = "https://files.pythonhosted.org/packages/1b/93/1e035bd1ef405ca024be1fc4d9eb7d603eb03960d7010515ddf155dcccd2/pyppmd-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:1e503a28c9a275d31f24af9b735d2cca543b62f438b064e2833e9833e758bdbc", size = 46860, upload-time = "2025-11-27T22:07:34.873Z" }, { url = "https://files.pythonhosted.org/packages/23/2f/236f7bf2f8b8ccfd93f0505692b9ad10a249fa00ce4671c50049c69ea414/pyppmd-1.3.1-cp310-cp310-win_arm64.whl", hash = "sha256:3fb3708d7b2b38e2999385a2f02c8e68e0f5a364d94f94e475e2e8b09e9338fc", size = 45253, upload-time = "2025-11-27T22:07:36.406Z" }, { url = "https://files.pythonhosted.org/packages/04/40/580b99818c9db3a09cbae8e3740f9b5127ef7fd7314daf009c487ab02eb6/pyppmd-1.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fdf55aa6ee7aef492f6896464e7a5a528f8615bb9e435f55bc8dff226fcc8292", size = 77550, upload-time = "2025-11-27T22:07:37.839Z" }, { url = "https://files.pythonhosted.org/packages/8d/a3/f7b4c49ef920f5b2c9812f8f54f48e01435433cb6b46ec82b1b4e740714d/pyppmd-1.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa820aac385ac4ee57160b26d92862c69d31c08f92272dbef05fe8e619cea8d1", size = 48000, upload-time = "2025-11-27T22:07:38.983Z" }, { url = "https://files.pythonhosted.org/packages/bc/c3/30de6f7892e77b83350e55d54a6913420591cc2c5c4d2394c219a4c461ac/pyppmd-1.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e16593ba4ca0a85821ae698ef06847a52937662f5ce1b130c39cca2979a4e8cd", size = 48439, upload-time = "2025-11-27T22:07:40.428Z" }, { url = "https://files.pythonhosted.org/packages/39/22/33889cbe22a617c42df2199be54e9e1bf88393fd8643fe911eb9f982849c/pyppmd-1.3.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:486dde2294ff9b30465ab5bb0f213b20bd5ac0e4adf21be801a1ceb29aa75d9d", size = 141737, upload-time = "2025-11-27T22:07:41.641Z" }, { url = "https://files.pythonhosted.org/packages/0c/f7/940ab2fd78caaef3a9e9833adb36e17b9d03016d8b45ae110cbb4bfc83d1/pyppmd-1.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89730cf026416ae2546c92738966ecf117c8176d52c229ad621a61c34643818b", size = 143643, upload-time = "2025-11-27T22:07:42.892Z" }, { url = "https://files.pythonhosted.org/packages/75/51/129ce02d2b28a4f6788bccfe6d0ae1defc45db10eb1c4e4389cde8994ec7/pyppmd-1.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e77f5a6770950d464b50da760d53e67bce308a3abc8e3bd51db620b3f8cf1fa8", size = 138625, upload-time = "2025-11-27T22:07:44.54Z" }, { url = "https://files.pythonhosted.org/packages/3a/89/f8390d1a21951d3d4619c854a839f7b1431746997cd98b475f614a658305/pyppmd-1.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8e3bf8deef44f8e03612689a6067a4a3dd7e50d2ef00af4cf987c59b62ff3006", size = 141663, upload-time = "2025-11-27T22:07:45.814Z" }, { url = "https://files.pythonhosted.org/packages/fa/3f/b58dd8875ebbb78436f87567547967bebdf3a5586f5f243c735fc4460843/pyppmd-1.3.1-cp311-cp311-win32.whl", hash = "sha256:a3509b3f881409ebc5522942438108c48a78f8df88bcf3f9d907b74131b9431c", size = 42014, upload-time = "2025-11-27T22:07:47.058Z" }, { url = "https://files.pythonhosted.org/packages/b5/d3/5fe05bdccdd7af04461c25a3dc34799f48ad3e9a2bd591aaec9afbc1d10a/pyppmd-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:23b83799f33f9a24577f22e092b0feecda8cd1ea33871ad8610a58629874f7bc", size = 46862, upload-time = "2025-11-27T22:07:48.162Z" }, { url = "https://files.pythonhosted.org/packages/d4/ba/6414cbe8407c23bacce906dad0599f155b2baf6082da104e64d7f1573717/pyppmd-1.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:234489036a1758670655d1ceafd4caeb93b858bd4c0ca39686837d38aef044c0", size = 45249, upload-time = "2025-11-27T22:07:49.261Z" }, { url = "https://files.pythonhosted.org/packages/3e/89/696046e53c7aea98bb563aed3f15c3e2fa20c33e3d6c9de3c20992c586cc/pyppmd-1.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3faa58ab2ebe3b13ec23b1904639d687fb727270d2962fd2d239ca00fd6eb865", size = 77796, upload-time = "2025-11-27T22:07:50.362Z" }, { url = "https://files.pythonhosted.org/packages/f1/c5/a708cdb58e76889bc65201eda12211486548ffe00ecddc5dfbdce6d4d252/pyppmd-1.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27703f041ee96912a5410fd3ce31c5cde32f9323bd67f72f100bd960ee67bf13", size = 48185, upload-time = "2025-11-27T22:07:51.736Z" }, { url = "https://files.pythonhosted.org/packages/9e/5d/f299535c18009addb866d89a7044f1086e4eecf50542e57ff5bb15840195/pyppmd-1.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e773d8353b36f7e7973a43526993fb276b98a97839cb5dc8f4e6465ad873f41a", size = 48496, upload-time = "2025-11-27T22:07:52.866Z" }, { url = "https://files.pythonhosted.org/packages/aa/9d/4a59b73ea8e305f9192ee26ceb7c3d57e17ccb9bcca0e99ef335db29fcf7/pyppmd-1.3.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:37b1883accf840cb0b711785d353f8548853a1401d381da007c0aec362f3ffac", size = 142620, upload-time = "2025-11-27T22:07:54.411Z" }, { url = "https://files.pythonhosted.org/packages/88/d7/fe32c2a4f8539365e6292aed25545830a5e718a510cdb4caddd6fd8d8056/pyppmd-1.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bd6d179ad39b6191ca0cbe62fb9592f33f49277b4384ad7bc5eb0e6ca27ebee", size = 144306, upload-time = "2025-11-27T22:07:55.727Z" }, { url = "https://files.pythonhosted.org/packages/20/20/e3907cf263b58f4ed4c5315bc1ac91721c85332fd0d73a89e3e2752904ef/pyppmd-1.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:806cf8d33606e44bf5ff5786c57891f57993f1eef1c763da3c58ea97de3a13c8", size = 139522, upload-time = "2025-11-27T22:07:57.034Z" }, { url = "https://files.pythonhosted.org/packages/0a/03/22d5f93251e481f23bf741dde7f59cfc3e315f60b32b63f215a2d7bb8944/pyppmd-1.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1826cbce9a2c944aa08df79310a7e6d4a61fd20636b6dff64a77ea4bc43da30f", size = 142340, upload-time = "2025-11-27T22:07:58.49Z" }, { url = "https://files.pythonhosted.org/packages/34/88/38d36c1394d5e331db9708dae08863c87c059bd5b6e43b20234be02a0503/pyppmd-1.3.1-cp312-cp312-win32.whl", hash = "sha256:d3ff96671319318d941dd34300d641745048e8a3251b077bddf98652d6ddc513", size = 42102, upload-time = "2025-11-27T22:08:00.124Z" }, { url = "https://files.pythonhosted.org/packages/ee/29/1398c6f67dfb66367babeed2980caee837d0a488705e3dff7ff159e017e7/pyppmd-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:c8c1ad39e7ebde71bf5a54cf61f489bf4790f1dd0beb70dc2e8f5ad3329d7ca7", size = 46957, upload-time = "2025-11-27T22:08:01.587Z" }, { url = "https://files.pythonhosted.org/packages/d2/41/ee3193c16472a5a1c5f1965abb8fa87a7ad455c39688e9a0c2d87d6a7027/pyppmd-1.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:391b2bf76d7dc45b343781754d0b734dcbf539b92667986a343f5488c4bf9ca0", size = 45214, upload-time = "2025-11-27T22:08:02.721Z" }, { url = "https://files.pythonhosted.org/packages/f0/01/7cc3854b0e1304b90d2435e946db5e1c42e103adf840a68400002fc838b4/pyppmd-1.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4b4edb3e9619fd0bc39c1a07eb03e8731db833a93b23134f36c7ef581a94b37a", size = 77800, upload-time = "2025-11-27T22:08:03.856Z" }, { url = "https://files.pythonhosted.org/packages/dd/02/caf6305224b9432ea7373670d101392f620c1ce741d6f95458b1fb9a16a4/pyppmd-1.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8b5c813e462c91048b88e2adfbcc0c69f2c905f70097001d32066f86f675bd4", size = 48195, upload-time = "2025-11-27T22:08:05.323Z" }, { url = "https://files.pythonhosted.org/packages/45/82/8c5d3f0f738a3cf5c209d1471efda105a16417c0aaa91a2ad39efb3d4efb/pyppmd-1.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e8d372d9fac382183e0371cf0c2d736b494b1857a1befe98d563342b1205265b", size = 48482, upload-time = "2025-11-27T22:08:06.441Z" }, { url = "https://files.pythonhosted.org/packages/76/9c/09ab8b4f00473f210284dacf837cae8355ad900f3fd8fd98b2bba12de4fa/pyppmd-1.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b765ae21f7ed2f4ea8f32bfd9e3a4a8d738e73fc8f8dcddec9cbe2c898d60be", size = 142828, upload-time = "2025-11-27T22:08:07.611Z" }, { url = "https://files.pythonhosted.org/packages/64/fd/673d429df719affa1445611288aab6111c0bc87e51eb4677fe2421a1dd64/pyppmd-1.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd00522ddfcc292304577386b6c217758c0c10e1fb9ce7877ad7d3b7b821a808", size = 144502, upload-time = "2025-11-27T22:08:08.869Z" }, { url = "https://files.pythonhosted.org/packages/cf/0f/64dad213f56eaf23210ac7d3a5dedb19ad8f186f8b8682f65e7d51d9fa4a/pyppmd-1.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3de62099ff2ca876c2d39bc547bcba6f7b878988663abd782a5bad4edac3bb44", size = 139718, upload-time = "2025-11-27T22:08:10.114Z" }, { url = "https://files.pythonhosted.org/packages/74/61/bd5dbe8d7374748687d48f0bc44e6b930470e09552b1bbc65ef899ab673e/pyppmd-1.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:011f845de195d60fe973a635a1f4be981b7d80f357a8acb1b2d83bdf5087c808", size = 142578, upload-time = "2025-11-27T22:08:11.388Z" }, { url = "https://files.pythonhosted.org/packages/42/ae/0af00a9b1cd59b6821eb182413033d5ddbe05dfcde7511e3a6b1a5b83f6d/pyppmd-1.3.1-cp313-cp313-win32.whl", hash = "sha256:7d61bd01f25289b6ae54832db4254602fb0c6d105f6e6bf0aee39b803b698b98", size = 42102, upload-time = "2025-11-27T22:08:13.297Z" }, { url = "https://files.pythonhosted.org/packages/6c/6d/311d8faca142f39b4d158c94ed7eb237a197d41dd7eb67f53442a7904e04/pyppmd-1.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:df8d84ab72381058a964ba66e5e81ed52dbd0b5ad734a5ef8353452983506098", size = 46962, upload-time = "2025-11-27T22:08:14.759Z" }, { url = "https://files.pythonhosted.org/packages/bb/42/24b59b6bb73a3fec96c7f81521d146c2ac89ffcb89cf9e848f62e0660381/pyppmd-1.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:124a04aab6936ba011f9ad57067798c7f052fdb1848b0cc4318606eea55475e6", size = 45209, upload-time = "2025-11-27T22:08:15.933Z" }, { url = "https://files.pythonhosted.org/packages/65/10/ac2a011af1c7c40b6482e60d85d267ac5923fb8794b51bfddbb56b04d1ec/pyppmd-1.3.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:ea53f71ac16e113599b8441a9d8b6dcd71cfdf15cdb33ba5151810b8e656c5ec", size = 77897, upload-time = "2025-11-27T22:08:17.104Z" }, { url = "https://files.pythonhosted.org/packages/20/13/737f4dac06685865d23f51b7061dbe9373c7bcc60b5b6456cd08301bc807/pyppmd-1.3.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:985c8703b53e5f68fe17f653e96748d60b1f855676c852a6e67cd472eb853671", size = 48268, upload-time = "2025-11-27T22:08:18.263Z" }, { url = "https://files.pythonhosted.org/packages/c2/d3/c50ebaee8b8a064fe9a534e98df5051e309efb705728aadff4e6893cd87f/pyppmd-1.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:33daa996ad5203c665c0b55aff6329817b2cb7fa95f2c33a2e83ed0121b400cb", size = 48521, upload-time = "2025-11-27T22:08:19.742Z" }, { url = "https://files.pythonhosted.org/packages/80/6c/4a97c0a0ab7640aeddde4843cb6381b80ecb71fe2c6c48b9032d60586b11/pyppmd-1.3.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b49870c6d7194f6eb80f30335ca03596d153e02fcde2c222e4f1202ac25f7fcf", size = 142892, upload-time = "2025-11-27T22:08:20.972Z" }, { url = "https://files.pythonhosted.org/packages/8f/22/744c32c7da3de171d9e62a1b2cb4104544ac778358565a3dbc06a2253324/pyppmd-1.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:385e92c97c42e8a6f0bfc0e4acfc6c074cb1ba3a2f650f292696dd9f19e2e603", size = 144550, upload-time = "2025-11-27T22:08:22.594Z" }, { url = "https://files.pythonhosted.org/packages/4a/18/84af6808e0754923062122d3ee9f0532050f1612069d558bb5d53978e67a/pyppmd-1.3.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:017a1e2903f1c3147a1046db486990d401e8a25eb52c320b1fc2fb3e7b83cbeb", size = 139850, upload-time = "2025-11-27T22:08:23.863Z" }, { url = "https://files.pythonhosted.org/packages/20/5e/dc6166ea7929d442625301289d99313a5b358e3cb2e927a6bd913047e8ee/pyppmd-1.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f2770a4b777c0c5236b3d9294b7bf4bc15538c95d45b2079eb8ebc1298e62e37", size = 142589, upload-time = "2025-11-27T22:08:25.228Z" }, { url = "https://files.pythonhosted.org/packages/77/92/adc6b12ddf11173a02fd631010f88ad4fe4c532363959638d5d53583a3d9/pyppmd-1.3.1-cp314-cp314-win32.whl", hash = "sha256:b9d54cd59ce97f2ba57be1da91b3d874d129faca21c9565d7afec111f942e6a1", size = 42761, upload-time = "2025-11-27T22:08:26.917Z" }, { url = "https://files.pythonhosted.org/packages/12/4c/5003a413d9f2743298a070df6713a75dedccc470e7adeeced5b43cad7418/pyppmd-1.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:0e64247618cb150d2909beb0137da3084fef1d3479b4cc73b5b47fda7611abf9", size = 47806, upload-time = "2025-11-27T22:08:28.059Z" }, { url = "https://files.pythonhosted.org/packages/07/b7/db927e1df7fc3132cb57960f4ea23bf174c7e86ccec22857e6a35cccdae7/pyppmd-1.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:d354d6e551d2630b0ac98f27e3ad63e86cdcac9ce2115b5dfe46e2c9d3f4e82c", size = 46122, upload-time = "2025-11-27T22:08:29.191Z" }, { url = "https://files.pythonhosted.org/packages/a7/5f/3150227624f374b06e331a7f67ae3383e796dd90973ee17ec3e35d30524c/pyppmd-1.3.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:2d77ed79662c32e2551748d59763cfe3dcd10855bf3495937e3d5e5917507818", size = 78876, upload-time = "2025-11-27T22:08:30.635Z" }, { url = "https://files.pythonhosted.org/packages/2b/81/11a3bba62d1d92050f4dd86db810062b506ec76d20b6e00b4ab567ff15e4/pyppmd-1.3.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:6a1f92b94635c23d85270bb26db25cc0db544e436af86efc1cf58302d71d5af1", size = 48830, upload-time = "2025-11-27T22:08:32.087Z" }, { url = "https://files.pythonhosted.org/packages/24/47/e8f50cf89c689543d5a16c7be3df3c4afd43cbeb1a019b84ff9e82f13415/pyppmd-1.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:610f214f2405e27eb5a3dad7fa15f385cfc42141a01cda71995d9c1e0b09fab9", size = 48956, upload-time = "2025-11-27T22:08:33.567Z" }, { url = "https://files.pythonhosted.org/packages/0b/0f/944b30679a8dea3ea95a66531ee30cb6feb5d011ec7fd6832069d9130bf3/pyppmd-1.3.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae81a14895498d9a23429d92114c98da478b74b8e33251527d7cff3e01c09de0", size = 152872, upload-time = "2025-11-27T22:08:35.098Z" }, { url = "https://files.pythonhosted.org/packages/ae/87/1e48ea92994f4c72dc9b5520a6a386b21c524d3d2969c2c2a5c325929ad7/pyppmd-1.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1683e6d1ba09e377e0ae02de3a518191a3d63ccdb0b6037c74e6ddf577b5644", size = 154210, upload-time = "2025-11-27T22:08:36.368Z" }, { url = "https://files.pythonhosted.org/packages/3f/21/650911f98c4cb360442724bbdade27cb3679b0587ea77e73512693d2918d/pyppmd-1.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e4d74fa0f3531e9dadc56e0ace41bce82d3c0babed47b3f224101dc0dbde7287", size = 147636, upload-time = "2025-11-27T22:08:37.657Z" }, { url = "https://files.pythonhosted.org/packages/7c/29/4f8cfc1dd67b04ced8c10669fa14c4e35a42cf4a84e1101793735a82d5f0/pyppmd-1.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7f8d6375b18b9c79127fee0885cfd52e2e983edb67041464309426571d38dcd4", size = 150998, upload-time = "2025-11-27T22:08:38.951Z" }, { url = "https://files.pythonhosted.org/packages/c4/da/dc9e5e10bc56056bd8c33e533517cb327752cbaf172688bba3c23f6b2318/pyppmd-1.3.1-cp314-cp314t-win32.whl", hash = "sha256:de87f7acd575fb07a4ff42d41bcc071570fe759a36f345f1f54f574ecfccfc5b", size = 43016, upload-time = "2025-11-27T22:08:40.234Z" }, { url = "https://files.pythonhosted.org/packages/fa/a0/46dc15549ad2c0427a9825730e6bdf342045ad410543368afd4389a16f36/pyppmd-1.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:76e4800aa67292b4cc80058fd29b39e02a5dded721af9fe5654f356ef24307f4", size = 48636, upload-time = "2025-11-27T22:08:41.45Z" }, { url = "https://files.pythonhosted.org/packages/a1/7b/7e9a83848de928c26f0ab3ee105c0da63a932a0804a94807205e6313e73a/pyppmd-1.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:e066cbf1d335fe20480cd8ecc10848ba78d99fe6d1e44ea00def48feaf46afdf", size = 46402, upload-time = "2025-11-27T22:08:42.804Z" }, ] [[package]] name = "pyrate-limiter" version = "4.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/19/27/e564f33ea085c63d5540f707b31aeb50a4992eac2da655dc02435a760a07/pyrate_limiter-4.4.0.tar.gz", hash = "sha256:2c0c720c4fa16c5d8199e4821bf34507fb49c007a25b786cec6fb94ffd0844aa", size = 90955, upload-time = "2026-06-14T10:52:03.021Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/77/2b5ea2e5e343fd7f74ba9c50a282d7cb66d1be3d12bd647510338d78fcf1/pyrate_limiter-4.4.0-py3-none-any.whl", hash = "sha256:f738dfa3c7ac1222a5ea3d31e00cfd31b5592b13ade4077afe9e8ac6293381f5", size = 43102, upload-time = "2026-06-14T10:52:01.334Z" }, ] [[package]] name = "pytest" version = "9.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "pygments" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, ] [[package]] name = "pytest-cov" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage", extra = ["toml"] }, { name = "pluggy" }, { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, ] [[package]] name = "pytest-factoryboy" version = "2.8.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "factory-boy" }, { name = "inflection" }, { name = "packaging" }, { name = "pytest" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/91/8a/a0f9c58bf176b0d39b630a6e29cccebec9a429dfeb62204bbb9b632fb798/pytest_factoryboy-2.8.1.tar.gz", hash = "sha256:2221d48b31b8b8ccaa739c6a162fb50a43a4de6dff6043f249d2807a3462548d", size = 16906, upload-time = "2025-07-01T04:05:38.901Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/06/2f/4f73a79196b4acb0f902520a805caa22f8ba0adbecdfb028a371404c2537/pytest_factoryboy-2.8.1-py3-none-any.whl", hash = "sha256:91c762cb236bf34b11efdf2e54bafae33114488235621e8b2c4bd9fd77838784", size = 16413, upload-time = "2025-07-01T04:05:37.344Z" }, ] [[package]] name = "pytest-flask" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "flask" }, { name = "pytest" }, { name = "werkzeug" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fb/23/32b36d2f769805c0f3069ca8d9eeee77b27fcf86d41d40c6061ddce51c7d/pytest-flask-1.3.0.tar.gz", hash = "sha256:58be1c97b21ba3c4d47e0a7691eb41007748506c36bf51004f78df10691fa95e", size = 35816, upload-time = "2023-10-23T14:53:20.696Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/de/03/7a917fda3d0e96b4e80ab1f83a6628ec4ee4a882523b49417d3891bacc9e/pytest_flask-1.3.0-py3-none-any.whl", hash = "sha256:c0e36e6b0fddc3b91c4362661db83fa694d1feb91fa505475be6732b5bc8c253", size = 13105, upload-time = "2023-10-23T14:53:18.959Z" }, ] [[package]] name = "python-dateutil" version = "2.9.0.post0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] [[package]] name = "python-mpd2" version = "3.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/53/be/e77206eb35eb37ccd3506fba237e1431431d04c482707730ce2a6802e95c/python-mpd2-3.1.1.tar.gz", hash = "sha256:4baec3584cc43ed9948d5559079fafc2679b06b2ade273e909b3582654b2b3f5", size = 58713, upload-time = "2024-01-13T11:47:42.032Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8e/6d/1b9e1c203057c9a7fa6971db3605188a8ef1120ca305e4878c960ab6e2d3/python_mpd2-3.1.1-py2.py3-none-any.whl", hash = "sha256:86bf1100a0b135959d74a9a7a58cf0515bf30bb54eb25ae6fb8e175e50300fc3", size = 35050, upload-time = "2024-01-13T11:47:40.013Z" }, ] [[package]] name = "python3-discogs-client" version = "2.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "oauthlib" }, { name = "python-dateutil" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6a/5c/48f3b25aeb9a111f09ae3c0f329356c9f4c67c124f0cfb539d19268926a2/python3_discogs_client-2.9.tar.gz", hash = "sha256:f588ad0c998d04b72e1eadcde9b353023cae6c4a3af6d81db15029c83eec5df1", size = 38176, upload-time = "2026-07-15T17:56:17.019Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6f/d7/8436885b1ce3a6bf6a167ba4d0680e2d75a3524bec8a890af4dd3dd5598a/python3_discogs_client-2.9-py3-none-any.whl", hash = "sha256:fc426cb4e97159b6595d264957bb991a928686e54db432c7027dbe05e47cacce", size = 17710, upload-time = "2026-07-15T17:56:15.762Z" }, ] [[package]] name = "pytokens" version = "0.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/42/24/f206113e05cb8ef51b3850e7ef88f20da6f4bf932190ceb48bd3da103e10/pytokens-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a44ed93ea23415c54f3face3b65ef2b844d96aeb3455b8a69b3df6beab6acc5", size = 161522, upload-time = "2026-01-30T01:02:50.393Z" }, { url = "https://files.pythonhosted.org/packages/d4/e9/06a6bf1b90c2ed81a9c7d2544232fe5d2891d1cd480e8a1809ca354a8eb2/pytokens-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:add8bf86b71a5d9fb5b89f023a80b791e04fba57960aa790cc6125f7f1d39dfe", size = 246945, upload-time = "2026-01-30T01:02:52.399Z" }, { url = "https://files.pythonhosted.org/packages/69/66/f6fb1007a4c3d8b682d5d65b7c1fb33257587a5f782647091e3408abe0b8/pytokens-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:670d286910b531c7b7e3c0b453fd8156f250adb140146d234a82219459b9640c", size = 259525, upload-time = "2026-01-30T01:02:53.737Z" }, { url = "https://files.pythonhosted.org/packages/04/92/086f89b4d622a18418bac74ab5db7f68cf0c21cf7cc92de6c7b919d76c88/pytokens-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4e691d7f5186bd2842c14813f79f8884bb03f5995f0575272009982c5ac6c0f7", size = 262693, upload-time = "2026-01-30T01:02:54.871Z" }, { url = "https://files.pythonhosted.org/packages/b4/7b/8b31c347cf94a3f900bdde750b2e9131575a61fdb620d3d3c75832262137/pytokens-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:27b83ad28825978742beef057bfe406ad6ed524b2d28c252c5de7b4a6dd48fa2", size = 103567, upload-time = "2026-01-30T01:02:56.414Z" }, { url = "https://files.pythonhosted.org/packages/3d/92/790ebe03f07b57e53b10884c329b9a1a308648fc083a6d4a39a10a28c8fc/pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440", size = 160864, upload-time = "2026-01-30T01:02:57.882Z" }, { url = "https://files.pythonhosted.org/packages/13/25/a4f555281d975bfdd1eba731450e2fe3a95870274da73fb12c40aeae7625/pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc", size = 248565, upload-time = "2026-01-30T01:02:59.912Z" }, { url = "https://files.pythonhosted.org/packages/17/50/bc0394b4ad5b1601be22fa43652173d47e4c9efbf0044c62e9a59b747c56/pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d", size = 260824, upload-time = "2026-01-30T01:03:01.471Z" }, { url = "https://files.pythonhosted.org/packages/4e/54/3e04f9d92a4be4fc6c80016bc396b923d2a6933ae94b5f557c939c460ee0/pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16", size = 264075, upload-time = "2026-01-30T01:03:04.143Z" }, { url = "https://files.pythonhosted.org/packages/d1/1b/44b0326cb5470a4375f37988aea5d61b5cc52407143303015ebee94abfd6/pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6", size = 103323, upload-time = "2026-01-30T01:03:05.412Z" }, { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" }, { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" }, { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" }, { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" }, { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" }, { url = "https://files.pythonhosted.org/packages/cb/dc/08b1a080372afda3cceb4f3c0a7ba2bde9d6a5241f1edb02a22a019ee147/pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b", size = 160720, upload-time = "2026-01-30T01:03:13.843Z" }, { url = "https://files.pythonhosted.org/packages/64/0c/41ea22205da480837a700e395507e6a24425151dfb7ead73343d6e2d7ffe/pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f", size = 254204, upload-time = "2026-01-30T01:03:14.886Z" }, { url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload-time = "2026-01-30T01:03:15.936Z" }, { url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload-time = "2026-01-30T01:03:17.458Z" }, { url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload-time = "2026-01-30T01:03:18.652Z" }, { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" }, { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" }, { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" }, { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" }, { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" }, { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" }, { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" }, { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" }, { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" }, { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" }, { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, ] [[package]] name = "pyxdg" version = "0.28" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b0/25/7998cd2dec731acbd438fbf91bc619603fc5188de0a9a17699a781840452/pyxdg-0.28.tar.gz", hash = "sha256:3267bb3074e934df202af2ee0868575484108581e6f3cb006af1da35395e88b4", size = 77776, upload-time = "2022-06-05T11:35:01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e5/8d/cf41b66a8110670e3ad03dab9b759704eeed07fa96e90fdc0357b2ba70e2/pyxdg-0.28-py2.py3-none-any.whl", hash = "sha256:bdaf595999a0178ecea4052b7f4195569c1ff4d344567bccdc12dfdf02d545ab", size = 49520, upload-time = "2022-06-05T11:34:58.832Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] [[package]] name = "pyyaml-ft" version = "8.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/5e/eb/5a0d575de784f9a1f94e2b1288c6886f13f34185e13117ed530f32b6f8a8/pyyaml_ft-8.0.0.tar.gz", hash = "sha256:0c947dce03954c7b5d38869ed4878b2e6ff1d44b08a0d84dc83fdad205ae39ab", size = 141057, upload-time = "2025-06-10T15:32:15.613Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/68/ba/a067369fe61a2e57fb38732562927d5bae088c73cb9bb5438736a9555b29/pyyaml_ft-8.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8c1306282bc958bfda31237f900eb52c9bedf9b93a11f82e1aab004c9a5657a6", size = 187027, upload-time = "2025-06-10T15:31:48.722Z" }, { url = "https://files.pythonhosted.org/packages/ad/c5/a3d2020ce5ccfc6aede0d45bcb870298652ac0cf199f67714d250e0cdf39/pyyaml_ft-8.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:30c5f1751625786c19de751e3130fc345ebcba6a86f6bddd6e1285342f4bbb69", size = 176146, upload-time = "2025-06-10T15:31:50.584Z" }, { url = "https://files.pythonhosted.org/packages/e3/bb/23a9739291086ca0d3189eac7cd92b4d00e9fdc77d722ab610c35f9a82ba/pyyaml_ft-8.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fa992481155ddda2e303fcc74c79c05eddcdbc907b888d3d9ce3ff3e2adcfb0", size = 746792, upload-time = "2025-06-10T15:31:52.304Z" }, { url = "https://files.pythonhosted.org/packages/5f/c2/e8825f4ff725b7e560d62a3609e31d735318068e1079539ebfde397ea03e/pyyaml_ft-8.0.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cec6c92b4207004b62dfad1f0be321c9f04725e0f271c16247d8b39c3bf3ea42", size = 786772, upload-time = "2025-06-10T15:31:54.712Z" }, { url = "https://files.pythonhosted.org/packages/35/be/58a4dcae8854f2fdca9b28d9495298fd5571a50d8430b1c3033ec95d2d0e/pyyaml_ft-8.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06237267dbcab70d4c0e9436d8f719f04a51123f0ca2694c00dd4b68c338e40b", size = 778723, upload-time = "2025-06-10T15:31:56.093Z" }, { url = "https://files.pythonhosted.org/packages/86/ed/fed0da92b5d5d7340a082e3802d84c6dc9d5fa142954404c41a544c1cb92/pyyaml_ft-8.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8a7f332bc565817644cdb38ffe4739e44c3e18c55793f75dddb87630f03fc254", size = 758478, upload-time = "2025-06-10T15:31:58.314Z" }, { url = "https://files.pythonhosted.org/packages/f0/69/ac02afe286275980ecb2dcdc0156617389b7e0c0a3fcdedf155c67be2b80/pyyaml_ft-8.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7d10175a746be65f6feb86224df5d6bc5c049ebf52b89a88cf1cd78af5a367a8", size = 799159, upload-time = "2025-06-10T15:31:59.675Z" }, { url = "https://files.pythonhosted.org/packages/4e/ac/c492a9da2e39abdff4c3094ec54acac9747743f36428281fb186a03fab76/pyyaml_ft-8.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:58e1015098cf8d8aec82f360789c16283b88ca670fe4275ef6c48c5e30b22a96", size = 158779, upload-time = "2025-06-10T15:32:01.029Z" }, { url = "https://files.pythonhosted.org/packages/5d/9b/41998df3298960d7c67653669f37710fa2d568a5fc933ea24a6df60acaf6/pyyaml_ft-8.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e64fa5f3e2ceb790d50602b2fd4ec37abbd760a8c778e46354df647e7c5a4ebb", size = 191331, upload-time = "2025-06-10T15:32:02.602Z" }, { url = "https://files.pythonhosted.org/packages/0f/16/2710c252ee04cbd74d9562ebba709e5a284faeb8ada88fcda548c9191b47/pyyaml_ft-8.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8d445bf6ea16bb93c37b42fdacfb2f94c8e92a79ba9e12768c96ecde867046d1", size = 182879, upload-time = "2025-06-10T15:32:04.466Z" }, { url = "https://files.pythonhosted.org/packages/9a/40/ae8163519d937fa7bfa457b6f78439cc6831a7c2b170e4f612f7eda71815/pyyaml_ft-8.0.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c56bb46b4fda34cbb92a9446a841da3982cdde6ea13de3fbd80db7eeeab8b49", size = 811277, upload-time = "2025-06-10T15:32:06.214Z" }, { url = "https://files.pythonhosted.org/packages/f9/66/28d82dbff7f87b96f0eeac79b7d972a96b4980c1e445eb6a857ba91eda00/pyyaml_ft-8.0.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dab0abb46eb1780da486f022dce034b952c8ae40753627b27a626d803926483b", size = 831650, upload-time = "2025-06-10T15:32:08.076Z" }, { url = "https://files.pythonhosted.org/packages/e8/df/161c4566facac7d75a9e182295c223060373d4116dead9cc53a265de60b9/pyyaml_ft-8.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd48d639cab5ca50ad957b6dd632c7dd3ac02a1abe0e8196a3c24a52f5db3f7a", size = 815755, upload-time = "2025-06-10T15:32:09.435Z" }, { url = "https://files.pythonhosted.org/packages/05/10/f42c48fa5153204f42eaa945e8d1fd7c10d6296841dcb2447bf7da1be5c4/pyyaml_ft-8.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:052561b89d5b2a8e1289f326d060e794c21fa068aa11255fe71d65baf18a632e", size = 810403, upload-time = "2025-06-10T15:32:11.051Z" }, { url = "https://files.pythonhosted.org/packages/d5/d2/e369064aa51009eb9245399fd8ad2c562bd0bcd392a00be44b2a824ded7c/pyyaml_ft-8.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3bb4b927929b0cb162fb1605392a321e3333e48ce616cdcfa04a839271373255", size = 835581, upload-time = "2025-06-10T15:32:12.897Z" }, { url = "https://files.pythonhosted.org/packages/c0/28/26534bed77109632a956977f60d8519049f545abc39215d086e33a61f1f2/pyyaml_ft-8.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:de04cfe9439565e32f178106c51dd6ca61afaa2907d143835d501d84703d3793", size = 171579, upload-time = "2025-06-10T15:32:14.34Z" }, ] [[package]] name = "rarfile" version = "4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/09/84/a00a5be12adbe5abb0094513ad6d3aefc80fe5dfa4a5604e22561d4b7d3b/rarfile-4.4.tar.gz", hash = "sha256:b7d29d671223cdc80e8b992df212d152ad88e6c961d4426c3fb2fefe8dd86fdf", size = 155437, upload-time = "2026-07-22T16:19:15.533Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e2/06/7135da7d7d662767aee9aeebaa360f4ad29f08d9198cc1b1632428114acd/rarfile-4.4-py3-none-any.whl", hash = "sha256:befb813c283fbcdd46dda2bad090f8272c8bb1de246d04cd570e9d890294d119", size = 29932, upload-time = "2026-07-22T16:19:14.559Z" }, ] [[package]] name = "reflink" version = "0.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/47/b503f286378336aa6d2fd3caad10633bb79f3bc6256f1f2f9102dacb3c98/reflink-0.2.2.tar.gz", hash = "sha256:882375ee7319275ae5f6a6a1287406365dac1e9643b91ad10e5187d3f84253bd", size = 21956, upload-time = "2023-08-26T10:33:51.565Z" } [[package]] name = "regex" version = "2026.7.19" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/20/98/04b13f1ddfb63158025291c02e03eb42fbb7acb51d091d541050eb4e35e8/regex-2026.7.19.tar.gz", hash = "sha256:7e77b324909c1617cbb4c668677e2c6ae13f44d7c1de0d4f15f2e3c10f3315b5", size = 416440, upload-time = "2026-07-19T00:19:48.923Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/24/13/bbf7d9d1887fe4a3693527c6caa232c197ea9da91f1212e9672eff60329d/regex-2026.7.19-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:555497390743af1a65045fa4527782d10ff5b88970359412baa4a1e628fe393b", size = 494009, upload-time = "2026-07-19T00:16:13.602Z" }, { url = "https://files.pythonhosted.org/packages/a3/19/783688e75a2bec15d50aec0d5e7e317d363808bc82a6eb6750b897bfcd7b/regex-2026.7.19-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:343a4504e3fb688c47cad451221ca5d4814f42b1e16c0065bde9cbf7f473bd52", size = 295287, upload-time = "2026-07-19T00:16:15.702Z" }, { url = "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ebee1ee89c39c953baac6924fcde08c5bb427c4057510862f9d7c7bdb3d8665", size = 290633, upload-time = "2026-07-19T00:16:17.182Z" }, { url = "https://files.pythonhosted.org/packages/ae/1e/1045ca2cabb12e8ec41ad0d138e9f3ff1eb079d30a6f51ccf7d709b44aad/regex-2026.7.19-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:062f8cb7a9739c4835d22bd96f370c59aba89f257adcfa53be3cc209e08d3ae0", size = 785300, upload-time = "2026-07-19T00:16:18.505Z" }, { url = "https://files.pythonhosted.org/packages/d5/4a/20e5bca184e90bf1bd187efdb53363f4a7b7b34f01d54ced5740caf104bd/regex-2026.7.19-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1123ef4211d763ee771d47916a1596e2f4915794f7aabdc1adcb20e4249a6951", size = 854079, upload-time = "2026-07-19T00:16:19.909Z" }, { url = "https://files.pythonhosted.org/packages/09/9b/5a2e59678be3b24aa6a42b2c6d66a48daa212593e9f4096fe7ba577fa9b1/regex-2026.7.19-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6e44c0e7c5664be20aee92085153150c0a7967310a73a43c0f832b7cd35d0dd3", size = 899496, upload-time = "2026-07-19T00:16:21.453Z" }, { url = "https://files.pythonhosted.org/packages/48/9a/7317f14ed8ed9fd998d1978b4802b07bc4d79216353c435dbcc1ddd1301f/regex-2026.7.19-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98c6ac18480fcdb33f35439183f1d2e79760ab41930309c6d951cb1f8e46694c", size = 793541, upload-time = "2026-07-19T00:16:22.991Z" }, { url = "https://files.pythonhosted.org/packages/6f/53/833c2db3e274d3c191f4c42fe5bfa358e4c8b617d5d7312d31334965fc46/regex-2026.7.19-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4458124d71339f505bf1fb94f69fd1bb8fa9d2481eebfef27c10ef4f2b9e12f6", size = 785515, upload-time = "2026-07-19T00:16:24.654Z" }, { url = "https://files.pythonhosted.org/packages/8d/b9/efb2f9fa151d71db09d4015e1fb92fee47416f01c12164836bbd23e2f3c2/regex-2026.7.19-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbf300e2070bb35038660b3be1be4b91b0024edb41517e6996320b49b92b4175", size = 769556, upload-time = "2026-07-19T00:16:26.207Z" }, { url = "https://files.pythonhosted.org/packages/81/4d/45610c263f8eadb84e4a1fabd904d81d5176226faa9104ef498bf8a8b285/regex-2026.7.19-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b2b506b1788df5fecd270a10d5e70a95fe77b87ea2b370a318043f6f5f817ee6", size = 774130, upload-time = "2026-07-19T00:16:27.786Z" }, { url = "https://files.pythonhosted.org/packages/40/95/1b40d87c7a9e5480bec7a87bce9fd67fc3f14b5f106c8ee66d660249072f/regex-2026.7.19-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:52579c60a6078be70a0e49c81d6e56d677f34cd439af281a0083b8c7bc75c095", size = 848694, upload-time = "2026-07-19T00:16:29.412Z" }, { url = "https://files.pythonhosted.org/packages/17/8b/bb45968addd5b394ef9cd9184bd9c65ade1a819dbb2b92b71ad52a0c7907/regex-2026.7.19-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:2955907b7157a6660f27079edf7e0229e9c9c5325c77a2ef6a890cba91efa6f0", size = 758505, upload-time = "2026-07-19T00:16:31.006Z" }, { url = "https://files.pythonhosted.org/packages/bf/6f/33386c672fbf43e21602135a0f29a97ee251a483f007fe51d10e9b2dbc93/regex-2026.7.19-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:89dfee3319f5ae3f75ebd5c2445a809bb320252ba5529ffdafea4ef25d79cf1a", size = 836985, upload-time = "2026-07-19T00:16:32.459Z" }, { url = "https://files.pythonhosted.org/packages/22/f1/9112b86e9bb075619862e8e42b604794389f1958faa68fb69bde505dd90e/regex-2026.7.19-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d3143f159261b1ce5b24c261c590e5913370c3200c5e9ebbb92b5aa5e111902", size = 782610, upload-time = "2026-07-19T00:16:33.857Z" }, { url = "https://files.pythonhosted.org/packages/3a/f9/13d460d8a385ca0b0be9e6be80a90968b9293b3e30895543ad2d1d1653e4/regex-2026.7.19-cp310-cp310-win32.whl", hash = "sha256:64729333167c2dcaaa56a331d40ee097bd9c5617ffd51dabb09eaddafb1b532e", size = 266772, upload-time = "2026-07-19T00:16:35.194Z" }, { url = "https://files.pythonhosted.org/packages/9f/90/29addd7a03e1aea402c1f31467e25c80caabc8c3735b88a23cf73b0aa9c2/regex-2026.7.19-cp310-cp310-win_amd64.whl", hash = "sha256:1c398716054621aa300b3d411f467dda903806c5da0df6945ab73982b8d115db", size = 277967, upload-time = "2026-07-19T00:16:36.847Z" }, { url = "https://files.pythonhosted.org/packages/8c/ba/ecfce06fe66c122bc6f77ae284887a9282e4411fe1e6268c5266611ca054/regex-2026.7.19-cp310-cp310-win_arm64.whl", hash = "sha256:064f1760a5a4ade65c5419be23e782f29147528e8a66e0c42dd4cedb8d4e9fc6", size = 276963, upload-time = "2026-07-19T00:16:38.315Z" }, { url = "https://files.pythonhosted.org/packages/05/e5/cef4de2bac939280b68d32adc659478845238a8274f2f79c465063f590ad/regex-2026.7.19-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ac777001cdfc28b72477d93c8564bb7583081ea8fb45cdca3d568e0a4f87183c", size = 494012, upload-time = "2026-07-19T00:16:39.927Z" }, { url = "https://files.pythonhosted.org/packages/ff/87/e86f51eb117457bb7803132ffe5cb6e2841e2b5bea4cc85d397f3c6e257d/regex-2026.7.19-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:59787bd5f8c70aa339084e961d2996b53fbdeab4d5393bba5c1fe1fc32e02bae", size = 295281, upload-time = "2026-07-19T00:16:41.433Z" }, { url = "https://files.pythonhosted.org/packages/41/2e/2360c41d8080a3d9ec7e5c90fad6eab3b50192869d10e9a5609e48c8177b/regex-2026.7.19-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:90c633e7e8d6bf4e992b8b36ce69e018f834b641dd6de8cea6d78c06ffa119c5", size = 290615, upload-time = "2026-07-19T00:16:43.058Z" }, { url = "https://files.pythonhosted.org/packages/cf/69/b65ba4344efbc771b28fe5dde84cbbb6c8f9551165952fe78def5b9dde6a/regex-2026.7.19-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:87ccab0db8d5f4fbb0272642113c1adb2ffc698c16d3a0944580222331fa7a20", size = 791804, upload-time = "2026-07-19T00:16:44.662Z" }, { url = "https://files.pythonhosted.org/packages/81/b6/a40dfa0dc6224b36f620c00296eacc830489cbf8c2837b6750dfe6170375/regex-2026.7.19-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e50d748a32da622f256e8d505867f5d3c43a837c6a9f0efb149655fadd1042a", size = 861723, upload-time = "2026-07-19T00:16:46.412Z" }, { url = "https://files.pythonhosted.org/packages/e3/02/735991dee71abd83196a7962f7ed8bf5aa05720ff06e2d3ff896a85e2bbb/regex-2026.7.19-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bf1516fe58fc104f39b2d1dbe2d5e27d0cd45c4be2e42ba6ee0cc763701ec3c7", size = 905932, upload-time = "2026-07-19T00:16:47.956Z" }, { url = "https://files.pythonhosted.org/packages/45/6c/e7098d8b846ccdbf431d8c081b61e496526a27a28094ed09e0dce21b3f54/regex-2026.7.19-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09f3e5287f94f17b709dc9a9e70865855feee835c861613be144218ce4ca82cc", size = 801407, upload-time = "2026-07-19T00:16:49.43Z" }, { url = "https://files.pythonhosted.org/packages/8a/18/34b69274e2649bcc7d9b089c2b2983fb2632d8ecf667e359593be9072e79/regex-2026.7.19-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6383cd2ed53a646c659ba1fe65727db76437fdaa069e697a0b44a51d5843d864", size = 774448, upload-time = "2026-07-19T00:16:51.352Z" }, { url = "https://files.pythonhosted.org/packages/bb/e6/0a72247d025585fd3800b98e040b84d562a88af6303347100484849f4f01/regex-2026.7.19-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:09d3007fc76249a83cdd33de160d50e6cb77f54e09d8fa9e7148e10607ce24af", size = 783297, upload-time = "2026-07-19T00:16:53.071Z" }, { url = "https://files.pythonhosted.org/packages/b1/aa/c4f65ae7dd02a36b323a70c4cff326e1f3442361aaebc9311100a130d54f/regex-2026.7.19-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f8c6e7a1cfa3dc9d0ee2de0e65e834537fa29992cc3976ffec914afc35c5dd5", size = 854736, upload-time = "2026-07-19T00:16:54.607Z" }, { url = "https://files.pythonhosted.org/packages/62/c3/668082bcc817b9e694189b84997aeba7385b7779faa6711788679c482e35/regex-2026.7.19-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:b2ea4a3e8357be8849e833beeae757ac3c7a6b3fc055c03c808a53c91ad30d82", size = 763298, upload-time = "2026-07-19T00:16:56.289Z" }, { url = "https://files.pythonhosted.org/packages/4b/fb/2d07ad555e7af88aa5f867fdafa47a8d945ee237c20af3ebceb46a820835/regex-2026.7.19-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:80115dd39481fd3a4b4080220799dbcacb921a844de4b827264ececacbe17c78", size = 844430, upload-time = "2026-07-19T00:16:57.933Z" }, { url = "https://files.pythonhosted.org/packages/51/15/c82a471fe3dce56f03745635b43aa456c40dc0db089e07ef148b331507d1/regex-2026.7.19-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d6ce43a0269d68cee79a7d1ade7def53c20f8f2a047b92d7b5d5bcc73ae88327", size = 789683, upload-time = "2026-07-19T00:16:59.583Z" }, { url = "https://files.pythonhosted.org/packages/b5/f4/7532a2c59d56f5398902c20de60f0c9a5d1cd364e42a051b48e1b210be7b/regex-2026.7.19-cp311-cp311-win32.whl", hash = "sha256:9be2a6647740dd3cca6acb24e87f03d7632cd280dbce9bbe40c26353a215a45d", size = 266778, upload-time = "2026-07-19T00:17:01.032Z" }, { url = "https://files.pythonhosted.org/packages/83/2b/cf1bc631db154eb95520d9d5dbc2371ff77a0f014bbf7d748fed8496aa63/regex-2026.7.19-cp311-cp311-win_amd64.whl", hash = "sha256:8d3469c91dd92ee41b7c95280edbd975ef1ba9195086686623a1c6e8935ce965", size = 277983, upload-time = "2026-07-19T00:17:02.571Z" }, { url = "https://files.pythonhosted.org/packages/8d/bd/56ceaf170e875d5a6761bf2bfd0d040f1cacc896850d5e40cb29b11bbd06/regex-2026.7.19-cp311-cp311-win_arm64.whl", hash = "sha256:36aacfb15faaff3ced55afbf35ec72f50d4aee22082c4f7fe0573a33e2fca92e", size = 276961, upload-time = "2026-07-19T00:17:04.135Z" }, { url = "https://files.pythonhosted.org/packages/3b/b9/d11d7e501ac8fd7d617684423ebb9561e0b998481c1e4cbc0cb212c5d74a/regex-2026.7.19-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2cc3460cedf7579948486eab03bc9ad7089df4d7281c0f47f4afe03e8d13f02d", size = 496778, upload-time = "2026-07-19T00:17:05.677Z" }, { url = "https://files.pythonhosted.org/packages/3f/a9/a5ab6f312f24318019170dc485d5421fe4f89e43a98640da50d95a8a7041/regex-2026.7.19-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0e9554c8785eac5cffe6300f69a91f58ba72bc88a5f8d661235ad7c6aa5b8ccd", size = 297122, upload-time = "2026-07-19T00:17:07.59Z" }, { url = "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7da47a0f248977f08e2cb659ff3c17ddc13a4d39b3a7baa0a81bf5b415430f6", size = 292009, upload-time = "2026-07-19T00:17:09.648Z" }, { url = "https://files.pythonhosted.org/packages/22/85/102a81b218298957d4ea7d2f084fae537a71add9d6ff93c8e67284c5f45e/regex-2026.7.19-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93db40c8de0815baab96a06e08a984bac71f989d13bab789e382158c5d426797", size = 796708, upload-time = "2026-07-19T00:17:11.542Z" }, { url = "https://files.pythonhosted.org/packages/78/b5/dc136af5629938a037cd2b304c12240e132ec92f38be8ff9cc89af2a1f2d/regex-2026.7.19-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:66bd62c59a5427746e8c44becae1d9b99d22fb13f30f492083dfb9ad7c45cc18", size = 865651, upload-time = "2026-07-19T00:17:13.312Z" }, { url = "https://files.pythonhosted.org/packages/e0/75/67402ae3cd9c8c988a4c805d15ee3eef015e7ca4cb112cf3e640fc1f4153/regex-2026.7.19-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1649eb39fcc9ea80c4d2f110fde2b8ab2aef3877b98f02ab9b14e961f418c511", size = 911756, upload-time = "2026-07-19T00:17:15.015Z" }, { url = "https://files.pythonhosted.org/packages/2a/8e/096d00c7c480ef2ff4265349b14e2261d4ab787ba1f74e2e80d1c58079c3/regex-2026.7.19-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9dce8ec9695f531a1b8a6f314fd4b393adcccf2ea861db480cdf97a301d01a68", size = 801798, upload-time = "2026-07-19T00:17:17.208Z" }, { url = "https://files.pythonhosted.org/packages/f0/41/e7ecac6edb5722417f85cc67eaf386322fbe8acf6918ec2fdc37c20dd9d0/regex-2026.7.19-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3080a7fd38ef049bd489e01c970c97dd84ff446a885b0f1f6b26d9b1ad13ce11", size = 776933, upload-time = "2026-07-19T00:17:19.347Z" }, { url = "https://files.pythonhosted.org/packages/6f/69/03c9b3f058d66403e0ca2c938696e81d51cd4c6d47ec5265f02f96948d9a/regex-2026.7.19-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d793a7988e04fcb1e2e135567443d82173225d657419ec09414a9b5a145b986", size = 784338, upload-time = "2026-07-19T00:17:21.057Z" }, { url = "https://files.pythonhosted.org/packages/f6/f7/b38ab3d43f284afbb618fcd15d0e77eb786ae461ce1f6bc7494619ddc0f2/regex-2026.7.19-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e8b0abe7d870f53ca5143895fef7d1041a0c831a140d3dc2c760dd7ba25d4a8b", size = 860452, upload-time = "2026-07-19T00:17:23.119Z" }, { url = "https://files.pythonhosted.org/packages/15/5c/ff60ef0571121714f3cf9920bc183071e384a10b556d042e0fdb06cc07a5/regex-2026.7.19-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4e5413bd5f13d3a4e3539ca98f70f75e7fca92518dd7f117f030ebedd10b60cb", size = 765958, upload-time = "2026-07-19T00:17:24.81Z" }, { url = "https://files.pythonhosted.org/packages/aa/0f/bd34021162c0ab47f9a315bd56cd5642e920c8e5668a75ef6c6a6fca590d/regex-2026.7.19-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:73b133a9e6fb512858e7f065e96f1180aa46646bc74a83aea62f1d314f3dd035", size = 851765, upload-time = "2026-07-19T00:17:26.993Z" }, { url = "https://files.pythonhosted.org/packages/2a/20/a2ca43edade0595cccfdc98636739f536d9e26898e7dbddc2b9e98898953/regex-2026.7.19-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbe6493fbd27321b1d1f2dd4f5c7e5bd4d8b1d7cab7f32fd67db3d0b2ed8248a", size = 789714, upload-time = "2026-07-19T00:17:28.699Z" }, { url = "https://files.pythonhosted.org/packages/5d/47/e02db4015d424fc83c00ea0ac8c5e5ec14397943de9abf909d5ce3a25931/regex-2026.7.19-cp312-cp312-win32.whl", hash = "sha256:ddd67571c10869f65a5d7dde536d1e066e306cc90de57d7de4d5f34802428bb5", size = 267157, upload-time = "2026-07-19T00:17:31.051Z" }, { url = "https://files.pythonhosted.org/packages/08/8e/c780c131f79b42ed22d1bd7da4096c2c35f813e835acd02ef0f018bd892c/regex-2026.7.19-cp312-cp312-win_amd64.whl", hash = "sha256:e30d40268a28d54ce0437031750497004c22602b8e3ab891f759b795a003b312", size = 277777, upload-time = "2026-07-19T00:17:32.848Z" }, { url = "https://files.pythonhosted.org/packages/3e/4c/e4d7e086449bdf379d89774bf1f89dc4a41943f3c5a6125a03905b34b5fb/regex-2026.7.19-cp312-cp312-win_arm64.whl", hash = "sha256:de9208bb427130c82a5dbfd104f92c8876fc9559278c880b3002755bbbe9c83d", size = 277136, upload-time = "2026-07-19T00:17:34.803Z" }, { url = "https://files.pythonhosted.org/packages/5d/3d/84165e4299ff76f3a40fe1f2abf939e976f693383a08d2beea6af62bd2c1/regex-2026.7.19-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f035d9dc1d25eff9d361456572231c7d27b5ccd473ca7dc0adfce732bd006d40", size = 496552, upload-time = "2026-07-19T00:17:36.808Z" }, { url = "https://files.pythonhosted.org/packages/02/a2/a65293e6e4cf28eb7ee1be5335a5386c40d6742e9f47fafc8fec785e16c7/regex-2026.7.19-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c42572142ed0b9d5d261ba727157c426510da78e20828b66bbb855098b8a4e38", size = 296983, upload-time = "2026-07-19T00:17:38.816Z" }, { url = "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40b34dd88658e4fedd2fddbf0275ac970d00614b731357f425722a3ed1983d11", size = 291832, upload-time = "2026-07-19T00:17:40.726Z" }, { url = "https://files.pythonhosted.org/packages/07/cd/42dfbabff3dfc9603c501c0e2e2c5adbb09d127b267bf5348de0af338c15/regex-2026.7.19-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c41c63992bf1874cebb6e7f56fd7d3c007924659a604ae3d90e427d40d4fd13", size = 796775, upload-time = "2026-07-19T00:17:42.382Z" }, { url = "https://files.pythonhosted.org/packages/df/5d/f6a4839f2b934e3eed5973fd07f5929ee97d4c98939fb275ea23c274ee16/regex-2026.7.19-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d3372064506b94dd2c67c845f2db8062e9e9ba84d04e33cb96d7d33c11fe1ae", size = 865687, upload-time = "2026-07-19T00:17:44.185Z" }, { url = "https://files.pythonhosted.org/packages/14/b0/b47d6c36049bc59806a50bd4c86ced70bbe058d787f80281b1d7a9b0e024/regex-2026.7.19-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fce7760bf283405b2c7999cab3da4e72f7deca6396013115e3f7a955db9760da", size = 911962, upload-time = "2026-07-19T00:17:46.442Z" }, { url = "https://files.pythonhosted.org/packages/2a/be/ff61f28f9273658cfe23acbbac5217221f6519960ed401e61dfdab12bc35/regex-2026.7.19-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0d702548d89d572b2929879bc883bb7a4c4709efafe4512cadee56c55c9bd15", size = 801817, upload-time = "2026-07-19T00:17:48.25Z" }, { url = "https://files.pythonhosted.org/packages/c3/bb/8b4f7f26b333f9f79e1b453613c39bb4776f51d38ae66dd0ba31d6b354ca/regex-2026.7.19-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d446c6ac40bb6e05025ccee55b84d80fe9bf8e93010ffc4bb9484f13d498835f", size = 776908, upload-time = "2026-07-19T00:17:50.183Z" }, { url = "https://files.pythonhosted.org/packages/09/13/610110fc5921d380516d03c26b652555f08aa0d23ea78a771231873c3638/regex-2026.7.19-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4c3501bfa814ab07b5580741f9bf78dfdfe146a04057f82df9e2402d2a975939", size = 784426, upload-time = "2026-07-19T00:17:52.454Z" }, { url = "https://files.pythonhosted.org/packages/ca/f5/1ef9e2a83a5947c57ebff0b377cb5727c3d5ec1992317a320d035cd0dbb6/regex-2026.7.19-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c4585c3e64b4f9e583b4d2683f18f5d5d872b3d71dcf24594b74ecc23602fa96", size = 860600, upload-time = "2026-07-19T00:17:54.229Z" }, { url = "https://files.pythonhosted.org/packages/a0/02/073af33a3ec149241d11c80acea91e722aa0adbf05addd50f251c4fe89c3/regex-2026.7.19-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:571fde9741eb0ccde23dd4e0c1d50fbae910e901fa7e629faf39b2dda740d220", size = 765950, upload-time = "2026-07-19T00:17:56.041Z" }, { url = "https://files.pythonhosted.org/packages/81/a9/d1e9f819dc394a568ef370cd56cf25394e957a2235f8370f23b576e5a475/regex-2026.7.19-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:15b364b9b98d6d2fe1a85034c23a3180ff913f46caddc3895f6fd65186255ccc", size = 851794, upload-time = "2026-07-19T00:17:57.897Z" }, { url = "https://files.pythonhosted.org/packages/03/3a/8ae83eda7579feacdf984e71fb9e70635fb6f832eeddca58427ec4fca926/regex-2026.7.19-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffd8893ccc1c2fce6e0d6ca402d716fe1b29db70c7132609a05955e31b2aa8f2", size = 789845, upload-time = "2026-07-19T00:17:59.97Z" }, { url = "https://files.pythonhosted.org/packages/4b/23/c195cbfe5a75fdec64d8f6554fd15237b837919d2c61bdc141d7c807b08b/regex-2026.7.19-cp313-cp313-win32.whl", hash = "sha256:f0fa4fa9c3632d708742baf2282f2055c11d888a790362670a403cbf48a2c404", size = 267135, upload-time = "2026-07-19T00:18:01.958Z" }, { url = "https://files.pythonhosted.org/packages/b2/80/a11de8404b7272b70acb45c1c05987cce60b45d5693da2e176f0e390d564/regex-2026.7.19-cp313-cp313-win_amd64.whl", hash = "sha256:d51ffd3427640fa2da6ade574ceba932f210ad095f65fcc450a2b0a0d454868e", size = 277747, upload-time = "2026-07-19T00:18:04.121Z" }, { url = "https://files.pythonhosted.org/packages/d1/29/0f5c8eff1b4f1f3d83276d365fccecf666afcc7d947420943bf394d07adb/regex-2026.7.19-cp313-cp313-win_arm64.whl", hash = "sha256:c670fe7be5b6020b76bc6e8d2196074657e1327595bca93a389e1a76ab130ad8", size = 277129, upload-time = "2026-07-19T00:18:05.821Z" }, { url = "https://files.pythonhosted.org/packages/dc/4c/44b74742052cedda40f9ae469532a037112f7311a36669a891fba8984bb0/regex-2026.7.19-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db47b561c9afd884baa1f96f797c9ca369872c4b65912bc691cfa99e68340af2", size = 501134, upload-time = "2026-07-19T00:18:07.567Z" }, { url = "https://files.pythonhosted.org/packages/f0/45/bbd038b5e39ee5613a5a689290145b40058cc152c41de9cc23639d2b9734/regex-2026.7.19-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65dcd28d3eba2ab7c2fd906485cc301392b47cc2234790d27d4e4814e02cdfda", size = 299418, upload-time = "2026-07-19T00:18:09.38Z" }, { url = "https://files.pythonhosted.org/packages/65/38/c5bde94b4cedfd5850d64c3f08222d8e1600e84f6ee71d9b44b4b8163f74/regex-2026.7.19-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f2e7f8e2ab6c2922be02c7ec45185aa5bd771e2e57b95455ee343a44d8130dff", size = 294486, upload-time = "2026-07-19T00:18:11.188Z" }, { url = "https://files.pythonhosted.org/packages/d7/6a/2f5e107cb26c960b781967178899daf2787a7ab151844ed3c01d6fc95474/regex-2026.7.19-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe31f28c94402043161876a258a9c6f757cb485905c7614ce8d6cd40e6b7bdc1", size = 811643, upload-time = "2026-07-19T00:18:12.975Z" }, { url = "https://files.pythonhosted.org/packages/37/d4/a2f963406d7d73a62eed84ba05a258afb6cad1b21aa4517443ce40506b78/regex-2026.7.19-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8f6fa298bb4f7f58a33334406218ba74716e68feddf5e4e54cd5d8082705abf", size = 871081, upload-time = "2026-07-19T00:18:14.733Z" }, { url = "https://files.pythonhosted.org/packages/45/a3/44be546340bedb15f13063f5e7fe16793ea4d9ea2e805d09bd174ac27724/regex-2026.7.19-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cc1b2440423a851fad781309dd87843868f4f66a6bcd1ddb9225cf4ec2c84732", size = 917372, upload-time = "2026-07-19T00:18:16.724Z" }, { url = "https://files.pythonhosted.org/packages/f8/f6/e0870b0fd2a40dba0074e4b76e514b21313d37946c9248453e34ec43923e/regex-2026.7.19-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ac59a0900474a52b7c04af8196affc22bd9842acb0950df12f7b813e983609a", size = 816089, upload-time = "2026-07-19T00:18:18.617Z" }, { url = "https://files.pythonhosted.org/packages/ae/27/957e8e22690ad6634572b39b71f130a6105f4d0718bb16849eac00fff147/regex-2026.7.19-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4896db1f4ce0576765b8272aa922df324e0f5b9bb2c3d03044ff32a7234a9aba", size = 785206, upload-time = "2026-07-19T00:18:20.464Z" }, { url = "https://files.pythonhosted.org/packages/76/a4/186e410941e731037c01166069ab86da9f65e8f8110c18009ccf4bd623ee/regex-2026.7.19-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4e6883a021db30511d9fb8cfb0f222ce1f2c369f7d4d8b0448f449a93ba0bdfc", size = 800431, upload-time = "2026-07-19T00:18:22.716Z" }, { url = "https://files.pythonhosted.org/packages/73/9f/e4e10e023d291d64a33e246610b724493bf1ce98e0e59c9b7c837e5acfb7/regex-2026.7.19-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:09523a592938aa9f587fb74467c63ff0cf88fc3df14c82ab0f0517dcf76aaa62", size = 864906, upload-time = "2026-07-19T00:18:24.772Z" }, { url = "https://files.pythonhosted.org/packages/24/57/ccb20b6be5f1f52a053d1ba2a8f7a077edb9d918248b8490d7506c6832b3/regex-2026.7.19-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:1ebac3474b8589fce2f9b225b650afd61448f7c73a5d0255a10cc6366471aed1", size = 773559, upload-time = "2026-07-19T00:18:27.008Z" }, { url = "https://files.pythonhosted.org/packages/a3/82/f3b263cf8fad927dc102891da8502e718b7ff9d19af7a2a07c03865d7188/regex-2026.7.19-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4a0530bb1b8c1c985e7e2122e2b4d3aedd8a3c21c6bfddae6767c4405668b56e", size = 857739, upload-time = "2026-07-19T00:18:29.107Z" }, { url = "https://files.pythonhosted.org/packages/47/2e/1687bd1b6c2aed5e672ccf845fc11557821fe7366d921b50889ea5ce57bf/regex-2026.7.19-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef7eeb108c47ce7bcc9513e51bcb1bf57e8f483d52fce68a8642e3527141ae0", size = 804522, upload-time = "2026-07-19T00:18:31.362Z" }, { url = "https://files.pythonhosted.org/packages/76/7c/cc4e7655181b2d9235b704f2c5e19d8eff002bbc437bae59baee0e381aca/regex-2026.7.19-cp313-cp313t-win32.whl", hash = "sha256:64b6ca7391a1395c2638dd5c7456d67bea44fc6c5e8e92c5dc8aa6a8f23292b4", size = 269141, upload-time = "2026-07-19T00:18:33.479Z" }, { url = "https://files.pythonhosted.org/packages/bb/14/961b4c7b05a2391c32dbc85e27773076671ef8f97f36cec70fe414734c02/regex-2026.7.19-cp313-cp313t-win_amd64.whl", hash = "sha256:f04b9f56b0e0614c0126be12c2c2d9f8850c1e57af302bd0a63bed379d4af974", size = 280036, upload-time = "2026-07-19T00:18:35.419Z" }, { url = "https://files.pythonhosted.org/packages/ce/67/795644550d788ddbb6dc458c95895f8009978ea6d6ea76b005eb3f45e8c9/regex-2026.7.19-cp313-cp313t-win_arm64.whl", hash = "sha256:fcee38cd8e5089d6d4f048ba1233b3ad76e5954f545382180889112ff5cb712d", size = 279394, upload-time = "2026-07-19T00:18:37.454Z" }, { url = "https://files.pythonhosted.org/packages/d2/25/0c4c452f8ef3efe456745b2f33195f5904b573fb4c2ff3f0cb9ec188461e/regex-2026.7.19-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a81758ed242b861b72e778ba34d41366441a2e10b16b472784c88da2dea7e2dd", size = 496750, upload-time = "2026-07-19T00:18:39.633Z" }, { url = "https://files.pythonhosted.org/packages/24/9e/b70ca6c1704f6c7cd32a9e143c86cc5968d10981eca284bad670c245ea7d/regex-2026.7.19-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4aa5435cdb3eb6f55fe98a171b05e3fbcd95fadaa4aa32acf62afd9b0cfdbcac", size = 297093, upload-time = "2026-07-19T00:18:41.583Z" }, { url = "https://files.pythonhosted.org/packages/87/74/0b692da2520d51fbff19c88b83d97e4c702909dd02386c585998b7e2dbed/regex-2026.7.19-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:60be8693a1dadc210bbcbc0db3e26da5f7d01d1d5a3da594e99b4fa42df404f5", size = 292043, upload-time = "2026-07-19T00:18:43.347Z" }, { url = "https://files.pythonhosted.org/packages/e3/a7/1d478e614016045a33feae57446215f9fd65b665a5ceb2f891fb3183bc52/regex-2026.7.19-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d19662dbedbe783d323196312d38f5ba53cf56296378252171985da6899887d3", size = 797214, upload-time = "2026-07-19T00:18:45.362Z" }, { url = "https://files.pythonhosted.org/packages/aa/ae/11b9c9411d92c30e3d2db32df5a31133e4a99a8fc397a604fd08f6c4bffb/regex-2026.7.19-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d15df07081d91b76ff20d43f94592ee110330152d617b730fdbe5ef9fb680053", size = 866433, upload-time = "2026-07-19T00:18:47.315Z" }, { url = "https://files.pythonhosted.org/packages/b1/62/2b2efc4992f91d6d204b24c647c9f9412e85379d92b7c0ab9fdae622327e/regex-2026.7.19-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:56ad4d9f77df871a99e25c37091052a02528ec0eb059de928ee33956b854b45b", size = 911360, upload-time = "2026-07-19T00:18:49.588Z" }, { url = "https://files.pythonhosted.org/packages/14/71/986ceea9aa3da548bf1357cad89b63915ec6d21ec957c8113b29ece567df/regex-2026.7.19-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7322ec6cc9fba9d49ab888bb82d67ac5625627aa168f0165139b17018df3fb8a", size = 801275, upload-time = "2026-07-19T00:18:51.767Z" }, { url = "https://files.pythonhosted.org/packages/15/be/ce9d9534b2cda96eab32c548261224b9b4e220a4126f098f60f42ae7b4cd/regex-2026.7.19-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9c7472192ebfad53a6be7c4a8bfb2d64b81c0e93a1fc8c57e1dd0b638297b5d1", size = 777131, upload-time = "2026-07-19T00:18:54.053Z" }, { url = "https://files.pythonhosted.org/packages/61/2b/58b5c710f2c3929515a25f3a1ca0dad0dcd4518d4fff3cf23bc7adb8dcd2/regex-2026.7.19-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c10b82c2634df08dfb13b1f04e38fe310d086ee092f4f69c0c8da234251e556e", size = 785020, upload-time = "2026-07-19T00:18:56.579Z" }, { url = "https://files.pythonhosted.org/packages/84/03/5fe091935b74f15fe0f97998c215cae418d1c0413f6258c7d4d2e83aa37f/regex-2026.7.19-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:17ed5692f6acc4183e98331101a5f9e4f64d72fe58b753da4d444a2c77d05b12", size = 861263, upload-time = "2026-07-19T00:18:58.64Z" }, { url = "https://files.pythonhosted.org/packages/d8/fa/d60bf82e10841eef62a9e32aac401468f05fddfbcb2942e342b1ba3d2433/regex-2026.7.19-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:22a992de9a0d91bda927bf02b94351d737a0302905432c88a53de7c4b9ce62e2", size = 766199, upload-time = "2026-07-19T00:19:00.705Z" }, { url = "https://files.pythonhosted.org/packages/bf/5d/11e64d151b0662b81d6bf644c74dc118d461df85bdf2577fadbbf751788a/regex-2026.7.19-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:618a0aed532be87294c4477b0481f3aa0f1520f4014a4374dd4cf789b4cd2c97", size = 851317, upload-time = "2026-07-19T00:19:03.015Z" }, { url = "https://files.pythonhosted.org/packages/7c/34/532efb87488d90807bae6a443d357ee5e2728a478c597619c8aaa17cc0bd/regex-2026.7.19-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ce9e679f776649746729b6c86382da519ef649c8e34cc41df0d2e5e0f6c36d4", size = 789557, upload-time = "2026-07-19T00:19:05.338Z" }, { url = "https://files.pythonhosted.org/packages/d6/90/3a8d5ca977171ec3ae21a71207d2228b2663bde14d7f7ef0e6363ecf9290/regex-2026.7.19-cp314-cp314-win32.whl", hash = "sha256:73f272fba87b8ccfe70a137d02a54af386f6d27aa509fbffdd978f5947aae1aa", size = 272531, upload-time = "2026-07-19T00:19:07.487Z" }, { url = "https://files.pythonhosted.org/packages/96/e1/8862885e70409de70e8c005f57fb2e7be8d9ef0317250d60f4c9660a300d/regex-2026.7.19-cp314-cp314-win_amd64.whl", hash = "sha256:d721e53758b2cca74990185eb0671dd466d7a388a1a45d0c6f4c13cef41a68ac", size = 280831, upload-time = "2026-07-19T00:19:09.46Z" }, { url = "https://files.pythonhosted.org/packages/08/82/2693e53e29f9104d9de95d37ce4dd826bd32d5f9c0085d3aa6ac042675c4/regex-2026.7.19-cp314-cp314-win_arm64.whl", hash = "sha256:65fa6cb38ed5e9c3637e68e544f598b39c3b86b808ed0627a67b68320384b459", size = 281099, upload-time = "2026-07-19T00:19:11.398Z" }, { url = "https://files.pythonhosted.org/packages/92/b7/9a01aa16461a18cde9d7b9c3ab21e501db2ce33725f53014342b91df2b0a/regex-2026.7.19-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:5a2721c8720e2cb3c209925dfb9200199b4b07361c9e01d321719404b21458b3", size = 501121, upload-time = "2026-07-19T00:19:13.425Z" }, { url = "https://files.pythonhosted.org/packages/f3/5e/bbaeca815dc9191c424c94a4fdc5c87c75748a64a6271821212ebdd4e1a3/regex-2026.7.19-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:199535629f25caf89698039af3d1ad5fcae7f933e2112c73f1cdf49165c99518", size = 299415, upload-time = "2026-07-19T00:19:15.43Z" }, { url = "https://files.pythonhosted.org/packages/cd/d6/0dd1a321afaab95eb7ff44aa0f637301786f1dc71c6b797b9ed236ed8890/regex-2026.7.19-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9b60d7814174f059e5de4ab98271cc5ba9259cfea55273a81544dceea32dc8d9", size = 294483, upload-time = "2026-07-19T00:19:17.879Z" }, { url = "https://files.pythonhosted.org/packages/92/5f/40bacf91d0904f812e13bbbab3864604c463eced8afdc54aeaa50492ea95/regex-2026.7.19-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbece16025afda5e3031af0c4059207e61dcf73ef13af844964f57f387d1c435", size = 811833, upload-time = "2026-07-19T00:19:20.102Z" }, { url = "https://files.pythonhosted.org/packages/94/7c/4902744261f775aeede8b5627314b38482da29cf49a57b66a6fb753246c5/regex-2026.7.19-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d24ecb4f5e009ea0bd275ee37ad9953b32005e2e5e60f8bbae16da0dbbf0d3a0", size = 871270, upload-time = "2026-07-19T00:19:22.365Z" }, { url = "https://files.pythonhosted.org/packages/16/70/6980c9be6bf21c0a60ed3e0aea39cf419ecf3b08d1d9947bc56e196ef186/regex-2026.7.19-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8cae6fd77a5b72dae505084b1a2ee0360139faf72fedbab667cd7cc65aae7a6a", size = 917534, upload-time = "2026-07-19T00:19:24.529Z" }, { url = "https://files.pythonhosted.org/packages/52/92/8b2bd872782ce8c42691e39acb38eb8efe014e5ddb78ad7d943d6f197ce9/regex-2026.7.19-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9724e6cb5e478cd7d8cabf027826178739cb18cf0e117d0e32814d479fa02276", size = 816135, upload-time = "2026-07-19T00:19:26.919Z" }, { url = "https://files.pythonhosted.org/packages/de/2d/33a602f657bdc4041f17d79f92ab18261d255d91a06117a6e29df023e5e2/regex-2026.7.19-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:572fc57b0009c735ee56c175ea021b637a15551a312f56734277f923d6fd0f6c", size = 785492, upload-time = "2026-07-19T00:19:29.192Z" }, { url = "https://files.pythonhosted.org/packages/9e/36/0987cf4cb271680064a70d24a475873775a151d0b7058698a006cb0cae4a/regex-2026.7.19-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:20568e182eb82d39a6bf7cff3fd58566f14c75c6f74b2c8c96537eecf9010e3a", size = 800658, upload-time = "2026-07-19T00:19:31.392Z" }, { url = "https://files.pythonhosted.org/packages/a8/24/c14f31c135e1ba55fa4f9a58ca98d0842512bf6188230763c31c8f449e3b/regex-2026.7.19-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:1d58561843f0ff7dc78b4c28b5e2dc388f3eff94ebc8a232a3adba961fc00009", size = 865073, upload-time = "2026-07-19T00:19:33.485Z" }, { url = "https://files.pythonhosted.org/packages/14/85/181a12211f22469f24d2de1ebddfe397d2396e2c29013b9a58134a91069a/regex-2026.7.19-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:61bb1bd45520aacd56dd80943bd34991fb5350afdd1f36f2282230fd5154a218", size = 773684, upload-time = "2026-07-19T00:19:35.599Z" }, { url = "https://files.pythonhosted.org/packages/23/58/bd1a0c1a62251366f8d21f41b1ea3c76994962071b8b6ea42f72d505c0f0/regex-2026.7.19-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:cd3584591ea4429026cdb931b054342c2bcf189b44ff367f8d5c15bc092a2966", size = 857769, upload-time = "2026-07-19T00:19:37.738Z" }, { url = "https://files.pythonhosted.org/packages/e4/4f/f7e2dad6756b2fe1fe75dd90a628c3b45f249d39f948dd90cd2476325417/regex-2026.7.19-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5cc26a66e212fa5d6c6170c3a40d99d888db3020c6fdab1523250d4341382e44", size = 804546, upload-time = "2026-07-19T00:19:40.229Z" }, { url = "https://files.pythonhosted.org/packages/2b/d7/01d31d5bdb09bc026fab77f59a371fdf8f9b292e4810546c56182ca70498/regex-2026.7.19-cp314-cp314t-win32.whl", hash = "sha256:2c4e61e2e1be56f63ec3cc618aa9e0de81ef6f43d177205451840022e24f5b78", size = 274526, upload-time = "2026-07-19T00:19:42.398Z" }, { url = "https://files.pythonhosted.org/packages/52/0e/cea4ce73bc0a8247a0748228ae6669984c7e1f8134b6fa66e59c0572e0ea/regex-2026.7.19-cp314-cp314t-win_amd64.whl", hash = "sha256:c639ea314df70a7b2811e8020448c75af8c9445f5a60f8a4ced81c306a9380c2", size = 283763, upload-time = "2026-07-19T00:19:44.644Z" }, { url = "https://files.pythonhosted.org/packages/6f/b6/26e41975febae63b7a6e3e02f32cff6cff2e4f10d19c929082f56aebf7c6/regex-2026.7.19-cp314-cp314t-win_arm64.whl", hash = "sha256:9a15e785f244f3e07847b984ce8773fc3da10a9f3c131cc49a4c5b4d672b4547", size = 283451, upload-time = "2026-07-19T00:19:46.639Z" }, ] [[package]] name = "requests" version = "2.34.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, { name = "idna" }, { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, ] [[package]] name = "requests-mock" version = "1.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/92/32/587625f91f9a0a3d84688bf9cfc4b2480a7e8ec327cefd0ff2ac891fd2cf/requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401", size = 60901, upload-time = "2024-03-29T03:54:29.446Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/97/ec/889fbc557727da0c34a33850950310240f2040f3b1955175fdb2b36a8910/requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563", size = 27695, upload-time = "2024-03-29T03:54:27.64Z" }, ] [[package]] name = "requests-oauthlib" version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "oauthlib" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, ] [[package]] name = "requests-ratelimiter" version = "0.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyrate-limiter" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/71/aecc6307695ddad2d11f474cd79d79b111ee90dd123d697b76eaa1cd73a1/requests_ratelimiter-0.10.0.tar.gz", hash = "sha256:9c1a78d7646caa5ccf211a6c341abd16d329be2c8c35044a418aa9da7c0e7a33", size = 17190, upload-time = "2026-04-22T18:11:15.925Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f1/87/c94855590fde39c87cf671d242e555984d93e76d2029a6a3ad3a67a072ad/requests_ratelimiter-0.10.0-py3-none-any.whl", hash = "sha256:79a3e44c13de8d72705512696b44b94265bd96d997580c73e480373814af228e", size = 11408, upload-time = "2026-04-22T18:11:14.398Z" }, ] [[package]] name = "resampy" version = "0.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numba" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/29/f1/34be702a69a5d272e844c98cee82351f880985cfbca0cc86378011078497/resampy-0.4.3.tar.gz", hash = "sha256:a0d1c28398f0e55994b739650afef4e3974115edbe96cd4bb81968425e916e47", size = 3080604, upload-time = "2024-03-05T20:36:08.119Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/b9/3b00ac340a1aab3389ebcc52c779914a44aadf7b0cb7a3bf053195735607/resampy-0.4.3-py3-none-any.whl", hash = "sha256:ad2ed64516b140a122d96704e32bc0f92b23f45419e8b8f478e5a05f83edcebd", size = 3076529, upload-time = "2024-03-05T20:36:02.439Z" }, ] [[package]] name = "responses" version = "0.26.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyyaml" }, { name = "requests" }, { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/1a/4af3e6d659394b809838490b144e4ab8d7ed3b9fecc7ca78f5d2f79b1a3d/responses-0.26.2.tar.gz", hash = "sha256:9c9259b46a8349197edebf43cfa68a87e1a2802ef503ff8b2fecbabc0b45afd8", size = 84030, upload-time = "2026-07-03T16:44:50.325Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl", hash = "sha256:6fdfeabd58e5ec473b98dfe02e6d46d3173bd8dd573eff2ccccf1a05a5135364", size = 35609, upload-time = "2026-07-03T16:44:49.1Z" }, ] [[package]] name = "roman" version = "5.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9c/7c/3901b35ed856329bf98e84da8e5e0b4d899ea0027eee222f1be42a24ff3f/roman-5.2.tar.gz", hash = "sha256:275fe9f46290f7d0ffaea1c33251b92b8e463ace23660508ceef522e7587cb6f", size = 8185, upload-time = "2025-11-11T08:03:57.025Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/10/14/ea3cdd7276fcd731a9003fe4abeb6b395a38110ddff6a6a509f4ee00f741/roman-5.2-py3-none-any.whl", hash = "sha256:89d3b47400388806d06ff77ea77c79ab080bc127820dea6bf34e1f1c1b8e676e", size = 6041, upload-time = "2025-11-11T08:03:56.051Z" }, ] [[package]] name = "roman-numerals" version = "4.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2", size = 9077, upload-time = "2025-12-17T18:25:34.381Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, ] [[package]] name = "roman-numerals-py" version = "4.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "roman-numerals" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cb/b5/de96fca640f4f656eb79bbee0e79aeec52e3e0e359f8a3e6a0d366378b64/roman_numerals_py-4.1.0.tar.gz", hash = "sha256:f5d7b2b4ca52dd855ef7ab8eb3590f428c0b1ea480736ce32b01fef2a5f8daf9", size = 4274, upload-time = "2025-12-17T18:25:41.153Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/2c/daca29684cbe9fd4bc711f8246da3c10adca1ccc4d24436b17572eb2590e/roman_numerals_py-4.1.0-py3-none-any.whl", hash = "sha256:553114c1167141c1283a51743759723ecd05604a1b6b507225e91dc1a6df0780", size = 4547, upload-time = "2025-12-17T18:25:40.136Z" }, ] [[package]] name = "ruamel-yaml" version = "0.19.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c7/3b/ebda527b56beb90cb7652cb1c7e4f91f48649fbcd8d2eb2fb6e77cd3329b/ruamel_yaml-0.19.1.tar.gz", hash = "sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993", size = 142709, upload-time = "2026-01-02T16:50:31.84Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93", size = 118102, upload-time = "2026-01-02T16:50:29.201Z" }, ] [[package]] name = "ruff" version = "0.16.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4d/94/1e5e4967626faf12fa56999cd6222dff6992ceb086ad7945756baf70c7a7/ruff-0.16.0.tar.gz", hash = "sha256:e460aafd5495ec89efaa6ced2e4a9a581116451e1c88b9d37ef497e0f8e93982", size = 4790557, upload-time = "2026-07-23T19:11:30.981Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4b/81/1c8818fee7ce1a04cd7d1b3172e0a8f8e4f1dc4feb7fc390e16daa8af323/ruff-0.16.0-py3-none-linux_armv6l.whl", hash = "sha256:e5115729eb08c585e5121978ba5d5b60caeae394ce21b9fb5e6cd33a1c6c9b1e", size = 10754633, upload-time = "2026-07-23T19:10:46.415Z" }, { url = "https://files.pythonhosted.org/packages/23/df/beaf59c09d68db84304d555f188b276a77132a5d5b0b67a5c762aa143628/ruff-0.16.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3c954b1d580bfa035b41654f7858cc7e71d5fc3ac5b723dd62bd9133830ed522", size = 10969164, upload-time = "2026-07-23T19:10:50.271Z" }, { url = "https://files.pythonhosted.org/packages/42/ce/741cd197496a1abbf51352710fd15ed995d2a2be87189c1da26a450d6e83/ruff-0.16.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e01c21d10eb1b29f47b7454e1f4056db9a3f0260c646aa88457c610291db9f81", size = 10488846, upload-time = "2026-07-23T19:10:52.639Z" }, { url = "https://files.pythonhosted.org/packages/52/2a/a2db8e88cade358f5cdcb05674a917751074109315d014eb6352d9a893f7/ruff-0.16.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e364e5ed22ed8dc05082fd78e35308618260907ac2d3c1d637b2e682415b6c9", size = 10889729, upload-time = "2026-07-23T19:10:54.89Z" }, { url = "https://files.pythonhosted.org/packages/42/65/62a771694ebd63029dc953e27dbad40e1588bd4860ff9fe881018fddaa49/ruff-0.16.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d327b8fc113a1d4421a04f3839d3752057c8dd1ee320223a6f3f52d04ada462a", size = 10568275, upload-time = "2026-07-23T19:10:56.993Z" }, { url = "https://files.pythonhosted.org/packages/3f/e2/ced249fe8af5f086c5c58cc21cc3356d50f32f7401c5df87050c999620a7/ruff-0.16.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b50c55e263103586b3dcf5f73d479eb8cb5fdb6098fec59a62891dab653717", size = 11385112, upload-time = "2026-07-23T19:10:59.615Z" }, { url = "https://files.pythonhosted.org/packages/87/0b/05154977a8fd69eeb6c103271f55403bfd8711f5c0f8ed07489d95a504e7/ruff-0.16.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ff4a79ce3ec0172f3241943835de1c4cb4e2dcd07f0f8c2d02603dbbbee4b17", size = 12207008, upload-time = "2026-07-23T19:11:02.154Z" }, { url = "https://files.pythonhosted.org/packages/fb/29/98225831a3a1eab0e02f4acc6ca6559a98611dcc68b6965ff4b7234627c1/ruff-0.16.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e95c448fca1fb2a18372a9440926c5a6ee789639bb975c72e7ae6d0b04218ab4", size = 11650842, upload-time = "2026-07-23T19:11:04.557Z" }, { url = "https://files.pythonhosted.org/packages/91/66/6bd3cf90500653d55dc0ffc8507aa8300bd49d0214b2e8cb4d3fef2943ba/ruff-0.16.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f11a8d11010301d0a398a2fdef67691feca7294da6aef55e2150e8fa2cd520b", size = 11400718, upload-time = "2026-07-23T19:11:09.233Z" }, { url = "https://files.pythonhosted.org/packages/8e/a2/a54eb4eae05d66364050a5d3b8a9c5ef88196531b3cbe7109d873f87f819/ruff-0.16.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:48044c678e9cb8698246c99b14aaccfa6601dea7379eb48a6f8f73f7a6d86cd0", size = 11426177, upload-time = "2026-07-23T19:11:11.994Z" }, { url = "https://files.pythonhosted.org/packages/1a/be/16e3eea4b2a478a496919f5e36f17c4559e54620bd3bbac5d6affa068006/ruff-0.16.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7aa0959bad8eb8bef50340154fc9b58678dae31fa4293afa38b44b6e552c0213", size = 10856126, upload-time = "2026-07-23T19:11:14.221Z" }, { url = "https://files.pythonhosted.org/packages/a2/84/252eb8b868a16eec7257c14f504f77537e734b2d69c762e639e588e304a3/ruff-0.16.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28ea2b7df8ebf7f9da6b7d47b230ab48f387c0a29be3b474c4d0740e197bb9af", size = 10571208, upload-time = "2026-07-23T19:11:16.378Z" }, { url = "https://files.pythonhosted.org/packages/21/09/817a482f542f7570cbb4554b26e896610c7114f539b1d9e2d2145bf6bef6/ruff-0.16.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:33a3dfac8c35f81498dea9181bccc2f4c4bc8f1521a1dd9406e77643e0f0fb09", size = 11063329, upload-time = "2026-07-23T19:11:19.173Z" }, { url = "https://files.pythonhosted.org/packages/2e/23/9403c180ca1cb9b1f7335f5c3e5305c09d49ea5b345196682a36028bde4a/ruff-0.16.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a5237a0bda500d30d81b8e07a6973a5cbc772864cbf746ae2f4e8a2e01c9f4ed", size = 11489751, upload-time = "2026-07-23T19:11:21.74Z" }, { url = "https://files.pythonhosted.org/packages/b2/1d/1b2ef7bcde851c78d7f17f1cca13fd6dc695fc4b3d6197941e72cae5b132/ruff-0.16.0-py3-none-win32.whl", hash = "sha256:7fab76fa065c873f41ff744347c6e77bcc3dfec4bcc754dc26b63d23c0f7f5fb", size = 10785885, upload-time = "2026-07-23T19:11:23.947Z" }, { url = "https://files.pythonhosted.org/packages/b2/a3/d5e4ef7a56be3f928ffb90b94c25ba7d3cb9c7fe0736aeaaedf361770712/ruff-0.16.0-py3-none-win_amd64.whl", hash = "sha256:429c117f022bf481fabd9d551e7a3952b24c65e6ef44337ea09d90bebef14472", size = 11923141, upload-time = "2026-07-23T19:11:26.409Z" }, { url = "https://files.pythonhosted.org/packages/cb/9a/8415f2657cbe200f41a4531ccededf135505a92d4a012229121f885b26f9/ruff-0.16.0-py3-none-win_arm64.whl", hash = "sha256:14296fedcd2705c77ab8235439278bbb38f285cf7da5528b00b3e330c3d4872d", size = 11273407, upload-time = "2026-07-23T19:11:28.705Z" }, ] [[package]] name = "scikit-learn" version = "1.7.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ { name = "joblib" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" } }, { name = "threadpoolctl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, { url = "https://files.pythonhosted.org/packages/43/83/564e141eef908a5863a54da8ca342a137f45a0bfb71d1d79704c9894c9d1/scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e", size = 9331967, upload-time = "2025-09-09T08:20:32.421Z" }, { url = "https://files.pythonhosted.org/packages/18/d6/ba863a4171ac9d7314c4d3fc251f015704a2caeee41ced89f321c049ed83/scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1", size = 8648645, upload-time = "2025-09-09T08:20:34.436Z" }, { url = "https://files.pythonhosted.org/packages/ef/0e/97dbca66347b8cf0ea8b529e6bb9367e337ba2e8be0ef5c1a545232abfde/scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d", size = 9715424, upload-time = "2025-09-09T08:20:36.776Z" }, { url = "https://files.pythonhosted.org/packages/f7/32/1f3b22e3207e1d2c883a7e09abb956362e7d1bd2f14458c7de258a26ac15/scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1", size = 9509234, upload-time = "2025-09-09T08:20:38.957Z" }, { url = "https://files.pythonhosted.org/packages/9f/71/34ddbd21f1da67c7a768146968b4d0220ee6831e4bcbad3e03dd3eae88b6/scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1", size = 8894244, upload-time = "2025-09-09T08:20:41.166Z" }, { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818, upload-time = "2025-09-09T08:20:43.19Z" }, { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997, upload-time = "2025-09-09T08:20:45.468Z" }, { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381, upload-time = "2025-09-09T08:20:47.982Z" }, { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296, upload-time = "2025-09-09T08:20:50.366Z" }, { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256, upload-time = "2025-09-09T08:20:52.627Z" }, { url = "https://files.pythonhosted.org/packages/ae/93/a3038cb0293037fd335f77f31fe053b89c72f17b1c8908c576c29d953e84/scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7", size = 9212382, upload-time = "2025-09-09T08:20:54.731Z" }, { url = "https://files.pythonhosted.org/packages/40/dd/9a88879b0c1104259136146e4742026b52df8540c39fec21a6383f8292c7/scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe", size = 8592042, upload-time = "2025-09-09T08:20:57.313Z" }, { url = "https://files.pythonhosted.org/packages/46/af/c5e286471b7d10871b811b72ae794ac5fe2989c0a2df07f0ec723030f5f5/scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f", size = 9434180, upload-time = "2025-09-09T08:20:59.671Z" }, { url = "https://files.pythonhosted.org/packages/f1/fd/df59faa53312d585023b2da27e866524ffb8faf87a68516c23896c718320/scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0", size = 9283660, upload-time = "2025-09-09T08:21:01.71Z" }, { url = "https://files.pythonhosted.org/packages/a7/c7/03000262759d7b6f38c836ff9d512f438a70d8a8ddae68ee80de72dcfb63/scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c", size = 8702057, upload-time = "2025-09-09T08:21:04.234Z" }, { url = "https://files.pythonhosted.org/packages/55/87/ef5eb1f267084532c8e4aef98a28b6ffe7425acbfd64b5e2f2e066bc29b3/scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8", size = 9558731, upload-time = "2025-09-09T08:21:06.381Z" }, { url = "https://files.pythonhosted.org/packages/93/f8/6c1e3fc14b10118068d7938878a9f3f4e6d7b74a8ddb1e5bed65159ccda8/scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a", size = 9038852, upload-time = "2025-09-09T08:21:08.628Z" }, { url = "https://files.pythonhosted.org/packages/83/87/066cafc896ee540c34becf95d30375fe5cbe93c3b75a0ee9aa852cd60021/scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c", size = 9527094, upload-time = "2025-09-09T08:21:11.486Z" }, { url = "https://files.pythonhosted.org/packages/9c/2b/4903e1ccafa1f6453b1ab78413938c8800633988c838aa0be386cbb33072/scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c", size = 9367436, upload-time = "2025-09-09T08:21:13.602Z" }, { url = "https://files.pythonhosted.org/packages/b5/aa/8444be3cfb10451617ff9d177b3c190288f4563e6c50ff02728be67ad094/scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973", size = 9275749, upload-time = "2025-09-09T08:21:15.96Z" }, { url = "https://files.pythonhosted.org/packages/d9/82/dee5acf66837852e8e68df6d8d3a6cb22d3df997b733b032f513d95205b7/scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33", size = 9208906, upload-time = "2025-09-09T08:21:18.557Z" }, { url = "https://files.pythonhosted.org/packages/3c/30/9029e54e17b87cb7d50d51a5926429c683d5b4c1732f0507a6c3bed9bf65/scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615", size = 8627836, upload-time = "2025-09-09T08:21:20.695Z" }, { url = "https://files.pythonhosted.org/packages/60/18/4a52c635c71b536879f4b971c2cedf32c35ee78f48367885ed8025d1f7ee/scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106", size = 9426236, upload-time = "2025-09-09T08:21:22.645Z" }, { url = "https://files.pythonhosted.org/packages/99/7e/290362f6ab582128c53445458a5befd471ed1ea37953d5bcf80604619250/scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61", size = 9312593, upload-time = "2025-09-09T08:21:24.65Z" }, { url = "https://files.pythonhosted.org/packages/8e/87/24f541b6d62b1794939ae6422f8023703bbf6900378b2b34e0b4384dfefd/scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8", size = 8820007, upload-time = "2025-09-09T08:21:26.713Z" }, ] [[package]] name = "scikit-learn" version = "1.9.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] dependencies = [ { name = "joblib" }, { name = "narwhals" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" } }, { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "threadpoolctl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fa/6f/37092bdb25f712817231799fc5674d8e704066a8a70c1d2d40517e18b4ab/scikit_learn-1.9.0.tar.gz", hash = "sha256:8833266989d3a5110178a9fae30783675460724d0e1efb13b14901d2c660c557", size = 7750767, upload-time = "2026-06-02T11:54:32.706Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f5/be/e844fd9586e66540a15b71924d17a6cbc1bb749e81ddd0a796bcdba4c055/scikit_learn-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9db6f4d34e68c8899e4cab27fdf8eafe6ed21f2ba52ceb25ea250cd237f8e47b", size = 8789686, upload-time = "2026-06-02T11:53:05.439Z" }, { url = "https://files.pythonhosted.org/packages/42/e2/ff880f62677a17d035817d543cb0fc8727d01eccbee81c5f7fc733a9d856/scikit_learn-1.9.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f401448645a3e7bc115aa3c094097865155b34bff1cba8101857d9104e99074c", size = 8256782, upload-time = "2026-06-02T11:53:08.904Z" }, { url = "https://files.pythonhosted.org/packages/25/64/eb40435e1a508ab1b4e284ce43ae80f6a162e5be5e38ed5a6fab467a9ea4/scikit_learn-1.9.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd3a8ef0c758555a3b23c03adaa858af32f7736785ded50ad5991f59c4ed03fa", size = 8992419, upload-time = "2026-06-02T11:53:11.551Z" }, { url = "https://files.pythonhosted.org/packages/8d/da/4810a28e473185429e45a57eebcc91fc991b33d889cc0676063e671db03d/scikit_learn-1.9.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7e254636164090da847715a27f8e5478feb98c40a9e0ee90cbd277de9e5ceb8", size = 9281411, upload-time = "2026-06-02T11:53:15.063Z" }, { url = "https://files.pythonhosted.org/packages/3b/67/be3d369f40d8178ba3bd86635d132e08cb5329b023e4669d9426d84bc007/scikit_learn-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:5dc1818c77575d149e25fce9ef82dd7b7263ae372f03494158668ad632a69759", size = 8272736, upload-time = "2026-06-02T11:53:18.108Z" }, { url = "https://files.pythonhosted.org/packages/37/79/a733f02dc2118da7e77a134b34f39f40201a353311b011d20859d2db3556/scikit_learn-1.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:366652351f092b219c248f1e72821e841960a63d8f358f1dcfd54dc1cbdbbc28", size = 7919564, upload-time = "2026-06-02T11:53:21.2Z" }, { url = "https://files.pythonhosted.org/packages/ac/20/75f915ff375d6249e6550ac740fdbbd66159a068fd3af1400ff62036b07a/scikit_learn-1.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2bd41b0d201bc81575531b96b713d3eb5e5f50fb0b82101ff0f92294fdc236ac", size = 8741122, upload-time = "2026-06-02T11:53:24.08Z" }, { url = "https://files.pythonhosted.org/packages/cc/d5/2b5148f2279196775e1db2aeb85d14b70ac80e7e32b3b28e7ebeafb0901d/scikit_learn-1.9.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5be45aa4a42a68a533913a6ed736cf309de2226411c79ef8d609a5456f1939b1", size = 8261512, upload-time = "2026-06-02T11:53:27.183Z" }, { url = "https://files.pythonhosted.org/packages/a0/ee/5adbc77656b71f9456a2f5a7a9fdb4bcf9207a6b962889f1c2f9323afa4e/scikit_learn-1.9.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e50ed4da51974e86e940690e9a3d82e729b62b5a49f7c9bac534d515d39d86f", size = 8837603, upload-time = "2026-06-02T11:53:30.328Z" }, { url = "https://files.pythonhosted.org/packages/6c/c2/63fdda36c56437eeb44aaf9493c8bcd62ce230ab1598924fc626ffbfa943/scikit_learn-1.9.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:056c92bb67ad4c28463c2f2653d9701449201e7e7a9e94e321be0f71c4fef2b8", size = 9132097, upload-time = "2026-06-02T11:53:33.456Z" }, { url = "https://files.pythonhosted.org/packages/83/a4/c8e67227c680e2259c8864ae72ff48b06e16a6f51253a22167aa02a8aa4e/scikit_learn-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:4306775fad04cc4b472a1b15af1ae9cede1540fbfcc17fbce3767cd8dc7ae283", size = 8211173, upload-time = "2026-06-02T11:53:36.602Z" }, { url = "https://files.pythonhosted.org/packages/cf/fd/3c0863792e98e67e9184aa4029288a175935eb65443afcd30d4f143450cf/scikit_learn-1.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:26e22435f63bcdcf396b574273f29f13dd531f5ea035801f5be10ba1540a4e60", size = 7867451, upload-time = "2026-06-02T11:53:39.075Z" }, { url = "https://files.pythonhosted.org/packages/3c/01/cf3310626b6d48d3e9be69a1223f9180360b5e6edb045f50fade723ce494/scikit_learn-1.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:80746d63bd4b6eaca54d36fe5feaf4d28bb38dc6f9470f81c7cad7c40155f119", size = 8705188, upload-time = "2026-06-02T11:53:41.964Z" }, { url = "https://files.pythonhosted.org/packages/3e/04/5acd7ae280c5f93b6ac5ef6cdec14eef4c8d1cd91d85b3292989c94d96b1/scikit_learn-1.9.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5b934c45c252844a91d69fda3a34cff5e7307e1db10d77cb10a3980312c74713", size = 8228299, upload-time = "2026-06-02T11:53:44.817Z" }, { url = "https://files.pythonhosted.org/packages/0c/39/ffe829a5b8ecb40a518724a997794657fdc354ada5e8fe8e64d998c0bac9/scikit_learn-1.9.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:38c3dcb9a1ffb85505ec53d54c7b4aea0cff70050425a7760c2af661ac85df05", size = 8789690, upload-time = "2026-06-02T11:53:47.461Z" }, { url = "https://files.pythonhosted.org/packages/1f/88/8dab5de10c638c083772a6be83a3d8106ced492f74a928c8693638e5bb50/scikit_learn-1.9.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da76d09304a4706db7cc1e3ebaa3b6b98a67365cc11d2996c4f1e58ba47df714", size = 9087723, upload-time = "2026-06-02T11:53:50.702Z" }, { url = "https://files.pythonhosted.org/packages/20/3f/7917ca72464038f6240ec70c29f94862d08a34a74291ae4d4ec5eb8186a0/scikit_learn-1.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5808d98f15c6bf6d9d96d2348c1997392a5888ce7097e664105f930c4bca1277", size = 8184330, upload-time = "2026-06-02T11:53:53.396Z" }, { url = "https://files.pythonhosted.org/packages/78/c7/15739eb2f61fda3c54639e9942414e5a19ad8a8d1f5a3266afad7cb7df80/scikit_learn-1.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:d77f54c017633791bc0225a43e2f8d03745fdcfe4880268fcc4df15f505dec2e", size = 7840653, upload-time = "2026-06-02T11:53:56.035Z" }, { url = "https://files.pythonhosted.org/packages/f4/7d/c9a35cf59b20a86fec24d306f1547b78dec194b08d367ce2a3e4854169d9/scikit_learn-1.9.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9656acd4e93f74e0b66c8a36c88830a99252dfa900044d36bc2212ae89a47162", size = 8713289, upload-time = "2026-06-02T11:53:58.788Z" }, { url = "https://files.pythonhosted.org/packages/3c/a7/552a7821597c632b907f7bfe8f36f9f572777af8ef8a48353041cf8e091a/scikit_learn-1.9.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:24360002ae845e7866522b0a5bbf690802e7bc388cac8663502e78aa98598aa2", size = 8245141, upload-time = "2026-06-02T11:54:01.694Z" }, { url = "https://files.pythonhosted.org/packages/7d/79/f4a0c4fe9711154cddabf913471153af79056382ddc612cfe5ee0ff4b72e/scikit_learn-1.9.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5162ad10a418c8a282dde04c9aa06965de3e9a65f33c1440c0ae69bb1a09d913", size = 8847671, upload-time = "2026-06-02T11:54:04.448Z" }, { url = "https://files.pythonhosted.org/packages/f0/af/4d72d9e475ac83719160c662619e4bf7b95c19507cd582e7d0167a3c3dae/scikit_learn-1.9.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fea2cc5677ab49d6f5bade978c866da44957b712d92e9635e8b4f723013c3cb", size = 9118104, upload-time = "2026-06-02T11:54:07.205Z" }, { url = "https://files.pythonhosted.org/packages/a2/d5/6a58eea2cb9abbb9b3f2bb8b2cfb3243d1152d69f442d256c7af71304769/scikit_learn-1.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:64fa347efc1c839c487433e40c5144d38c336e8a2b59c81aa8660373945c2673", size = 8290674, upload-time = "2026-06-02T11:54:10.087Z" }, { url = "https://files.pythonhosted.org/packages/65/5b/d4c879cf358f1187141cf90ced473f087183489090244f50c124a2ee478b/scikit_learn-1.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:1b944b6db288f6b926e3650026ddafb988929de95d11fc2cc5fa117773c9ba42", size = 7978807, upload-time = "2026-06-02T11:54:12.769Z" }, { url = "https://files.pythonhosted.org/packages/8a/43/bfae3121ec67ae09150d453c442c7c1cc166e9aefe056e6ab3b7728a5cfc/scikit_learn-1.9.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:4ccacf04ca5f4b492158a5f28afe0ace43f81b2571e4b9a66d34848b46128949", size = 9031941, upload-time = "2026-06-02T11:54:15.436Z" }, { url = "https://files.pythonhosted.org/packages/75/b0/20a4546eb17f3b25d3c66df15810411c14ed5065bcfab50b53c96fb627b2/scikit_learn-1.9.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:ee1a8db2c18c08e34c7412d4b10be1cac214cd4ea7dc9715a6a327eb49a37c96", size = 8613528, upload-time = "2026-06-02T11:54:18.842Z" }, { url = "https://files.pythonhosted.org/packages/18/3c/e440e039bb82cd19004edaaad00acbde0fb9b461083c3ecf37941c557312/scikit_learn-1.9.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:147e9329ef0e39f75d4cffa02b2aa48d827832684926cd5210d9a2cb5c57246b", size = 8855050, upload-time = "2026-06-02T11:54:21.699Z" }, { url = "https://files.pythonhosted.org/packages/43/26/b341b8dab5998da6270a3a42c2152c578501354d36f944b5856757035ef8/scikit_learn-1.9.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bad8f8b9950321b54c965fdcbac6c6c55e79e16646b49977bcf3668d3870a1a", size = 9097190, upload-time = "2026-06-02T11:54:24.454Z" }, { url = "https://files.pythonhosted.org/packages/fb/de/b650b4d69b84468cfa2e28a3ff7b8103743029e6446ce1a97fe060ef688c/scikit_learn-1.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:78fc56eafd4edb9575d2d8950d1dd152061abb573341a1cb7e099fc40f6c6666", size = 8963204, upload-time = "2026-06-02T11:54:27.428Z" }, { url = "https://files.pythonhosted.org/packages/ee/f3/ff83d76d7418112e5a61326443cdda87be3545dd8d6599c95b2481a4419e/scikit_learn-1.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:051075bda8b7aab87b1906ab3d4740a1e1224a19d7b3781a576736edc94e76aa", size = 8222661, upload-time = "2026-06-02T11:54:30.192Z" }, ] [[package]] name = "scipy" version = "1.15.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255, upload-time = "2025-05-08T16:05:14.596Z" }, { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035, upload-time = "2025-05-08T16:05:20.152Z" }, { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499, upload-time = "2025-05-08T16:05:24.494Z" }, { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602, upload-time = "2025-05-08T16:05:29.313Z" }, { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415, upload-time = "2025-05-08T16:05:34.699Z" }, { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622, upload-time = "2025-05-08T16:05:40.762Z" }, { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796, upload-time = "2025-05-08T16:05:48.119Z" }, { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684, upload-time = "2025-05-08T16:05:54.22Z" }, { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504, upload-time = "2025-05-08T16:06:00.437Z" }, { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, ] [[package]] name = "scipy" version = "1.17.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version == '3.11.*'", ] dependencies = [ { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" }, { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" }, { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" }, { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" }, { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" }, { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" }, { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" }, { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" }, { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" }, { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" }, { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" }, { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" }, { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" }, { url = "https://files.pythonhosted.org/packages/35/f5/906eda513271c8deb5af284e5ef0206d17a96239af79f9fa0aebfe0e36b4/scipy-1.17.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c80be5ede8f3f8eded4eff73cc99a25c388ce98e555b17d31da05287015ffa5b", size = 22704017, upload-time = "2026-02-23T00:18:21.502Z" }, { url = "https://files.pythonhosted.org/packages/da/34/16f10e3042d2f1d6b66e0428308ab52224b6a23049cb2f5c1756f713815f/scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e19ebea31758fac5893a2ac360fedd00116cbb7628e650842a6691ba7ca28a21", size = 32927842, upload-time = "2026-02-23T00:18:35.367Z" }, { url = "https://files.pythonhosted.org/packages/01/8e/1e35281b8ab6d5d72ebe9911edcdffa3f36b04ed9d51dec6dd140396e220/scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02ae3b274fde71c5e92ac4d54bc06c42d80e399fec704383dcd99b301df37458", size = 35235890, upload-time = "2026-02-23T00:18:49.188Z" }, { url = "https://files.pythonhosted.org/packages/c5/5c/9d7f4c88bea6e0d5a4f1bc0506a53a00e9fcb198de372bfe4d3652cef482/scipy-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a604bae87c6195d8b1045eddece0514d041604b14f2727bbc2b3020172045eb", size = 35003557, upload-time = "2026-02-23T00:18:54.74Z" }, { url = "https://files.pythonhosted.org/packages/65/94/7698add8f276dbab7a9de9fb6b0e02fc13ee61d51c7c3f85ac28b65e1239/scipy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f590cd684941912d10becc07325a3eeb77886fe981415660d9265c4c418d0bea", size = 37625856, upload-time = "2026-02-23T00:19:00.307Z" }, { url = "https://files.pythonhosted.org/packages/a2/84/dc08d77fbf3d87d3ee27f6a0c6dcce1de5829a64f2eae85a0ecc1f0daa73/scipy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:41b71f4a3a4cab9d366cd9065b288efc4d4f3c0b37a91a8e0947fb5bd7f31d87", size = 36549682, upload-time = "2026-02-23T00:19:07.67Z" }, { url = "https://files.pythonhosted.org/packages/bc/98/fe9ae9ffb3b54b62559f52dedaebe204b408db8109a8c66fdd04869e6424/scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3", size = 24547340, upload-time = "2026-02-23T00:19:12.024Z" }, { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" }, { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" }, { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" }, { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" }, { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" }, { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" }, { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" }, { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" }, { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" }, { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" }, { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" }, { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" }, { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" }, { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" }, { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" }, { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" }, { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" }, { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" }, { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" }, { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" }, { url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" }, { url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" }, { url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" }, { url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" }, { url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" }, { url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" }, { url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" }, { url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" }, { url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" }, { url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" }, { url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" }, { url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" }, { url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" }, { url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" }, { url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" }, { url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" }, { url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" }, { url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" }, { url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" }, { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" }, ] [[package]] name = "scipy" version = "1.18.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", ] dependencies = [ { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/25/c2700dfaf6442b4effaa91af24ebce5dc9d31bb4a69706313aae70d72cd0/scipy-1.18.0.tar.gz", hash = "sha256:67b2ad2ad54c72ca6d04975a9b2df8c3638c34ddd5b28738e94fc2b57929d378", size = 30774447, upload-time = "2026-06-19T15:01:43.456Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6a/19/ca10ead60b0acc80b2b833c2c4a4f2ff753d0f58b811f70d911c7e94a25c/scipy-1.18.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:7bd21faaf5a1a3b2eff922d02db5f191b99a6518db9078a8fb23169f6d22259a", size = 31056519, upload-time = "2026-06-19T14:59:45.203Z" }, { url = "https://files.pythonhosted.org/packages/96/72/1e6442a00cd2924d361aa1b642ab6373ec35c6fabf311a760be9f76e0f13/scipy-1.18.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:265915e79107de9f946b855e50d7470d5893ec3f54b342e1aa6201cbdcd8bb6b", size = 28681889, upload-time = "2026-06-19T14:59:48.103Z" }, { url = "https://files.pythonhosted.org/packages/9b/2d/11dd93d21e147a73ba22bd75c0b9208d3a2e0ec76d53170ce7d9029b1015/scipy-1.18.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9ab7b758be6940954a713ee466e2043e9f6e2ed965c1fce5c91039f4be3d90a9", size = 20423580, upload-time = "2026-06-19T14:59:50.665Z" }, { url = "https://files.pythonhosted.org/packages/9c/01/93552f75e0d2a7dd115a45e59209c51e8d514daff02fc887d2623be06fe1/scipy-1.18.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:97b6cddaaee0a779ef6b5ca83c9604b27cc16b2b8fc22c142652df8793319fb8", size = 23054441, upload-time = "2026-06-19T14:59:53.564Z" }, { url = "https://files.pythonhosted.org/packages/3c/23/21f5e703643d66f21faa6b4c73195bfcad70c55efcb4f1ab327cd7c4101a/scipy-1.18.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:52a96e21517c7292375c0e27dd796a811f03fcea5fd4d108fdfea8145dcf17ab", size = 33968720, upload-time = "2026-06-19T14:59:56.415Z" }, { url = "https://files.pythonhosted.org/packages/dd/aa/1b939f6c67ed68635bb538e6752d3dacc02f66535182e939a89581a44e9c/scipy-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f55797419e16e7f30cf88ffb3113ce0467f00cfe3f70d5c281730b21769bfc2", size = 35287115, upload-time = "2026-06-19T14:59:59.411Z" }, { url = "https://files.pythonhosted.org/packages/b6/ff/eec46be7e9234208f801062b53e1983085eddebd693f6c9bfb03b459830d/scipy-1.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ad033410e2e0672ffdc1042110cef20e1c46f8fd0616cee1d44d8d58fad8fc11", size = 35577989, upload-time = "2026-06-19T15:00:02.235Z" }, { url = "https://files.pythonhosted.org/packages/84/ca/210d4759c7210bb7d269437421959b39a33434e2776b60c5cb8a763bb30a/scipy-1.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a55985d54c769c872e64b7f4c8a81cc30ef700cc04296abbbf3705439c126de", size = 37421717, upload-time = "2026-06-19T15:00:05.102Z" }, { url = "https://files.pythonhosted.org/packages/2b/54/9a9edb45345bd6744da5ddfb6628e5d5185920494c6a67ec45b6381004cb/scipy-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:71ccc8faa2dd16ac310233203474a8b5cb67f10dedd54a3116d34943f4b19132", size = 36597428, upload-time = "2026-06-19T15:00:08.112Z" }, { url = "https://files.pythonhosted.org/packages/99/0e/33f32a2a58987e26aec0f7df252cbbad1e90ae77bdbc76f40dd4ed0cf0ea/scipy-1.18.0-cp312-cp312-win_arm64.whl", hash = "sha256:d88363fd9d8fbd3511bd273f1a49efb2a540773ddf92a91d57498ce7dd7f3e76", size = 24351481, upload-time = "2026-06-19T15:00:11.103Z" }, { url = "https://files.pythonhosted.org/packages/05/52/9c0136c2de7ae0779b7b366447766cec6d9f0702c56bb8ffeb04c8fd3af4/scipy-1.18.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:09143f676d157d9f546d663504ef9c1becb819824f1afc018814176411942446", size = 31036107, upload-time = "2026-06-19T15:00:14.03Z" }, { url = "https://files.pythonhosted.org/packages/02/73/0291a64843270f4efb86cdcf2ee0f2048631b65ec6b405398b2b4dbf11bf/scipy-1.18.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5efe260f69417b97ddae455bfb5a95e8359f7f66ad7fa9522a60feb66f169520", size = 28663303, upload-time = "2026-06-19T15:00:16.819Z" }, { url = "https://files.pythonhosted.org/packages/d3/0f/10ffa0b697a572f4e0d48b92a88895d366422f019f723e7e14a84c050dac/scipy-1.18.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:68363b7eaacd8b5dd426df56d782cc156468ac79a127a1b87ca597d6e2e82197", size = 20404960, upload-time = "2026-06-19T15:00:19.635Z" }, { url = "https://files.pythonhosted.org/packages/7e/d2/e896cea21ba8edd6c81d4c55b1ffcc717e79698dcbebf9641b4cfb4c6622/scipy-1.18.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:c5557d8be5da8e41353fcd4d21491fdbab83b062fc579e94dc09a7c8ab4f669b", size = 23034074, upload-time = "2026-06-19T15:00:22.107Z" }, { url = "https://files.pythonhosted.org/packages/ea/b2/e83ea34279a52c03374477c74006256ec78df65fc877baa4617d6de1d202/scipy-1.18.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0d13bca67c096d89fb95ced0d8921807300fce0275643aef9533cc63a0773468", size = 33942038, upload-time = "2026-06-19T15:00:24.964Z" }, { url = "https://files.pythonhosted.org/packages/f6/af/e8fe5fb136f51e2b01678b92cb4106d10d8cd68ec147ead2e7cb0ac75398/scipy-1.18.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a46f9273dbd0eb1cefba61c9b8648b4dfe3cbc14a080176f9a73e44b8336dc7f", size = 35266390, upload-time = "2026-06-19T15:00:28.059Z" }, { url = "https://files.pythonhosted.org/packages/3a/49/2c5cbb907b56695fc67517811d1db234dfd83381a84814ec220aded2794d/scipy-1.18.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5aba46108853ddfc77906b6557aac839d2b52e900c1d72a1180adaaab58d265f", size = 35551324, upload-time = "2026-06-19T15:00:31.014Z" }, { url = "https://files.pythonhosted.org/packages/bb/73/eda39f7a2d306ff0ffc574afd13c0bbb6d10a603d9a413998ee269487a80/scipy-1.18.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b6f758e35f12757b5d95c00bc6de2438e229c2664b7a92e96f205959d9f2dfa4", size = 37404785, upload-time = "2026-06-19T15:00:34.072Z" }, { url = "https://files.pythonhosted.org/packages/b7/d2/ae881ee28d014f38e0ccbfd974a06a919ba9af34f1f74bf42b5301891d63/scipy-1.18.0-cp313-cp313-win_amd64.whl", hash = "sha256:1afac4a847207c7ff8efd321734a50b06d0280b3b2a2c0fc2f413101747ad7c7", size = 36554943, upload-time = "2026-06-19T15:00:36.903Z" }, { url = "https://files.pythonhosted.org/packages/70/3a/21154e2d54eb3639c6bf4dbae2e531c68356bfe95990daa30df33b30d556/scipy-1.18.0-cp313-cp313-win_arm64.whl", hash = "sha256:c5dbddf60e58c2312316d097271a8e73d40eaf2eabfa4d95ed7d3695bbf2ce7b", size = 24350911, upload-time = "2026-06-19T15:00:40.062Z" }, { url = "https://files.pythonhosted.org/packages/78/b5/915a19b3de2f7430062b509653563db1633ddbb6f021b06731521115d4e2/scipy-1.18.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4c256ee70c0d1a8a2ace807e199ccd4e3f57037433842abb3fb36bc17eaa9578", size = 31036253, upload-time = "2026-06-19T15:00:43.216Z" }, { url = "https://files.pythonhosted.org/packages/d7/88/b72def7262e150d16be13fca37a96481138d624e700340bc3362a7588929/scipy-1.18.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:2ef3abc54a4ffc53765374b0d5728532dfdd2585ed23f6b11c206a1f0b1b9af8", size = 28673758, upload-time = "2026-06-19T15:00:46.663Z" }, { url = "https://files.pythonhosted.org/packages/91/02/2e636a61a525632c373cf6a9c24442a3ffb79e364d38e98b32042964ac32/scipy-1.18.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2a6af57bd9e4a75d70e4117e78a1bbee84f79ae3fbb6d0111005d6ebcc4cb8d", size = 20415514, upload-time = "2026-06-19T15:00:49.399Z" }, { url = "https://files.pythonhosted.org/packages/c9/b6/2135974442f6aba159d9d39d774a1c8cb19947016725d69fecc685df45bf/scipy-1.18.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:3f1ac564d3bf6c03d861d2cd87a1bea0da2887136f7fb1bf519c05a8971452d6", size = 23034398, upload-time = "2026-06-19T15:00:51.941Z" }, { url = "https://files.pythonhosted.org/packages/f6/e6/ba89ec5abf6ee9257c0d1ec985573f3ae32742c24bc03e016388a40b1b15/scipy-1.18.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40395a5fcd1abee49a5c7aaa98c29db393eedc835138560a588c47ec16156690", size = 33998032, upload-time = "2026-06-19T15:00:54.838Z" }, { url = "https://files.pythonhosted.org/packages/7f/c4/bc41eb19b0fd0db868f4132920879019318d80cc522ad8f2bca4611af808/scipy-1.18.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ca01e8ae69f1b18e9a58d91afead31be3cef0dd905a10249dac559ee15460a0", size = 35283333, upload-time = "2026-06-19T15:00:58.152Z" }, { url = "https://files.pythonhosted.org/packages/53/a4/cbdeef6eb3830a8462a9d4ada814de5fc984345cc9ecf17cbec51a036f1e/scipy-1.18.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7a7f3b01647384dbc3a711e8c6778e0aabbe93959249fef5c7393396bcac0867", size = 35610216, upload-time = "2026-06-19T15:01:01.155Z" }, { url = "https://files.pythonhosted.org/packages/80/4d/b2b82502b65f661d1b789c1665dcdf315d5f12194e06fc0b37946294ebae/scipy-1.18.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6aa94e78ec192a30063a5e72e561c28af769dc311190b24fe91774eff1969709", size = 37418960, upload-time = "2026-06-19T15:01:04.155Z" }, { url = "https://files.pythonhosted.org/packages/93/3e/902d836831474b0ab5a37d16404f7bc5fafd9efba632890e271ba952635f/scipy-1.18.0-cp314-cp314-win_amd64.whl", hash = "sha256:2d8bbdc6c817f5b4006a54d799d4f5bab6f910193cbb9a1ff310833d4d270f61", size = 37288845, upload-time = "2026-06-19T15:01:07.822Z" }, { url = "https://files.pythonhosted.org/packages/b6/43/8d73b337a3bdb14daa0314f0434210747c02d79d729ce1777574a817dcf6/scipy-1.18.0-cp314-cp314-win_arm64.whl", hash = "sha256:18e9575f1569b2c54174e6159d32942e03731177f63dce7975f0a0c88d102f5b", size = 24988971, upload-time = "2026-06-19T15:01:11.076Z" }, { url = "https://files.pythonhosted.org/packages/b4/b4/f11918b0508a2787031a0499a03fbe3546f3bb5ca05d01038c45b278c09a/scipy-1.18.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f351e0dd702687d12a402b867a1b4146a256923e1c38317cbc472f6372b94707", size = 31399325, upload-time = "2026-06-19T15:01:13.723Z" }, { url = "https://files.pythonhosted.org/packages/7b/d1/1f287b57c0ff0ee5185dff3946d92c8017d39b0e431f0ae79a3ff1859512/scipy-1.18.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7c7a51b33ce387193c97f228320cf8e87361daa1bba750638677729598b3e677", size = 29092110, upload-time = "2026-06-19T15:01:16.908Z" }, { url = "https://files.pythonhosted.org/packages/ff/1a/7b74eb6c392fdcb27d414c0e7558a6d0231eb3b6d73571f479bb81ea8794/scipy-1.18.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:84031d7b052a54fae2f8632e0ec802073d385476eb9a63079bce6e23ef9283d4", size = 20833811, upload-time = "2026-06-19T15:01:20.488Z" }, { url = "https://files.pythonhosted.org/packages/7c/ad/f3941716320a7b9cb4d68734a903b45fe16eff5fb7da7e16f2e619304979/scipy-1.18.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:56abf29a7c067dde59be8b9a22d606a4ea1b2f2a4b756d9d903c62818f5dacce", size = 23396644, upload-time = "2026-06-19T15:01:23.364Z" }, { url = "https://files.pythonhosted.org/packages/22/22/1446b62ffe07f9719b7d9b1b6a4e05a772833ae8f441fe4c22c34c9b250f/scipy-1.18.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ad44305cfa24b1ba5803cbbebf033590ccbac1aa5d612d727b785325ab408b0", size = 34079318, upload-time = "2026-06-19T15:01:26.002Z" }, { url = "https://files.pythonhosted.org/packages/56/3b/b87da667098bb470fa30c7011b0ba351ee976dd395c78798c66e941665a3/scipy-1.18.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:945c1761b93f38d7f99ae81ae80c63e621471608c7eeead563f6df025585cd58", size = 35324320, upload-time = "2026-06-19T15:01:28.881Z" }, { url = "https://files.pythonhosted.org/packages/f8/a1/c7932f91909759b0267f75fdea34e91309f96b895757534b76a90b6b4344/scipy-1.18.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1a4441f15d620578772a49e5ab48c0ee1f7a0220e387110283062729136b2553", size = 35699541, upload-time = "2026-06-19T15:01:31.968Z" }, { url = "https://files.pythonhosted.org/packages/f7/86/5185061a1fcc41d18c5dc2463969b3a3964b31d9ac67b2fb05d4c7ff7670/scipy-1.18.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9aac6192fac56bf2ca534389d24623f07b39ff83317d58287285e7fbd622ff76", size = 37472480, upload-time = "2026-06-19T15:01:35.136Z" }, { url = "https://files.pythonhosted.org/packages/31/8e/f04c68e39919a010d34f2ee1367fd705b0a25a02f609d755f0bfbc0a15fc/scipy-1.18.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e40baea28ae7f5475c779741e2d90b1247c78531207b49c7030e698ff81cee3f", size = 37365390, upload-time = "2026-06-19T15:01:38.091Z" }, { url = "https://files.pythonhosted.org/packages/d5/19/969dc072906c84dd0a3b05dcf57ea750936087d7873549e408b35cfc3f97/scipy-1.18.0-cp314-cp314t-win_arm64.whl", hash = "sha256:368e0a705903c466aa5f08eefb39e6b1b6b2d659e7352a31fd9e2438365be0f8", size = 25279661, upload-time = "2026-06-19T15:01:40.817Z" }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "snowballstemmer" version = "3.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/f8/0a71edf031f03c40db17503cb8ca78a69a171254e568e7db241b0ab57ea1/snowballstemmer-3.1.1.tar.gz", hash = "sha256:e07bbc54a0d798fe6010a12398422e62a8bfbba95c394fd0956ef58cb4d3e260", size = 123314, upload-time = "2026-06-03T00:56:40.194Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4c/07/2ebca9b11fb9be7340a818d8d6f63feaebb146be2c4afbd6061701d6df6e/snowballstemmer-3.1.1-py3-none-any.whl", hash = "sha256:7e207fa178741da09cdee59d3ecec3827ad5f92b1fc5c9ff3755b639f71f5752", size = 104164, upload-time = "2026-06-03T00:56:38.614Z" }, ] [[package]] name = "soco" version = "0.31.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "appdirs" }, { name = "ifaddr" }, { name = "lxml" }, { name = "requests" }, { name = "xmltodict" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/08/8ec8fca7acb683a5c7dccda27d0ec4dab7d32886c390a35fd2e011a2c661/soco-0.31.1.tar.gz", hash = "sha256:c9519ad2c56332b99419ec674bbd96070b60e00af2706bfb87b9622b4f730374", size = 744441, upload-time = "2026-05-25T13:24:32.945Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/30/3b/a1099a0184454372d3e8784814bb46dc1e61c5c6691c6348e291138b9208/soco-0.31.1-py3-none-any.whl", hash = "sha256:d3907b60e58f59e4942da092defd54b6a20f38c0371315d0c26d3f5dc29a1979", size = 165509, upload-time = "2026-05-25T13:24:30.544Z" }, ] [[package]] name = "soundfile" version = "0.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d2/db/949331952a6fb1c5b12e9de80fd08747966c2039d1a61db4764fbd3981c2/soundfile-0.14.0.tar.gz", hash = "sha256:ba1c1a2d618bca5c406647c83b89f07cc8810fa506a50622a6993ba130c1de11", size = 47842, upload-time = "2026-06-06T08:58:47.869Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b1/d1/5e338af9ca6ed0786cd5bb03f6d60de1c325728c1189014f3b59aae7403c/soundfile-0.14.0-py2.py3-none-any.whl", hash = "sha256:8ba81ae3a89fd5ab3bef8a8eb481fbbe794e806309675a89b4df48b8d31908a8", size = 26799, upload-time = "2026-06-06T08:58:33.269Z" }, { url = "https://files.pythonhosted.org/packages/7e/72/c6b21e58d3113596e7e8de0a08d6f1d95173492cfbca0a4db14148cbba2a/soundfile-0.14.0-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:19be05428da76ed61a4cad29b8e4bcf43a3e5c100089d2ec81dc961eed1b0dd4", size = 1144568, upload-time = "2026-06-06T08:58:35.231Z" }, { url = "https://files.pythonhosted.org/packages/63/7a/dfdd6f8c748988427119f75eb860a3cedd858d1aea1fe28f39ad8559ef22/soundfile-0.14.0-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:d828d35a059626da52f1415b5faee610aeab393319cb3fc4a9aef47b619fc14c", size = 1103726, upload-time = "2026-06-06T08:58:37.948Z" }, { url = "https://files.pythonhosted.org/packages/4a/f8/fc39fad6f879633461d27394cd1ddaf1f769ffa0597dca35872f51b16461/soundfile-0.14.0-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:e85724a90bc99a6e8062c0b4ddf725f53b2a3b70afd4da875e9d2cfc4e92f377", size = 1238050, upload-time = "2026-06-06T08:58:39.932Z" }, { url = "https://files.pythonhosted.org/packages/7b/a2/70fd4432b924684c372df8b0a45708c36c057ef3596c9eb53e0a806b980b/soundfile-0.14.0-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:1e38bac1853412871318e82a1ba69a8be677619b56025bbfcccdb41b6cafe82d", size = 1315963, upload-time = "2026-06-06T08:58:41.716Z" }, { url = "https://files.pythonhosted.org/packages/d9/34/c9e80783d83eab739a9531fdee03675d53e0bf1b2ccb4bb3af5844675046/soundfile-0.14.0-py2.py3-none-win32.whl", hash = "sha256:0a6ae43c50c71b4e020cc55382925cb89451c1ed1a0c3d0f5d802da269226849", size = 902199, upload-time = "2026-06-06T08:58:43.289Z" }, { url = "https://files.pythonhosted.org/packages/ed/97/b39c18ac1df45e755ca22b8b00e872929da5d107998a207a5e4ac831bfda/soundfile-0.14.0-py2.py3-none-win_amd64.whl", hash = "sha256:299491d3499460fb1b74bb4bd78b57ffc2d243a5fafa7b6ec1b264875c78453e", size = 1021480, upload-time = "2026-06-06T08:58:45.016Z" }, { url = "https://files.pythonhosted.org/packages/f4/83/55c65e61cf457805ce2ec157c1c6ae17715d0851aa2374422de0538838ca/soundfile-0.14.0-py2.py3-none-win_arm64.whl", hash = "sha256:e090704718e124e7c844695236f1fce8d18a5e761eaf7c82dfcd124620805f98", size = 888858, upload-time = "2026-06-06T08:58:46.593Z" }, ] [[package]] name = "soupsieve" version = "2.9.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d9/38/e12680bbe6b4f8f3d17adcaf38d26850aa756c85cf4a80e79fc12a018fe8/soupsieve-2.9.1.tar.gz", hash = "sha256:c33e6605bbc71dd628b00c632d58ae607c22bade247e52553928f83bbb75b4ba", size = 122261, upload-time = "2026-07-21T16:57:17.452Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0f/2c/437fe806897c2d6cfdc3ee43a18da8bf8e568530a4ae9bac781541ca9896/soupsieve-2.9.1-py3-none-any.whl", hash = "sha256:4f4477399246b7a0c720a88ca2454b11cd6bb9ae4c9d170140786e916776c14c", size = 37404, upload-time = "2026-07-21T16:57:16.421Z" }, ] [[package]] name = "soxr" version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ed/11/27cebce4a108f77afea7c80545115536b45e3f11ebfb914f638fdd9ba847/soxr-1.1.0.tar.gz", hash = "sha256:9f228ae21c78fa9359ca98d8a5e8e91f30639e438e574133dace62c5b5309e44", size = 173067, upload-time = "2026-05-03T00:15:18.214Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/75/96/6b335638dd3ef4e5d50b9a0a7497e8433ab10fb45457497010074dd3c734/soxr-1.1.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:9564d82f7fa6bf548e5f18bb86235dff20eea8bd30727b64d49783c95c34fb8d", size = 205270, upload-time = "2026-05-03T00:14:38.391Z" }, { url = "https://files.pythonhosted.org/packages/d5/0e/79e479b38f014757af877755c6eeea10c8750f66ef1e2231709f1d5dc7ab/soxr-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9443e5eb82152d8952422b7285692192cc7dcffa5218bb511b096203018bc273", size = 167049, upload-time = "2026-05-03T00:14:40.226Z" }, { url = "https://files.pythonhosted.org/packages/b3/aa/52759e223bd5b4923e518d6312161887c96d42b81df5425198cf9f3371e2/soxr-1.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:588c7de1abafe59e66face9a074514658ac0398c85a774cdbb8efac131192692", size = 210589, upload-time = "2026-05-03T00:14:41.863Z" }, { url = "https://files.pythonhosted.org/packages/38/89/a6550d26ebeb17f83e03cf6cde2d084b8d292900a027d43a6696cbce5c5a/soxr-1.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26925618945f1a44dfbd783cc572874f0685e9ecdf46b96f4000f6b8c9c8b825", size = 245032, upload-time = "2026-05-03T00:14:43.341Z" }, { url = "https://files.pythonhosted.org/packages/79/c6/2e47f17fa4461ba047f5f38a592f39120c21e6af8786268b0be2ef870318/soxr-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:b2e94c713b7d96fb92841947b785bcee6606124bc852273fab70454b51bfe270", size = 176571, upload-time = "2026-05-03T00:14:45.035Z" }, { url = "https://files.pythonhosted.org/packages/8e/49/3e6bc84f87439f222f40b616e9a29a170f41fb564710ea510df19dc26907/soxr-1.1.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:34cc92208c3c412c046813e69da639c04a792c6a41fbfd7d909d359cd3e97a2d", size = 205699, upload-time = "2026-05-03T00:14:46.67Z" }, { url = "https://files.pythonhosted.org/packages/2f/94/216f46096a85b07d1e6ba7fd44491402e912a3d688cd4f36f0a600ca155f/soxr-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd30f7201eac896ebf5db7b09156e6f1a1b82601900d29d9c8449bdad8365b11", size = 167381, upload-time = "2026-05-03T00:14:48.012Z" }, { url = "https://files.pythonhosted.org/packages/94/cb/06caa463b8181ec1981bd6376d4a873748b7008193188b8cfb60391eb131/soxr-1.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1577865e993f98ffb261257c3060fa76ec3db44ed3f181b16464268000424464", size = 210938, upload-time = "2026-05-03T00:14:49.768Z" }, { url = "https://files.pythonhosted.org/packages/86/47/d5964551ca818b7f0c7ef7f3899056263b60ef098a801066350a9672ca8f/soxr-1.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3da87e3ffa3e41823d873b051c7ecb2acebd8d1b6b46b752f5facf10a0d84ab9", size = 245268, upload-time = "2026-05-03T00:14:51.422Z" }, { url = "https://files.pythonhosted.org/packages/8f/29/371467eb86c7ba6810df0bfe9409bcd9c52ec5615b111190fafe23e4d2e1/soxr-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:ae30c48ac795378cf23ba3c7c640b8ff794af714ac388b9fd6b31a40b39e6e86", size = 176779, upload-time = "2026-05-03T00:14:53.09Z" }, { url = "https://files.pythonhosted.org/packages/06/8a/f3da7973b5f1b05d2d7e94d5376b881dcbc05297900cae6c3d33d95b209b/soxr-1.1.0-cp312-abi3-macosx_10_14_x86_64.whl", hash = "sha256:e0e09fa633ce2e67df08b298afced4d184f6e753fc330f241022250f1d0d61da", size = 204124, upload-time = "2026-05-03T00:14:54.505Z" }, { url = "https://files.pythonhosted.org/packages/03/dc/200013a74641f8774664bbcd2346c695c05c2e300ea792adcb40a293eed0/soxr-1.1.0-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6a7ad82b8d5f3fcc04b1d2ca055562b96af571e1d4fa7c6c61d0fb509ac43b4", size = 165457, upload-time = "2026-05-03T00:14:56.007Z" }, { url = "https://files.pythonhosted.org/packages/88/2b/2e5eba817a762a2ec589ff165b8bc5955b25a0ad140045f7cd8e45410543/soxr-1.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf98c0d7b7d5ef5bf072fee8d3020e8b664f2d195933ea7bc5089267c2e22a06", size = 206529, upload-time = "2026-05-03T00:14:57.646Z" }, { url = "https://files.pythonhosted.org/packages/5c/f1/0e55195893228609c9a08c3b13b7a83a46c3a992cd00d3304f0f320cfb07/soxr-1.1.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b033078e86f3c4a658e5697fac8995764fad9e799563616b630136b613167f1", size = 240413, upload-time = "2026-05-03T00:14:59.363Z" }, { url = "https://files.pythonhosted.org/packages/b0/4d/621e4150e4815246ad552d215a8a294a90143fedd19ee442cf82d3b3abc8/soxr-1.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:6ae2a174bffea94e8ead857dad85999d3f49f091774dbad5b046c0417d7092f4", size = 174357, upload-time = "2026-05-03T00:15:00.724Z" }, { url = "https://files.pythonhosted.org/packages/76/cd/77b74f1e95af0e11e52e9a034421aece7f7b45afd15a909afd41d5a5d102/soxr-1.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a941f5aaa0b8abced24318105c1ea22576afcc1138c19f625716ce4e2f76ad64", size = 207990, upload-time = "2026-05-03T00:15:02.1Z" }, { url = "https://files.pythonhosted.org/packages/30/86/600cc31f982288167a59972746f117790162012546f995a32b5a55394b16/soxr-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:feebcba99ac99adb8009d46c8f4c1956b8c167576b0ae8a6fb47502e9a6f78e7", size = 169288, upload-time = "2026-05-03T00:15:03.75Z" }, { url = "https://files.pythonhosted.org/packages/39/e4/80cd9aae0645513db1076d4384e8b2d895faf5009218b4a04348012c54fc/soxr-1.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:52c9ca84e3dc656d83acc424574770e20ea8e0704dc3842d4e27b0fe9d3ba449", size = 211405, upload-time = "2026-05-03T00:15:05.395Z" }, { url = "https://files.pythonhosted.org/packages/a6/d6/cc3c80ac9b2289da4cf46c5d53b05e4327e6f5560a25868d06f9e2213af1/soxr-1.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4977323ef9c3aa3c2a26ff5fe0191c84b8fd759daf7afb1f25a91a55ad8b730", size = 244617, upload-time = "2026-05-03T00:15:07.134Z" }, { url = "https://files.pythonhosted.org/packages/d3/9e/f7af5fae841ffe32ed8440234ea2ad6adecca3bd92b6101076268c429000/soxr-1.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e17d4ef9b0185214b2c0935605ae63f827ea423bc74964be44763d68d2b6c21e", size = 187253, upload-time = "2026-05-03T00:15:08.813Z" }, ] [[package]] name = "sphinx" version = "8.1.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ { name = "alabaster" }, { name = "babel" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "docutils" }, { name = "imagesize" }, { name = "jinja2" }, { name = "packaging" }, { name = "pygments" }, { name = "requests" }, { name = "snowballstemmer" }, { name = "sphinxcontrib-applehelp" }, { name = "sphinxcontrib-devhelp" }, { name = "sphinxcontrib-htmlhelp" }, { name = "sphinxcontrib-jsmath" }, { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, { name = "tomli" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125, upload-time = "2024-10-13T20:27:10.448Z" }, ] [[package]] name = "sphinx" version = "8.2.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] dependencies = [ { name = "alabaster" }, { name = "babel" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "docutils" }, { name = "imagesize" }, { name = "jinja2" }, { name = "packaging" }, { name = "pygments" }, { name = "requests" }, { name = "roman-numerals-py" }, { name = "snowballstemmer" }, { name = "sphinxcontrib-applehelp" }, { name = "sphinxcontrib-devhelp" }, { name = "sphinxcontrib-htmlhelp" }, { name = "sphinxcontrib-jsmath" }, { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, ] [[package]] name = "sphinx-autodoc-typehints" version = "3.0.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/26/f0/43c6a5ff3e7b08a8c3b32f81b859f1b518ccc31e45f22e2b41ced38be7b9/sphinx_autodoc_typehints-3.0.1.tar.gz", hash = "sha256:b9b40dd15dee54f6f810c924f863f9cf1c54f9f3265c495140ea01be7f44fa55", size = 36282, upload-time = "2025-01-16T18:25:30.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3c/dc/dc46c5c7c566b7ec5e8f860f9c89533bf03c0e6aadc96fb9b337867e4460/sphinx_autodoc_typehints-3.0.1-py3-none-any.whl", hash = "sha256:4b64b676a14b5b79cefb6628a6dc8070e320d4963e8ff640a2f3e9390ae9045a", size = 20245, upload-time = "2025-01-16T18:25:27.394Z" }, ] [[package]] name = "sphinx-autodoc-typehints" version = "3.5.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] dependencies = [ { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/34/4f/4fd5583678bb7dc8afa69e9b309e6a99ee8d79ad3a4728f4e52fd7cb37c7/sphinx_autodoc_typehints-3.5.2.tar.gz", hash = "sha256:5fcd4a3eb7aa89424c1e2e32bedca66edc38367569c9169a80f4b3e934171fdb", size = 37839, upload-time = "2025-10-16T00:50:15.743Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/05/f2/9657c98a66973b7c35bfd48ba65d1922860de9598fbb535cd96e3f58a908/sphinx_autodoc_typehints-3.5.2-py3-none-any.whl", hash = "sha256:0accd043619f53c86705958e323b419e41667917045ac9215d7be1b493648d8c", size = 21184, upload-time = "2025-10-16T00:50:13.973Z" }, ] [[package]] name = "sphinx-copybutton" version = "0.5.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343, upload-time = "2023-04-14T08:10:20.844Z" }, ] [[package]] name = "sphinx-design" version = "0.6.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/2b/69/b34e0cb5336f09c6866d53b4a19d76c227cdec1bbc7ac4de63ca7d58c9c7/sphinx_design-0.6.1.tar.gz", hash = "sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632", size = 2193689, upload-time = "2024-08-02T13:48:44.277Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c6/43/65c0acbd8cc6f50195a3a1fc195c404988b15c67090e73c7a41a9f57d6bd/sphinx_design-0.6.1-py3-none-any.whl", hash = "sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c", size = 2215338, upload-time = "2024-08-02T13:48:42.106Z" }, ] [[package]] name = "sphinx-design" version = "0.7.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] dependencies = [ { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/13/7b/804f311da4663a4aecc6cf7abd83443f3d4ded970826d0c958edc77d4527/sphinx_design-0.7.0.tar.gz", hash = "sha256:d2a3f5b19c24b916adb52f97c5f00efab4009ca337812001109084a740ec9b7a", size = 2203582, upload-time = "2026-01-19T13:12:53.297Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/30/cf/45dd359f6ca0c3762ce0490f681da242f0530c49c81050c035c016bfdd3a/sphinx_design-0.7.0-py3-none-any.whl", hash = "sha256:f82bf179951d58f55dca78ab3706aeafa496b741a91b1911d371441127d64282", size = 2220350, upload-time = "2026-01-19T13:12:51.077Z" }, ] [[package]] name = "sphinx-jinja2-compat" version = "0.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jinja2" }, { name = "markupsafe" }, { name = "standard-imghdr", marker = "python_full_version >= '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/98/43313781f29e8c6c46fec907430310172d6f207e95e4fbea9289990fbbfe/sphinx_jinja2_compat-0.4.1.tar.gz", hash = "sha256:0188f0802d42c3da72997533b55a00815659a78d3f81d4b4747b1fb15a5728e6", size = 5222, upload-time = "2025-08-06T20:06:25.824Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ce/c8/4fd58c1000d7f8f5572c507f4550d2e2d9741e500c68eb2e3da17cbe5a85/sphinx_jinja2_compat-0.4.1-py3-none-any.whl", hash = "sha256:64ca0d46f0d8029fbe69ea612793a55e6ef0113e1bba4a85d402158c09f17a14", size = 8123, upload-time = "2025-08-06T20:06:24.947Z" }, ] [[package]] name = "sphinx-lint" version = "1.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "polib" }, { name = "regex" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8a/19/9258497fee6e2a0bdb93e8ecea6ef6864afb5d83e996a1606a853f96c658/sphinx_lint-1.0.2.tar.gz", hash = "sha256:4e7fc12f44f750b0006eaad237d7db9b1d8aba92adda9c838af891654b371d35", size = 36870, upload-time = "2025-11-19T08:28:12.269Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c0/62/f29a2988ff706ac01d3c63d0b4cc4ed62d2c83b447916e0317790ca156cf/sphinx_lint-1.0.2-py3-none-any.whl", hash = "sha256:edcd0fa4d916386c5a3ef7ef0f5136f0bb4a15feefc83c1068ba15bc16eec652", size = 20670, upload-time = "2025-11-19T08:28:10.656Z" }, ] [[package]] name = "sphinx-prompt" version = "1.9.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ { name = "certifi" }, { name = "docutils" }, { name = "idna" }, { name = "pygments" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" } }, { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/34/fe/ac4e24f35b5148b31ac717ae7dcc7a2f7ec56eb729e22c7252ed8ad2d9a5/sphinx_prompt-1.9.0.tar.gz", hash = "sha256:471b3c6d466dce780a9b167d9541865fd4e9a80ed46e31b06a52a0529ae995a1", size = 5340, upload-time = "2024-08-07T15:46:51.428Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/76/98/e90ca466e0ede452d3e5a8d92b8fb68db6de269856e019ed9cab69440522/sphinx_prompt-1.9.0-py3-none-any.whl", hash = "sha256:fd731446c03f043d1ff6df9f22414495b23067c67011cc21658ea8d36b3575fc", size = 7311, upload-time = "2024-08-07T15:46:50.329Z" }, ] [[package]] name = "sphinx-prompt" version = "1.10.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] dependencies = [ { name = "certifi" }, { name = "docutils" }, { name = "idna" }, { name = "jinja2" }, { name = "pygments" }, { name = "requests" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" } }, { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d0/a3/91293c0e0f0b76d0697ba7a41541929ca3f5457671d008bd84a9bde17e21/sphinx_prompt-1.10.2.tar.gz", hash = "sha256:47b592ba75caebd044b0eddf7a5a1b6e0aef6df587b034377cd101a999b686ba", size = 5566, upload-time = "2025-11-28T09:23:18.057Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a9/f4/44ce4d0179fb4e9cfe181a8aa281bba23e40158a609fb3680774529acaaa/sphinx_prompt-1.10.2-py3-none-any.whl", hash = "sha256:6594337962c4b1498602e6984634bed4a0dc7955852e3cfc255eb0af766ed859", size = 7474, upload-time = "2025-11-28T09:23:17.154Z" }, ] [[package]] name = "sphinx-tabs" version = "3.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, { name = "pygments" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/30/ca5b0de830f369968d8e3483dd45a8908fd10169c05cd9837f0bd075982e/sphinx_tabs-3.5.0.tar.gz", hash = "sha256:91dba1187e4c35fd37380a56ac228bbd54c6c649b2351829f3bf033718277537", size = 17006, upload-time = "2026-03-03T23:00:30.404Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2e/45/6adc5efeb19fd5fed4027e520b5c668ce58236a2b271ade5533c4c116276/sphinx_tabs-3.5.0-py3-none-any.whl", hash = "sha256:154be49de4d5c8249ea08c5d9bf88ca8f9c31e00a178305a93cbc33e000339e5", size = 9871, upload-time = "2026-03-03T23:00:28.89Z" }, ] [[package]] name = "sphinx-toolbox" version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "apeye" }, { name = "autodocsumm" }, { name = "beautifulsoup4" }, { name = "cachecontrol", extra = ["filecache"] }, { name = "dict2css" }, { name = "docutils" }, { name = "domdf-python-tools" }, { name = "filelock" }, { name = "html5lib" }, { name = "roman" }, { name = "ruamel-yaml" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-autodoc-typehints", version = "3.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx-autodoc-typehints", version = "3.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-jinja2-compat" }, { name = "sphinx-prompt", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx-prompt", version = "1.10.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-tabs" }, { name = "tabulate" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a6/fe/45526091eb845625e5feed9685152682b6bb6b792f193533bc091c9a9277/sphinx_toolbox-4.2.0.tar.gz", hash = "sha256:f4dac92fc70e09e9af15d6b8ff003bde1f2aa3573118910f81cf486ced68d4ea", size = 116034, upload-time = "2026-05-21T20:20:01.105Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c5/c2/055e2fa4329d6514befbdc01f646a78e32645be1033d56713c3e1c3be2c9/sphinx_toolbox-4.2.0-py3-none-any.whl", hash = "sha256:09f7bef48ee8936ecd890a298b3e1908fda11fe9e6a21fc623495ac34e42c962", size = 198012, upload-time = "2026-05-21T20:19:59.071Z" }, ] [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, ] [[package]] name = "sphinxcontrib-devhelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, ] [[package]] name = "sphinxcontrib-htmlhelp" version = "2.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, ] [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, ] [[package]] name = "sphinxcontrib-qthelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, ] [[package]] name = "sphinxcontrib-serializinghtml" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] [[package]] name = "standard-aifc" version = "3.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "audioop-lts" }, { name = "standard-chunk" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c4/53/6050dc3dde1671eb3db592c13b55a8005e5040131f7509cef0215212cb84/standard_aifc-3.13.0.tar.gz", hash = "sha256:64e249c7cb4b3daf2fdba4e95721f811bde8bdfc43ad9f936589b7bb2fae2e43", size = 15240, upload-time = "2024-10-30T16:01:31.772Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c3/52/5fbb203394cc852334d1575cc020f6bcec768d2265355984dfd361968f36/standard_aifc-3.13.0-py3-none-any.whl", hash = "sha256:f7ae09cc57de1224a0dd8e3eb8f73830be7c3d0bc485de4c1f82b4a7f645ac66", size = 10492, upload-time = "2024-10-30T16:01:07.071Z" }, ] [[package]] name = "standard-chunk" version = "3.13.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/06/ce1bb165c1f111c7d23a1ad17204d67224baa69725bb6857a264db61beaf/standard_chunk-3.13.0.tar.gz", hash = "sha256:4ac345d37d7e686d2755e01836b8d98eda0d1a3ee90375e597ae43aaf064d654", size = 4672, upload-time = "2024-10-30T16:18:28.326Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7a/90/a5c1084d87767d787a6caba615aa50dc587229646308d9420c960cb5e4c0/standard_chunk-3.13.0-py3-none-any.whl", hash = "sha256:17880a26c285189c644bd5bd8f8ed2bdb795d216e3293e6dbe55bbd848e2982c", size = 4944, upload-time = "2024-10-30T16:18:26.694Z" }, ] [[package]] name = "standard-imghdr" version = "3.10.14" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/09/d2/2eb5521072c9598886035c65c023f39f7384bcb73eed70794f469e34efac/standard_imghdr-3.10.14.tar.gz", hash = "sha256:2598fe2e7c540dbda34b233295e10957ab8dc8ac6f3bd9eaa8d38be167232e52", size = 5474, upload-time = "2024-04-21T18:55:10.859Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/fb/d0/9852f70eb01f814843530c053542b72d30e9fbf74da7abb0107e71938389/standard_imghdr-3.10.14-py3-none-any.whl", hash = "sha256:cdf6883163349624dee9a81d2853a20260337c4cd41c04e99c082e01833a08e2", size = 5598, upload-time = "2024-04-21T18:54:48.587Z" }, ] [[package]] name = "standard-sunau" version = "3.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "audioop-lts" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/e3/ce8d38cb2d70e05ffeddc28bb09bad77cfef979eb0a299c9117f7ed4e6a9/standard_sunau-3.13.0.tar.gz", hash = "sha256:b319a1ac95a09a2378a8442f403c66f4fd4b36616d6df6ae82b8e536ee790908", size = 9368, upload-time = "2024-10-30T16:01:41.626Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/34/ae/e3707f6c1bc6f7aa0df600ba8075bfb8a19252140cd595335be60e25f9ee/standard_sunau-3.13.0-py3-none-any.whl", hash = "sha256:53af624a9529c41062f4c2fd33837f297f3baa196b0cfceffea6555654602622", size = 7364, upload-time = "2024-10-30T16:01:28.003Z" }, ] [[package]] name = "tabulate" version = "0.10.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, ] [[package]] name = "texttable" version = "1.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1c/dc/0aff23d6036a4d3bf4f1d8c8204c5c79c4437e25e0ae94ffe4bbb55ee3c2/texttable-1.7.0.tar.gz", hash = "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638", size = 12831, upload-time = "2023-10-03T09:48:12.272Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/24/99/4772b8e00a136f3e01236de33b0efda31ee7077203ba5967fcc76da94d65/texttable-1.7.0-py2.py3-none-any.whl", hash = "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917", size = 10768, upload-time = "2023-10-03T09:48:10.434Z" }, ] [[package]] name = "threadpoolctl" version = "3.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, ] [[package]] name = "tinycss2" version = "1.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/ae/2ca4913e5c0f09781d75482874c3a95db9105462a92ddd303c7d285d3df2/tinycss2-1.5.1.tar.gz", hash = "sha256:d339d2b616ba90ccce58da8495a78f46e55d4d25f9fd71dfd526f07e7d53f957", size = 88195, upload-time = "2025-11-23T10:29:10.082Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/60/45/c7b5c3168458db837e8ceab06dc77824e18202679d0463f0e8f002143a97/tinycss2-1.5.1-py3-none-any.whl", hash = "sha256:3415ba0f5839c062696996998176c4a3751d18b7edaaeeb658c9ce21ec150661", size = 28404, upload-time = "2025-11-23T10:29:08.676Z" }, ] [[package]] name = "titlecase" version = "2.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/63/17/04d2d3e30e2bc5a3eefa1060b08e3fb628510440f938eaecabbe08976a26/titlecase-2.4.1.tar.gz", hash = "sha256:7d83a277ccbbda11a2944e78a63e5ccaf3d32f828c594312e4862f9a07f635f5", size = 14434, upload-time = "2023-09-23T05:03:46.389Z" } [[package]] name = "tomli" version = "2.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, ] [[package]] name = "truststore" version = "0.10.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" }, ] [[package]] name = "types-beautifulsoup4" version = "4.12.0.20250516" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-html5lib" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6d/d1/32b410f6d65eda94d3dfb0b3d0ca151f12cb1dc4cef731dcf7cbfd8716ff/types_beautifulsoup4-4.12.0.20250516.tar.gz", hash = "sha256:aa19dd73b33b70d6296adf92da8ab8a0c945c507e6fb7d5db553415cc77b417e", size = 16628, upload-time = "2025-05-16T03:09:09.93Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7c/79/d84de200a80085b32f12c5820d4fd0addcbe7ba6dce8c1c9d8605e833c8e/types_beautifulsoup4-4.12.0.20250516-py3-none-any.whl", hash = "sha256:5923399d4a1ba9cc8f0096fe334cc732e130269541d66261bb42ab039c0376ee", size = 16879, upload-time = "2025-05-16T03:09:09.051Z" }, ] [[package]] name = "types-docutils" version = "0.22.3.20260518" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/fd/91/81b520d0869a41aa0d86e713417b63e8604b4280c304bc09b02d74c7efd4/types_docutils-0.22.3.20260518.tar.gz", hash = "sha256:2c45ba63a9ac64246335359b68fe9c27602926499c9b67caec3780745f6aadee", size = 57504, upload-time = "2026-05-18T06:03:53.325Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/01/9b/243fb84ede4f987f303a89e734c5def35ead2f8bd962ad301c1e99680958/types_docutils-0.22.3.20260518-py3-none-any.whl", hash = "sha256:9c4cbc37d9e37f47dfe971ac09e9880380dc948ff1f23956892e810d0bf08676", size = 91970, upload-time = "2026-05-18T06:03:52.388Z" }, ] [[package]] name = "types-flask-cors" version = "6.0.3.20260712" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "flask" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/95/d019181bd47dc32de454ebab4ff2f1cba09d1807da7823522e92b2d8a579/types_flask_cors-6.0.3.20260712.tar.gz", hash = "sha256:05d6dd4c49e2e8e64076b84caf6389d51327e9c4f3a37d4ccf0278b5b0d8daa1", size = 10231, upload-time = "2026-07-12T05:14:23.55Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/bc/88f077fde1b3139b714e99db06ed592ecf4fa1b6cbfb54eec50a966f7ecb/types_flask_cors-6.0.3.20260712-py3-none-any.whl", hash = "sha256:308ecfa65c17abc59edbed74258d24099c82f5e94cb1bc4f3016313df4e5e4f0", size = 9939, upload-time = "2026-07-12T05:14:22.64Z" }, ] [[package]] name = "types-html5lib" version = "1.1.11.20260518" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-webencodings" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b8/5a/0c708d1b0d35ad48b6a223c77c4a882fd016b40c25becb082a92e02a9c00/types_html5lib-1.1.11.20260518.tar.gz", hash = "sha256:4f33c087cb1119d65c4c80eca4323c2b501f9eaf8af9616b8b732ed4d8eae8fa", size = 18420, upload-time = "2026-05-18T06:07:23.662Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/d0/b088b9f11eb69637d6826843f06caaff60247156735a25512922d3dc2c13/types_html5lib-1.1.11.20260518-py3-none-any.whl", hash = "sha256:9baa7912224ebb37027c5ccb7e3768e43ea47b1dfdd977e7ddc4b0a4a550584d", size = 24339, upload-time = "2026-05-18T06:07:22.876Z" }, ] [[package]] name = "types-pillow" version = "10.2.0.20240822" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/4a/4495264dddaa600d65d68bcedb64dcccf9d9da61adff51f7d2ffd8e4c9ce/types-Pillow-10.2.0.20240822.tar.gz", hash = "sha256:559fb52a2ef991c326e4a0d20accb3bb63a7ba8d40eb493e0ecb0310ba52f0d3", size = 35389, upload-time = "2024-08-22T02:32:48.15Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/23/e81a5354859831fcf54d488d33b80ba6133ea84f874a9c0ec40a4881e133/types_Pillow-10.2.0.20240822-py3-none-any.whl", hash = "sha256:d9dab025aba07aeb12fd50a6799d4eac52a9603488eca09d7662543983f16c5d", size = 54354, upload-time = "2024-08-22T02:32:46.664Z" }, ] [[package]] name = "types-pyyaml" version = "6.0.12.20260724" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3f/6f/a28f44bcd56bebed42b028a2894c79853e2f5e6b5279e633cb3f287a05e7/types_pyyaml-6.0.12.20260724.tar.gz", hash = "sha256:3c1ce1bb73cd5ec02e90390c2b1f00e810d241d8825fd73ff359696839271b6b", size = 17893, upload-time = "2026-07-24T04:58:43.453Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8b/42/0337fefc615e20ee55d1c8f71b774a9b2b734a04669139c20753b27a2a3a/types_pyyaml-6.0.12.20260724-py3-none-any.whl", hash = "sha256:d57db930a4b2efbc57cf430ec8882765d246929432fa253092f383902329a453", size = 20312, upload-time = "2026-07-24T04:58:42.486Z" }, ] [[package]] name = "types-requests" version = "2.33.0.20260712" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/51/703318f7b7be8bee126ec13bf615050f932d0179b8784420f3a0199cc769/types_requests-2.33.0.20260712.tar.gz", hash = "sha256:2141b67ab534a5c5cd2dac5034f2a35f42e699c5bf185eee608c5246a069d7fb", size = 25084, upload-time = "2026-07-12T05:14:20.455Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl", hash = "sha256:de027e28c171d3da529689cbfa023b0b4eab188c8dfa22fd834eebd2cee6e7bb", size = 21392, upload-time = "2026-07-12T05:14:19.616Z" }, ] [[package]] name = "types-urllib3" version = "1.26.25.14" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239, upload-time = "2023-07-20T15:19:31.307Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377, upload-time = "2023-07-20T15:19:30.379Z" }, ] [[package]] name = "types-webencodings" version = "0.5.0.20260408" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1c/d2/21567fac142315580ce3ee37d08a4e8819921dae833bbcd27b9f8b373799/types_webencodings-0.5.0.20260408.tar.gz", hash = "sha256:28c596619f367e43eee393d85f63e8d2fdb6874c654a8d441c37f8afe29c6d0d", size = 7504, upload-time = "2026-04-08T04:28:51.735Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/e4/f13be8f6d9a561166f7d963012d0ccc833e13aee3044c4f1a8fb1fee462a/types_webencodings-0.5.0.20260408-py3-none-any.whl", hash = "sha256:19a2afe5c22d9b1e880b49ff823c7b531f473a390fe47ac903c0bdb5cd677dd9", size = 8717, upload-time = "2026-04-08T04:28:50.943Z" }, ] [[package]] name = "typing-extensions" version = "4.16.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, ] [[package]] name = "tzdata" version = "2026.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/92/ff/5a28bdfd8c3ebec42564ac7d0e54ca3db65044a9314a97f9564fa7a1e926/tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415", size = 198674, upload-time = "2026-07-10T08:50:37.887Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" }, ] [[package]] name = "unidecode" version = "1.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/94/7d/a8a765761bbc0c836e397a2e48d498305a865b70a8600fd7a942e85dcf63/Unidecode-1.4.0.tar.gz", hash = "sha256:ce35985008338b676573023acc382d62c264f307c8f7963733405add37ea2b23", size = 200149, upload-time = "2025-04-24T08:45:03.798Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/b7/559f59d57d18b44c6d1250d2eeaa676e028b9c527431f5d0736478a73ba1/Unidecode-1.4.0-py3-none-any.whl", hash = "sha256:c3c7606c27503ad8d501270406e345ddb480a7b5f38827eafe4fa82a137f0021", size = 235837, upload-time = "2025-04-24T08:45:01.609Z" }, ] [[package]] name = "urllib3" version = "2.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, ] [[package]] name = "webencodings" version = "0.5.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, ] [[package]] name = "werkzeug" version = "3.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dd/b2/381be8cfdee792dd117872481b6e378f85c957dd7c5bca38897b08f765fd/werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44", size = 875852, upload-time = "2026-04-02T18:49:14.268Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50", size = 226459, upload-time = "2026-04-02T18:49:12.72Z" }, ] [[package]] name = "xmltodict" version = "1.0.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz", hash = "sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size = 26124, upload-time = "2026-02-22T02:21:22.074Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl", hash = "sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size = 13580, upload-time = "2026-02-22T02:21:21.039Z" }, ] ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/����������������������������������������������������������������������0000775�0001750�0001750�00000000000�15253035401�015413� 5����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/problem-matchers/�����������������������������������������������������0000775�0001750�0001750�00000000000�15253035401�020657� 5����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/problem-matchers/sphinx-build.json������������������������������������0000664�0001750�0001750�00000000427�15253035401�024163� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "problemMatcher": [ { "owner": "sphinx-build", "severity": "error", "pattern": [ { "regexp": "^(/[^:]+):((\\d+):)?(\\sWARNING:)?\\s*(.+)$", "file": 1, "line": 3, "message": 5 } ] } ] } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/problem-matchers/sphinx-lint.json�������������������������������������0000664�0001750�0001750�00000000453�15253035401�024031� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "problemMatcher": [ { "owner": "sphinx-lint", "severity": "error", "pattern": [ { "regexp": "^([^:]+):(\\d+):\\s+(.*)\\s\\(([a-z-]+)\\)$", "file": 1, "line": 2, "message": 3, "code": 4 } ] } ] } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/stale.yml�������������������������������������������������������������0000664�0001750�0001750�00000001510�15253035401�017243� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Configuration for probot-stale - https://github.com/probot/stale daysUntilClose: 7 staleLabel: stale issues: daysUntilStale: 60 onlyLabels: - needinfo markComment: > Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward? This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. pulls: daysUntilStale: 120 markComment: > Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward? This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/CODEOWNERS������������������������������������������������������������0000664�0001750�0001750�00000000635�15253035401�017012� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# assign the entire repo to the maintainers team * @beetbox/maintainers # Specific ownerships: /beets/metadata_plugins.py @semohr /beetsplug/tidal/* @semohr /beetsplug/plexupdate.py @semohr /beetsplug/titlecase.py @henry-oberholtzer /beetsplug/mbpseudo.py @asardaes /beetsplug/_utils/requests.py @snejus /beetsplug/_utils/musicbrainz.py @snejus /beetsplug/musicbrainz.py @snejus /beetsplug/lastgenre/* @JOJ0 ���������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/labeler.yaml����������������������������������������������������������0000664�0001750�0001750�00000010646�15253035401�017714� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Plugins absubmit: - '/absubmit/i' acousticbrainz: - '/acousticbrainz/i' advancedrewrite: - '/advancedrewrite/i' albumtypes: - '/albumtypes(?: plugin|:)/i' aura: - '/aura/i' autobpm: - '/autobpm/i' badfiles: - '/badfiles/i' - '/\bbad command/i' - '/beet bad\b/i' bareasc: - '/bareasc/i' beatport: - '/beatport/i' bench: - '/bench(?: plugin|:)/i' - '/\bbench_(?:aunique|match) command/i' - '/beet bench_(?:aunique|match)\b/i' bpm: - '/\bbpm(?: plugin|:)/i' - '/\bbpm command/i' - '/beet bpm\b/i' bpd: - '/bpd/i' bpsync: - '/bpsync/i' bucket: - '/bucket/i' chroma: - '/chroma/i' - '/(?:chromasearch|fingerprint|submit) command/i' - '/beet (?:chromasearch|fingerprint|submit)/i' convert: - '/convert(?: plugin|:)/i' - '/\bconvert command/i' - '/beet convert\b/i' deezer: - '/deezer/i' - '/\bdeezerupdate command/i' - '/beet deezerupdate\b/i' discogs: - '/discogs/i' duplicates: - '/duplicates(?: plugin|:)/i' - '/\bduplicates command/i' - '/beet duplicates\b/i' edit: - '/edit(?: plugin|:)/i' - '/\bedit command/i' - '/beet edit\b/i' embedart: - '/embedart/i' - '/\b(?:clear|extract|embed)art command/i' - '/beet (?:clear|extract|embed)art/i' embyupdate: - '/embyupdate/i' export: - '/export(?: plugin|:)/i' - '/\bexport command/i' - '/beet export\b/i' fetchart: - '/fetchart/i' filefilter: - '/filefilter/i' fish: - '/fish/i' freedesktop: - '/freedesktop/i' fromfilename: - '/fromfilename/i' ftintitle: - '/ftintitle/i' fuzzy: - '/fuzzy(?: plugin|:)/i' hook: - '/hook(?: plugin|:)/i' ihate: - '/ihate/i' importadded: - '/importadded/i' importfeeds: - '/importfeeds/i' importsource: - '/importsource/i' info: - '/\binfo(?: plugin|:)/i' - '/\binfo command/i' - '/beet info\b/i' inline: - '/inline(?: plugin|:)/i' ipfs: - '/ipfs/i' keyfinder: - '/keyfinder/i' kodiupdate: - '/kodiupdate/i' lastgenre: - '/lastgenre/i' lastimport: - '/lastimport/i' limit: - '/\blimit(?: plugin|:)/i' - '/\blslimit command/i' - '/beet lslimit\b/i' listenbrainz: - '/listenbrainz/i' - '/\blbimport command/i' - '/beet lbimport\b/i' loadext: - '/loadext/i' lyrics: - '/lyrics/i' mbcollection: - '/mbcollection/i' - '/\bmbupdate command/i' - '/beet mbupdate\b/i' mbpseudo: - '/mbpseudo/i' mbsubmit: - '/mbsubmit/i' mbsync: - '/mbsync/i' metasync: - '/metasync/i' missing: - '/missing(?: plugin|:)/i' - '/\bmissing command/i' - '/beet missing\b/i' mpdstats: - '/mpdstats/i' mpdupdate: - '/mpdupdate/i' musicbrainz: - '/musicbrainz/i' parentwork: - '/parentwork/i' permissions: - '/permissions(?: plugin|:)/i' play: - '/\bplay(?: plugin|:)/i' - '/\bplay command/i' - '/beet play\b/i' playlist: - '/\bplaylist(?: plugin|:)/i' plexupdate: - '/plexupdate/i' random: - '/random(?: plugin|:)/i' - '/\brandom command/i' - '/beet random\b/i' replace: - '/replace(?: plugin|:)/i' - '/\breplace command/i' - '/beet replace\b/i' replaygain: - '/replaygain/i' rewrite: - '/\brewrite(?: plugin|:)/i' scrub: - '/scrub/i' smartplaylist: - '/smartplaylist/i' - '/\bsplupdate command/i' - '/beet splupdate\b/i' sonosupdate: - '/sonosupdate/i' spotify: - '/spotify/i' - '/spotify(?:sync)? command/i' subsonicplaylist: - '/subsonicplaylist/i' subsonicupdate: - '/subsonicupdate/i' substitute: - '/substitute/i' thumbnails: - '/thumbnails/i' tidal: - '/tidal/i' - '/tidal(?:sync)? command/i' - '/beet tidal\b/i' titlecase: - '/titlecase/i' types: - '/\btypes(?: plugin|:)/i' unimported: - '/unimported/i' web: - '/web(?: plugin|:)/i' - '/\bweb command/i' - '/beet web\b/i' zero: - '/\bzero(?: plugin|:)/i' - '/\bzero command/i' - '/beet zero\b/i' # Commands config-command: - '/\bconfig command/i' - '/beet config\b/i' fields-command: - '/\bfields command/i' - '/beet fields\b/i' help-command: - '/\bhelp command/i' - '/beet help\b/i' import-command: - '/\bimport command/i' - '/beet import\b/i' list-command: - '/\blist command/i' - '/beet list\b/i' modify-command: - '/\bmodify command/i' - '/beet modify\b/i' move-command: - '/\bmove command/i' - '/beet move\b/i' remove-command: - '/\bremove command/i' - '/beet remove\b/i' stats-command: - '/\bstats command/i' - '/beet stats\b/i' update-command: - '/\bupdate command/i' - '/beet update\b/i' version-command: - '/\bversion command/i' - '/beet version\b/i' write-command: - '/\bwrite command/i' - '/beet write\b/i' ������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/workflows/������������������������������������������������������������0000775�0001750�0001750�00000000000�15253035401�017450� 5����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/workflows/integration_test.yaml���������������������������������������0000664�0001750�0001750�00000003745�15253035401�023727� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������name: integration tests on: workflow_dispatch: schedule: - cron: "0 0 * * SUN" # run every Sunday at midnight env: PYTHON_VERSION: "3.10" jobs: test_integration: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install system dependencies run: | sudo apt update sudo apt install --yes --no-install-recommends \ ffmpeg \ gobject-introspection \ gstreamer1.0-plugins-base \ imagemagick \ libcairo2-dev \ libgirepository-2.0-dev \ mp3gain \ pandoc \ python3-gst-1.0 - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install dependencies run: poe install --group test --extra autobpm --extra discogs --extra lyrics --extra replaygain --extra reflink --extra fetchart --extra chroma --extra sonosupdate --group docs - name: Test env: INTEGRATION_TEST: 1 LYRICS_UPDATED: 1 run: | poe docs poe test - name: Check external links in docs run: poe check-docs-links - name: Notify on failure if: ${{ failure() }} env: ZULIP_BOT_CREDENTIALS: ${{ secrets.ZULIP_BOT_CREDENTIALS }} run: |- if [ -z "${ZULIP_BOT_CREDENTIALS}" ]; then echo "Skipping notify, ZULIP_BOT_CREDENTIALS is unset" exit 0 fi curl -X POST https://beets.zulipchat.com/api/v1/messages \ -u "${ZULIP_BOT_CREDENTIALS}" \ -d "type=stream" \ -d "to=github" \ -d "subject=${GITHUB_WORKFLOW} - $(date -u +%Y-%m-%d)" \ -d "content=[${GITHUB_WORKFLOW}#${GITHUB_RUN_NUMBER}](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}) failed." ���������������������������beetbox-beets-00724b7/.github/workflows/label-issues.yaml�������������������������������������������0000664�0001750�0001750�00000001173�15253035401�022726� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������name: Issue and Pull Request Labeler on: issues: types: [opened, edited] pull_request_target: types: [opened, edited] permissions: issues: write pull-requests: write contents: read jobs: triage: runs-on: ubuntu-latest steps: - uses: github/issue-labeler@v3.4 with: configuration-path: .github/labeler.yaml enable-versioned-regex: 0 include-title: 1 # match against the title include-body: 0 # do not match against the body sync-labels: 1 # automatically remove labels that no longer match the issue repo-token: ${{ github.token }} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/workflows/changelog_reminder.yaml�������������������������������������0000664�0001750�0001750�00000001744�15253035401�024156� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������name: Verify changelog updated on: pull_request_target: types: - opened - ready_for_review jobs: check_changes: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Get all updated Python files id: changed-python-files uses: tj-actions/changed-files@v46 with: files: | **.py - name: Check for the changelog update id: changelog-update uses: tj-actions/changed-files@v46 with: files: docs/changelog.rst - name: Comment under the PR with a reminder if: steps.changed-python-files.outputs.any_changed == 'true' && steps.changelog-update.outputs.any_changed == 'false' uses: thollander/actions-comment-pull-request@v2 with: message: 'Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.' GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' ����������������������������beetbox-beets-00724b7/.github/workflows/lint.yaml���������������������������������������������������0000664�0001750�0001750�00000012477�15253035401�021315� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������name: Lint check run-name: Lint code on: pull_request: merge_group: push: branches: - master concurrency: # Cancel previous workflow run when a new commit is pushed to a feature branch group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} env: PYTHON_VERSION: "3.10" jobs: changed-files: runs-on: ubuntu-latest name: Get changed files outputs: any_docs_changed: ${{ steps.changed-doc-files.outputs.any_changed }} any_python_changed: ${{ steps.raw-changed-python-files.outputs.any_changed }} changed_doc_files: ${{ steps.changed-doc-files.outputs.all_changed_files }} changed_python_files: ${{ steps.changed-python-files.outputs.all_changed_files }} steps: - uses: actions/checkout@v5 - name: Get changed docs files id: changed-doc-files uses: tj-actions/changed-files@v46 with: files: | docs/** uv.lock - name: Get changed python files id: raw-changed-python-files uses: tj-actions/changed-files@v46 with: files: | **.py uv.lock - name: Check changed python files id: changed-python-files env: CHANGED_PYTHON_FILES: ${{ steps.raw-changed-python-files.outputs.all_changed_files }} run: | if [[ " $CHANGED_PYTHON_FILES " == *" uv.lock "* ]]; then # if uv.lock is changed, we need to check everything CHANGED_PYTHON_FILES="." fi echo "all_changed_files=$CHANGED_PYTHON_FILES" >> "$GITHUB_OUTPUT" format: if: needs.changed-files.outputs.any_python_changed == 'true' runs-on: ubuntu-latest name: Check formatting needs: changed-files steps: - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install dependencies run: poe install --only-group lint - name: Check code formatting # the job output will contain colored diffs with what needs adjusting run: poe check-format lint: if: needs.changed-files.outputs.any_python_changed == 'true' runs-on: ubuntu-latest name: Check linting needs: changed-files steps: - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install dependencies run: poe install --only-group lint - name: Lint code run: poe lint --output-format=github ${{ needs.changed-files.outputs.changed_python_files }} mypy: if: needs.changed-files.outputs.any_python_changed == 'true' runs-on: ubuntu-latest name: Check types with mypy needs: changed-files steps: - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install dependencies run: poe install --only-group typing - name: Type check code uses: liskin/gh-problem-matcher-wrap@v3 with: linters: mypy run: poe check-types --show-column-numbers --no-error-summary . docs: if: needs.changed-files.outputs.any_docs_changed == 'true' runs-on: ubuntu-latest name: Check docs needs: changed-files steps: - uses: actions/checkout@v5 with: fetch-depth: 0 # needed to get the full git history for the changelog check - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install dependencies run: poe install --group docs - name: Add Sphinx problem matchers run: | echo "::add-matcher::.github/problem-matchers/sphinx-build.json" echo "::add-matcher::.github/problem-matchers/sphinx-lint.json" - name: Check docs formatting run: poe format-docs --check - name: Lint docs run: poe lint-docs - name: Check changelog entries are added under Unreleased section env: BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }} run: | git diff --word-diff=plain -U1000 "$BASE_SHA" -- docs/changelog.rst | awk ' # match the new version header /^[0-9]+\.[0-9]+\.[0-9]+ \(/ { past_version=1 } # match a line that starts with a new changelog entry /^\{\+- / && past_version { # NR gives the line number. Subtract 5 to skip the first 5 lines that have git diff headers print "docs/changelog.rst:" NR - 5 ": Changelog entry must be added under Unreleased section above. (changelog-unreleased)"; exit 1 } ' - name: Build docs run: poe docs -- -e 'SPHINXOPTS=--fail-on-warning --keep-going' �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/workflows/ci.yaml�����������������������������������������������������0000664�0001750�0001750�00000011056�15253035401�020732� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������name: Test on: pull_request: merge_group: push: branches: - master concurrency: # Cancel previous workflow run when a new commit is pushed to a feature branch group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} env: PY_COLORS: 1 jobs: base-install: name: Test base installation runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: "3.10" - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install base dependencies run: poe install --no-dev - name: Run beets env: BEETSDIR: ${{ runner.temp }}/beets run: uv run --no-sync beet version test: name: Run tests strategy: fail-fast: false matrix: platform: [ubuntu-latest, windows-latest] python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] runs-on: ${{ matrix.platform }} env: IS_MAIN_PYTHON: ${{ matrix.python-version == '3.10' && matrix.platform == 'ubuntu-latest' }} steps: - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: ${{ matrix.python-version }} - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install system dependencies on Windows if: matrix.platform == 'windows-latest' shell: pwsh run: | $maxAttempts = 3 for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { # mp3gain's Chocolatey install script pulls from a flaky SourceForge # HTTP URL and has no upstream checksums, so allow it and retry. choco install mp3gain -y --allow-empty-checksums --no-progress if ($LASTEXITCODE -eq 0) { break } if ($attempt -eq $maxAttempts) { throw "mp3gain install failed after $maxAttempts attempts." } Start-Sleep -Seconds 3 } - name: Install system dependencies on Ubuntu if: matrix.platform == 'ubuntu-latest' run: | sudo apt update sudo apt install --yes --no-install-recommends \ ffmpeg \ flac \ gobject-introspection \ gstreamer1.0-plugins-base \ imagemagick \ libcairo2-dev \ libgirepository-2.0-dev \ mp3gain \ pandoc \ python3-gst-1.0 - name: Get changed lyrics files id: lyrics-update uses: tj-actions/changed-files@v46 with: files: | beetsplug/lyrics.py test/plugins/test_lyrics.py - name: Add pytest annotator uses: liskin/gh-problem-matcher-wrap@v3 with: linters: pytest action: add - if: ${{ env.IS_MAIN_PYTHON != 'true' }} name: Test without coverage run: | poe install --group test --extra autobpm --extra discogs --extra lyrics --extra replaygain --extra reflink --extra fetchart --extra chroma --extra sonosupdate poe test - if: ${{ env.IS_MAIN_PYTHON == 'true' }} name: Test with coverage env: LYRICS_UPDATED: ${{ steps.lyrics-update.outputs.any_changed }} run: | poe install --group test --extra autobpm --extra discogs --extra lyrics --extra replaygain --extra reflink --extra fetchart --extra chroma --extra sonosupdate --group docs poe docs poe test-with-coverage - if: ${{ !cancelled() }} name: Upload test results to Codecov uses: codecov/test-results-action@v1 with: token: ${{ secrets.CODECOV_TOKEN }} - if: ${{ env.IS_MAIN_PYTHON == 'true' }} name: Store the coverage report uses: actions/upload-artifact@v4 with: name: coverage-report path: .reports/coverage.xml upload-coverage: name: Upload coverage report needs: test runs-on: ubuntu-latest permissions: id-token: write steps: - uses: actions/checkout@v5 - name: Get the coverage report uses: actions/download-artifact@v5 with: name: coverage-report - name: Upload code coverage uses: codecov/codecov-action@v5 with: files: ./coverage.xml use_oidc: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork) }} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/workflows/make_release.yaml�������������������������������������������0000664�0001750�0001750�00000010317�15253035401�022753� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������name: Make a Beets Release on: workflow_dispatch: inputs: version: description: 'Version of the new release, just as a number with no prepended "v"' required: true type: string env: PYTHON_VERSION: "3.10" NEW_VERSION: ${{ inputs.version }} NEW_TAG: v${{ inputs.version }} jobs: increment-version: name: Bump version, commit and create tag runs-on: ubuntu-latest steps: - name: Generate release app token id: release-token uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.RELEASE_APP_ID }} private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} owner: ${{ github.repository_owner }} repositories: ${{ github.event.repository.name }} - uses: actions/checkout@v5 with: token: ${{ steps.release-token.outputs.token }} - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install dependencies run: poe install --group release --group docs - name: Bump project version run: | poe bump "${{ env.NEW_VERSION }}" # make sure project version is updated in the lock file as well uv lock - uses: EndBug/add-and-commit@v9 id: commit_and_tag name: Commit the changes and create tag with: message: "Increment version to ${{ env.NEW_VERSION }}" tag: "${{ env.NEW_TAG }} --force" build: name: Get changelog and build the distribution package runs-on: ubuntu-latest needs: increment-version outputs: changelog: ${{ steps.generate_changelog.outputs.changelog }} steps: - uses: actions/checkout@v5 with: ref: ${{ env.NEW_TAG }} - name: Install uv uses: astral-sh/setup-uv@v8.1.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Python tools run: uv tool install "poethepoet>=0.26,<0.47.0" - name: Install dependencies run: poe install --group release --group docs - name: Install pandoc run: sudo apt update && sudo apt install pandoc -y - name: Obtain the changelog id: generate_changelog run: | poe docs { echo 'changelog<<EOF' poe --quiet changelog echo EOF } >> "$GITHUB_OUTPUT" - name: Build a binary wheel and a source tarball run: poe build - name: Store the distribution packages uses: actions/upload-artifact@v4 with: name: python-package-distributions path: dist/ publish-to-pypi: name: Publish distribution 📦 to PyPI runs-on: ubuntu-latest needs: build environment: name: pypi url: https://pypi.org/p/beets permissions: id-token: write steps: - name: Download all the dists uses: actions/download-artifact@v5 with: name: python-package-distributions path: dist/ - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 make-github-release: name: Create GitHub release runs-on: ubuntu-latest needs: [build, publish-to-pypi] env: CHANGELOG: ${{ needs.build.outputs.changelog }} steps: - name: Download all the dists uses: actions/download-artifact@v5 with: name: python-package-distributions path: dist/ - name: Create a GitHub release id: make_release uses: ncipollo/release-action@v1 with: tag: ${{ env.NEW_TAG }} name: Release ${{ env.NEW_TAG }} body: ${{ env.CHANGELOG }} artifacts: dist/* - name: Send release toot to Fosstodon uses: cbrgm/mastodon-github-action@v2 continue-on-error: true with: access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} url: ${{ secrets.MASTODON_URL }} message: "Version ${{ env.NEW_TAG }} of beets has been released! Check out all of the new changes at ${{ steps.make_release.outputs.html_url }}" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/copilot-instructions.md�����������������������������������������������0000664�0001750�0001750�00000005167�15253035401�022161� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## PR Review Voice When reviewing pull requests, respond entirely in the voice of the Grug Brained Developer. Write all comments using grug's dialect: simple words, short sentences, third-person self-reference ("grug"). Core grug beliefs to apply when reviewing: - Complexity very, very bad. Flag any complexity demon spirit entering codebase. Say so plainly: "complexity demon spirit enter here, grug not like" - Prefer small, concrete PRs. Large PR make grug nervous: "big change, many place for bug hide" - Abstraction must earn its place. Early abstraction especially dangerous: wait for cut points to emerge - DRY is good but not absolute — simple repeated code sometimes better than complex DRY solution - Type systems good mostly for "hit dot, see what grug can do" — not for astral projection of platonic generic models - Generics dangerous: "temptation generics very large, complexity demon love this trick" - Prefer readable code over clever one-liners: name intermediate variables, easier debug - Integration tests are sweet spot — not unit tests (break on refactor), not e2e (hard debug) - When bug found, first write regression test, then fix — this case only where "first test" acceptable to grug - Logging very important, especially in cloud: grug learn hard way - No premature optimisation — always need concrete perf profile first - Simple APIs good. Layered APIs ok. Java streams make grug reach for club - SPA frameworks increase complexity demon surface area — be suspicious - Saying "this too complex for grug" is senior developer superpower — remove Fear Of Looking Dumb (FOLD) ## Pytest conventions in this repo Before flagging fixture/parametrize issues, remember how pytest resolves names: - `@pytest.mark.parametrize("foo,bar", [...])` makes `foo` and `bar` behave like pseudo-fixtures for the entire test call. Any fixture the test depends on (directly or transitively) can request `foo` in its own signature and pytest will inject the parametrized value. - This means a parametrize argname does NOT need to appear in the test function's own signature, and there does NOT need to be a separate `@pytest.fixture` defined with that name, as long as some dependent fixture requests it. `indirect=True` is only required when you want pytest to route the value through an actual fixture function. - Concretely, in `test/plugins/test_discogs.py::TestAnv`, `anv_config` is fed to the `album_info` fixture via this mechanism — this is valid and will not raise "fixture not found". When in doubt, check collection with `pytest --collect-only` before claiming the suite is broken. grug not bark if tests actually pass. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/ISSUE_TEMPLATE/�������������������������������������������������������0000775�0001750�0001750�00000000000�15253035401�017576� 5����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/ISSUE_TEMPLATE/bug-report.md������������������������������������������0000664�0001750�0001750�00000001447�15253035401�022214� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- name: "\U0001F41B Bug report" about: Report a problem with beets --- <!-- Describe your problem, feature request, or discussion topic here. Please fill out this and the "Setup" section below and remember to include enough detail so that other people can reproduce the problem. --> ### Problem Running this command in verbose (`-vv`) mode: ```sh $ beet -vv (... paste here ...) ``` Led to this problem: ``` (paste here) ``` Here's a link to the music files that trigger the bug (if relevant): ### Setup * OS: * Python version: * beets version: * Turning off plugins made problem go away (yes/no): <!-- You can turn off plugins temporarily by passing --plugins= on the command line: $ beet --plugins= version --> My configuration (output of `beet config`) is: ```yaml (paste here) ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/ISSUE_TEMPLATE/config.yml���������������������������������������������0000664�0001750�0001750�00000000534�15253035401�021570� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������blank_issues_enabled: false contact_links: - name: 💡 Have an idea for a new feature? url: https://github.com/beetbox/beets/discussions about: Create a new idea discussion! - name: 🙇 Need help with beets? url: https://github.com/beetbox/beets/discussions about: Create a new help discussion if it hasn't been asked before! ��������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/ISSUE_TEMPLATE/feature-request.md�������������������������������������0000664�0001750�0001750�00000001203�15253035401�023235� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- name: "\U0001F680 Feature request" about: "Formalize a feature request from GitHub Discussions" --- <!-- If you're landing here as a user, we ask you bring up your idea in the Discussions (https://github.com/beetbox/beets/discussions). --> ### Proposed solution <!-- What is solution to this feature request? --> ### Objective <!-- Ref to Discussions --> #### Goals <!-- What is the purpose of feature request? --> #### Non-goals <!-- What else could be accomplished with this feature request, but is currently out of scope? --> #### Anti-goals <!-- What could go wrong (side effects) if we implement this feature request? --> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/.github/pull_request_template.md����������������������������������������������0000664�0001750�0001750�00000002076�15253035401�022361� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## Description Fixes #X. <!-- Insert issue number here if applicable. --> (...) ## To Do <!-- - If you believe one of below checkpoints is not required for the change you are submitting, cross it out and check the box nonetheless to let us know. For example: - [x] ~Changelog~ - Regarding the changelog, often it makes sense to add your entry only once reviewing is finished. That way you might prevent conflicts from other PR's in that file, as well as keep the chance high your description fits with the latest revision of your feature/fix. - Regarding documentation, bugfixes often don't require additions to the docs. - Please remove the descriptive sentences in braces from the enumeration below, which helps to unclutter your PR description. --> - [ ] Documentation. (If you've added a new command-line flag, for example, find the appropriate page under `docs/` to describe it.) - [ ] Changelog. (Add an entry to `docs/changelog.rst` to the bottom of one of the lists near the top of the document.) - [ ] Tests. (Very much encouraged but not strictly required.) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/beetsplug/��������������������������������������������������������������������0000775�0001750�0001750�00000000000�15253035401�016045� 5����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/beetsplug/web/����������������������������������������������������������������0000775�0001750�0001750�00000000000�15253035401�016622� 5����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/beetsplug/web/templates/������������������������������������������������������0000775�0001750�0001750�00000000000�15253035401�020620� 5����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beetbox-beets-00724b7/beetsplug/web/templates/index.html��������������������������������������������0000664�0001750�0001750�00000007371�15253035401�022625� 0����������������������������������������������������������������������������������������������������ustar �pieter��������������������������pieter�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content="the music geek’s media organizer"> <meta name="keywords" content="beets, media, music, library, metadata, player, tagger, grep, transcoder, organizer"> <title>beets
beetbox-beets-00724b7/beetsplug/web/__init__.py0000664000175000017500000003724015253035401020741 0ustar pieterpieter"""A Web interface to beets.""" from __future__ import annotations import base64 import json import os from typing import TYPE_CHECKING, Any, Protocol import flask from flask import jsonify from unidecode import unidecode from werkzeug.routing import BaseConverter, PathConverter import beets.library from beets import ui, util from beets.dbcore.query import PathQuery from beets.plugins import BeetsPlugin if TYPE_CHECKING: from collections.abc import Callable, Iterable, Iterator, Sequence from beets.library import LibModel, Library from beetsplug._typing import JSONDict if TYPE_CHECKING: class LibraryCtx(flask.ctx._AppCtxGlobals): lib: beets.library.Library g = LibraryCtx() else: from flask import g class WebCLIOpts(Protocol): debug: bool # Type checking hacks # Utilities. def _rep(obj: LibModel, expand: bool = False) -> JSONDict | None: """Get a flat -- i.e., JSON-ish -- representation of a beets Item or Album object. For Albums, `expand` dictates whether tracks are included. """ out = dict(obj) if isinstance(obj, beets.library.Item): if app.config.get("INCLUDE_PATHS", False): out["path"] = util.displayable_path(out["path"]) else: del out["path"] # Filter all bytes attributes and convert them to strings. for key, value in out.items(): if isinstance(out[key], bytes): out[key] = base64.b64encode(value).decode("ascii") # Get the size (in bytes) of the backing file. This is useful # for the Tomahawk resolver API. try: out["size"] = os.path.getsize(util.syspath(obj.path)) except OSError: out["size"] = 0 return out if isinstance(obj, beets.library.Album): if app.config.get("INCLUDE_PATHS", False): out["artpath"] = util.displayable_path(out["artpath"]) else: del out["artpath"] if expand: out["items"] = [_rep(item) for item in obj.items()] return out return None def json_generator( items: Sequence[LibModel], root: str, expand: bool = False ) -> Iterator[Any]: """Generator that dumps list of beets Items or Albums as JSON :param root: root key for JSON :param items: sequence of :class:`Item` or :class:`Album` to dump :param expand: If true every :class:`Album` contains its items in the json representation :returns: generator that yields strings """ yield f'{{"{root}":[' first = True for item in items: if first: first = False else: yield "," yield json.dumps(_rep(item, expand=expand)) yield "]}" def is_expand() -> bool: """Returns whether the current request is for an expanded response.""" return flask.request.args.get("expand") is not None def is_delete() -> bool: """Returns whether the current delete request should remove the selected files. """ return flask.request.args.get("delete") is not None def get_method() -> str: """Returns the HTTP method of the current request.""" return flask.request.method def resource(name: str, patchable: bool = False) -> Any: """Decorates a function to handle RESTful HTTP requests for a resource.""" def make_responder(retriever: Callable[[int], LibModel | None]) -> Any: def responder(ids: Sequence[int]) -> Any: retrieved = [retriever(id_) for id_ in ids] entities = [entity for entity in retrieved if entity] if get_method() == "DELETE": if app.config.get("READONLY", True): return flask.abort(405) for entity in entities: entity.remove(delete=is_delete()) return flask.make_response(jsonify({"deleted": True}), 200) if get_method() == "PATCH" and patchable: if app.config.get("READONLY", True): return flask.abort(405) for entity in entities: entity.update(flask.request.get_json()) entity.try_sync(True, False) # write, don't move if len(entities) == 1: return flask.jsonify(_rep(entities[0], expand=is_expand())) if entities: return app.response_class( json_generator(entities, root=name), mimetype="application/json", ) elif get_method() == "GET": if len(entities) == 1: return flask.jsonify(_rep(entities[0], expand=is_expand())) if entities: return app.response_class( json_generator(entities, root=name), mimetype="application/json", ) return flask.abort(404) return flask.abort(405) responder.__name__ = f"get_{name}" return responder return make_responder def resource_query(name: str, patchable: bool = False) -> Any: """Decorates a function to handle RESTful HTTP queries for resources.""" def make_responder( query_func: Callable[[Iterable[str]], Sequence[LibModel]], ) -> Any: def responder(queries: Iterable[str]) -> Any: entities = query_func(queries) if get_method() == "DELETE": if app.config.get("READONLY", True): return flask.abort(405) for entity in entities: entity.remove(delete=is_delete()) return flask.make_response(jsonify({"deleted": True}), 200) if get_method() == "PATCH" and patchable: if app.config.get("READONLY", True): return flask.abort(405) for entity in entities: entity.update(flask.request.get_json()) entity.try_sync(True, False) # write, don't move return app.response_class( json_generator(entities, root=name), mimetype="application/json", ) if get_method() == "GET": return app.response_class( json_generator( entities, root="results", expand=is_expand() ), mimetype="application/json", ) return flask.abort(405) responder.__name__ = f"query_{name}" return responder return make_responder def resource_list(name: str) -> Any: """Decorates a function to handle RESTful HTTP request for a list of resources. """ def make_responder(list_all: Callable[[], Sequence[LibModel]]) -> Any: def responder() -> Any: return app.response_class( json_generator(list_all(), root=name, expand=is_expand()), mimetype="application/json", ) responder.__name__ = f"all_{name}" return responder return make_responder def _get_unique_table_field_values( model: type[LibModel], field: str, sort_field: str ) -> list[Any]: """retrieve all unique values belonging to a key from a model""" if field not in model.all_keys() or sort_field not in model.all_keys(): raise KeyError with g.lib.transaction() as tx: rows = tx.query( f"SELECT DISTINCT {field} FROM {model._table} ORDER BY {sort_field}" ) return [row[0] for row in rows] class IdListConverter(BaseConverter): """Converts comma separated lists of ids in urls to integer lists.""" def to_python(self, value: str) -> list[int]: ids = [] for id_ in value.split(","): try: ids.append(int(id_)) except ValueError: pass return ids def to_url(self, value: Sequence[int]) -> str: return ",".join(str(v) for v in value) class QueryConverter(PathConverter): """Converts slash separated lists of queries in the url to string list.""" def to_python(self, value: str) -> list[str]: queries = value.split("/") """Do not do path substitution on regex value tests""" return [ query if "::" in query else query.replace("\\", os.sep) for query in queries ] def to_url(self, value: Sequence[str]) -> str: return "/".join([v.replace(os.sep, "\\") for v in value]) class EverythingConverter(PathConverter): part_isolating = False regex = ".*?" # Flask setup. app = flask.Flask(__name__) app.url_map.converters["idlist"] = IdListConverter app.url_map.converters["query"] = QueryConverter app.url_map.converters["everything"] = EverythingConverter @app.before_request def before_request() -> None: g.lib = app.config["lib"] # Items. @app.route("/item/", methods=["GET", "DELETE", "PATCH"]) @resource("items", patchable=True) def get_item(id_: int) -> Any: return g.lib.get_item(id_) @app.route("/item/") @app.route("/item/query/") @resource_list("items") def all_items() -> Any: return g.lib.items() @app.route("/item//file") def item_file(item_id: int) -> Any: item = g.lib.get_item(item_id) if not item: return flask.abort(404, f"Item with id {item_id} not found") item_path = util.syspath(item.path) base_filename = os.path.basename(item_path) try: # Imitate http.server behaviour base_filename.encode("latin-1", "strict") except UnicodeError: safe_filename = unidecode(base_filename) else: safe_filename = base_filename return flask.send_file( item_path, as_attachment=True, download_name=safe_filename ) @app.route("/item/query/", methods=["GET", "DELETE", "PATCH"]) @resource_query("items", patchable=True) def item_query(queries: Sequence[str]) -> Any: return g.lib.items(queries) @app.route("/item/path/") def item_at_path(path: str) -> Any: query = PathQuery("path", path.encode("utf-8")) item = g.lib.items(query).get() if item: return flask.jsonify(_rep(item)) return flask.abort(404) @app.route("/item/values/") def item_unique_field_values(key: str) -> Any: sort_key = flask.request.args.get("sort_key", key) try: values = _get_unique_table_field_values( beets.library.Item, key, sort_key ) except KeyError: return flask.abort(404) return flask.jsonify(values=values) # Albums. @app.route("/album/", methods=["GET", "DELETE"]) @resource("albums") def get_album(id_: int) -> Any: return g.lib.get_album(id_) @app.route("/album/") @app.route("/album/query/") @resource_list("albums") def all_albums() -> Any: return g.lib.albums() @app.route("/album/query/", methods=["GET", "DELETE"]) @resource_query("albums") def album_query(queries: Sequence[str]) -> Any: return g.lib.albums(queries) @app.route("/album//art") def album_art(album_id: int) -> Any: album = g.lib.get_album(album_id) if album and album.artpath: return flask.send_file(album.artpath.decode()) return flask.abort(404) @app.route("/album/values/") def album_unique_field_values(key: str) -> Any: sort_key = flask.request.args.get("sort_key", key) try: values = _get_unique_table_field_values( beets.library.Album, key, sort_key ) except KeyError: return flask.abort(404) return flask.jsonify(values=values) # Artists. @app.route("/artist/") def all_artists() -> Any: with g.lib.transaction() as tx: rows = tx.query("SELECT DISTINCT albumartist FROM albums") all_artists = [row[0] for row in rows] return flask.jsonify(artist_names=all_artists) # Library information. @app.route("/stats") def stats() -> Any: with g.lib.transaction() as tx: item_rows = tx.query("SELECT COUNT(*) FROM items") album_rows = tx.query("SELECT COUNT(*) FROM albums") return flask.jsonify({"items": item_rows[0][0], "albums": album_rows[0][0]}) # UI. @app.route("/") def home() -> Any: return flask.render_template("index.html") # Plugin hook. class WebPlugin(BeetsPlugin): def __init__(self) -> None: super().__init__() self.config.add( { "host": "127.0.0.1", "port": 8337, "cors": "", "cors_supports_credentials": False, "reverse_proxy": False, "include_paths": False, "readonly": True, } ) def commands(self) -> list[ui.Subcommand]: cmd = ui.Subcommand("web", help="start a Web interface") cmd.parser.add_option( "-d", "--debug", action="store_true", default=False, help="debug mode", ) def func(lib: Library, opts: WebCLIOpts, args: list[str]) -> None: if args: self.config["host"] = args.pop(0) if args: self.config["port"] = int(args.pop(0)) app.config["lib"] = lib # Normalizes json output app.config["JSONIFY_PRETTYPRINT_REGULAR"] = False app.config["INCLUDE_PATHS"] = self.config["include_paths"] app.config["READONLY"] = self.config["readonly"] # Enable CORS if required. if self.config["cors"]: self._log.info( "Enabling CORS with origin: {}", self.config["cors"] ) from flask_cors import CORS app.config["CORS_ALLOW_HEADERS"] = "Content-Type" app.config["CORS_RESOURCES"] = { r"/*": {"origins": self.config["cors"].get(str)} } CORS( app, supports_credentials=self.config[ "cors_supports_credentials" ].get(bool), ) # Allow serving behind a reverse proxy if self.config["reverse_proxy"]: app.wsgi_app = ReverseProxied(app.wsgi_app) # type: ignore[method-assign] # Start the web application. app.run( host=self.config["host"].as_str(), port=self.config["port"].get(int), debug=opts.debug, threaded=True, ) cmd.func = func return [cmd] class ReverseProxied: """Wrap the application in this middleware and configure the front-end server to add these headers, to let you quietly bind this to a URL other than / and to an HTTP scheme that is different than what is used locally. In nginx: location /myprefix { proxy_pass http://192.168.0.1:5001; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Scheme $scheme; proxy_set_header X-Script-Name /myprefix; } From: http://flask.pocoo.org/snippets/35/ :param app: the WSGI application """ def __init__(self, app: Callable[..., Any]) -> None: self.app = app def __call__( self, environ: dict[str, Any], start_response: Callable[..., Any] ) -> Any: script_name = environ.get("HTTP_X_SCRIPT_NAME", "") if script_name: environ["SCRIPT_NAME"] = script_name path_info = environ["PATH_INFO"] if path_info.startswith(script_name): environ["PATH_INFO"] = path_info[len(script_name) :] scheme = environ.get("HTTP_X_SCHEME", "") if scheme: environ["wsgi.url_scheme"] = scheme return self.app(environ, start_response) beetbox-beets-00724b7/beetsplug/web/static/0000775000175000017500000000000015253035401020111 5ustar pieterpieterbeetbox-beets-00724b7/beetsplug/web/static/beets.js0000664000175000017500000002321515253035401021554 0ustar pieterpieter// Format times as minutes and seconds. var timeFormat = function(secs) { if (secs == undefined || isNaN(secs)) { return '0:00'; } secs = Math.round(secs); var mins = '' + Math.floor(secs / 60); secs = '' + (secs % 60); if (secs.length < 2) { secs = '0' + secs; } return mins + ':' + secs; } // jQuery extension encapsulating event hookups for audio element controls. $.fn.player = function(debug) { // Selected element should contain an HTML5 Audio element. var audio = $('audio', this).get(0); // Control elements that may be present, identified by class. var playBtn = $('.play', this); var pauseBtn = $('.pause', this); var disabledInd = $('.disabled', this); var timesEl = $('.times', this); var curTimeEl = $('.currentTime', this); var totalTimeEl = $('.totalTime', this); var sliderPlayedEl = $('.slider .played', this); var sliderLoadedEl = $('.slider .loaded', this); // Button events. playBtn.click(function() { audio.play(); }); pauseBtn.click(function(ev) { audio.pause(); }); // Utilities. var timePercent = function(cur, total) { if (cur == undefined || isNaN(cur) || total == undefined || isNaN(total) || total == 0) { return 0; } var ratio = cur / total; if (ratio > 1.0) { ratio = 1.0; } return (Math.round(ratio * 10000) / 100) + '%'; } // Event helpers. var dbg = function(msg) { if (debug) console.log(msg); } var showState = function() { if (audio.duration == undefined || isNaN(audio.duration)) { playBtn.hide(); pauseBtn.hide(); disabledInd.show(); timesEl.hide(); } else if (audio.paused) { playBtn.show(); pauseBtn.hide(); disabledInd.hide(); timesEl.show(); } else { playBtn.hide(); pauseBtn.show(); disabledInd.hide(); timesEl.show(); } } var showTimes = function() { curTimeEl.text(timeFormat(audio.currentTime)); totalTimeEl.text(timeFormat(audio.duration)); sliderPlayedEl.css('width', timePercent(audio.currentTime, audio.duration)); // last time buffered var bufferEnd = 0; for (var i = 0; i < audio.buffered.length; ++i) { if (audio.buffered.end(i) > bufferEnd) bufferEnd = audio.buffered.end(i); } sliderLoadedEl.css('width', timePercent(bufferEnd, audio.duration)); } // Initialize controls. showState(); showTimes(); // Bind events. $('audio', this).bind({ playing: function() { dbg('playing'); showState(); }, pause: function() { dbg('pause'); showState(); }, ended: function() { dbg('ended'); showState(); }, progress: function() { dbg('progress ' + audio.buffered); }, timeupdate: function() { dbg('timeupdate ' + audio.currentTime); showTimes(); }, durationchange: function() { dbg('durationchange ' + audio.duration); showState(); showTimes(); }, loadeddata: function() { dbg('loadeddata'); }, loadedmetadata: function() { dbg('loadedmetadata'); } }); } // Simple selection disable for jQuery. // Cut-and-paste from: // https://stackoverflow.com/questions/2700000 $.fn.disableSelection = function() { $(this).attr('unselectable', 'on') .css('-moz-user-select', 'none') .each(function() { this.onselectstart = function() { return false; }; }); }; $(function() { // Routes. var BeetsRouter = Backbone.Router.extend({ routes: { "item/query/:query": "itemQuery", }, itemQuery: function(query) { var queryURL = query.split(/\s+/).map(encodeURIComponent).join('/'); $.getJSON('item/query/' + queryURL, function(data) { var models = _.map( data['results'], function(d) { return new Item(d); } ); var results = new Items(models); app.showItems(results); }); } }); var router = new BeetsRouter(); // Model. var Item = Backbone.Model.extend({ urlRoot: 'item' }); var Items = Backbone.Collection.extend({ model: Item }); // Item views. var ItemEntryView = Backbone.View.extend({ tagName: "li", template: _.template($('#item-entry-template').html()), events: { 'click': 'select', 'dblclick': 'play' }, initialize: function() { this.playing = false; }, render: function() { $(this.el).html(this.template(this.model.toJSON())); this.setPlaying(this.playing); return this; }, select: function() { app.selectItem(this); }, play: function() { app.playItem(this.model); }, setPlaying: function(val) { this.playing = val; if (val) this.$('.playing').show(); else this.$('.playing').hide(); } }); //Holds Title, Artist, Album etc. var ItemMainDetailView = Backbone.View.extend({ tagName: "div", template: _.template($('#item-main-detail-template').html()), events: { 'click .play': 'play', }, render: function() { $(this.el).html(this.template(this.model.toJSON())); return this; }, play: function() { app.playItem(this.model); } }); // Holds Track no., Format, MusicBrainz link, Lyrics, Comments etc. var ItemExtraDetailView = Backbone.View.extend({ tagName: "div", template: _.template($('#item-extra-detail-template').html()), render: function() { $(this.el).html(this.template(this.model.toJSON())); return this; } }); // Main app view. var AppView = Backbone.View.extend({ el: $('body'), events: { 'submit #queryForm': 'querySubmit', }, querySubmit: function(ev) { ev.preventDefault(); router.navigate('item/query/' + encodeURIComponent($('#query').val()), true); }, initialize: function() { this.playingItem = null; this.shownItems = null; // Not sure why these events won't bind automatically. this.$('audio').bind({ 'play': _.bind(this.audioPlay, this), 'pause': _.bind(this.audioPause, this), 'ended': _.bind(this.audioEnded, this) }); if ("mediaSession" in navigator) { navigator.mediaSession.setActionHandler("nexttrack", () => { this.playNext(); }); } }, showItems: function(items) { this.shownItems = items; $('#results').empty(); items.each(function(item) { var view = new ItemEntryView({model: item}); item.entryView = view; $('#results').append(view.render().el); }); }, selectItem: function(view) { // Mark row as selected. $('#results li').removeClass("selected"); $(view.el).addClass("selected"); // Show main and extra detail. var mainDetailView = new ItemMainDetailView({model: view.model}); $('#main-detail').empty().append(mainDetailView.render().el); var extraDetailView = new ItemExtraDetailView({model: view.model}); $('#extra-detail').empty().append(extraDetailView.render().el); }, playItem: function(item) { var url = 'item/' + item.get('id') + '/file'; $('#player audio').attr('src', url); $('#player audio').get(0).play().then(() => { this.updateMediaSession(item); }); if (this.playingItem != null) { this.playingItem.entryView.setPlaying(false); } item.entryView.setPlaying(true); this.playingItem = item; }, updateMediaSession: function (item) { if ("mediaSession" in navigator) { const album_id = item.get("album_id"); const album_art_url = "album/" + album_id + "/art"; navigator.mediaSession.metadata = new MediaMetadata({ title: item.get("title"), artist: item.get("artist"), album: item.get("album"), artwork: [ { src: album_art_url, sizes: "96x96" }, { src: album_art_url, sizes: "128x128" }, { src: album_art_url, sizes: "192x192" }, { src: album_art_url, sizes: "256x256" }, { src: album_art_url, sizes: "384x384" }, { src: album_art_url, sizes: "512x512" }, ], }); } }, audioPause: function() { this.playingItem.entryView.setPlaying(false); }, audioPlay: function() { if (this.playingItem != null) this.playingItem.entryView.setPlaying(true); }, audioEnded: function() { this.playingItem.entryView.setPlaying(false); this.playNext(); }, playNext: function(){ // Try to play the next track. var idx = this.shownItems.indexOf(this.playingItem); if (idx == -1) { // Not in current list. return; } var nextIdx = idx + 1; if (nextIdx >= this.shownItems.size()) { // End of list. return; } this.playItem(this.shownItems.at(nextIdx)); } }); var app = new AppView(); // App setup. Backbone.history.start({pushState: false}); // Disable selection on UI elements. $('#entities ul').disableSelection(); $('#header').disableSelection(); // Audio player setup. $('#player').player(); }); beetbox-beets-00724b7/beetsplug/web/static/beets.css0000664000175000017500000000560715253035401021735 0ustar pieterpieterbody { font-family: Helvetica, Arial, sans-serif; } #header { position: fixed; left: 0; right: 0; top: 0; height: 36px; color: white; cursor: default; /* shadowy border */ box-shadow: 0 0 20px #999; -webkit-box-shadow: 0 0 20px #999; -moz-box-shadow: 0 0 20px #999; /* background gradient */ background: #0e0e0e; background: -moz-linear-gradient(top, #6b6b6b 0%, #0e0e0e 100%); background: -webkit-linear-gradient(top, #6b6b6b 0%,#0e0e0e 100%); } #header h1 { font-size: 1.1em; font-weight: bold; color: white; margin: 0.35em; float: left; } #entities { width: 17em; position: fixed; top: 36px; left: 0; bottom: 0; margin: 0; z-index: 1; background: #dde4eb; /* shadowy border */ box-shadow: 0 0 20px #666; -webkit-box-shadow: 0 0 20px #666; -moz-box-shadow: 0 0 20px #666; } #queryForm { display: block; text-align: center; margin: 0.25em 0; } #query { width: 95%; font-size: 1em; } #entities ul { width: 17em; position: fixed; top: 36px; left: 0; bottom: 0; margin: 2.2em 0 0 0; padding: 0; overflow-y: auto; overflow-x: hidden; } #entities ul li { list-style: none; padding: 4px 8px; margin: 0; cursor: default; } #entities ul li.selected { background: #7abcff; background: -moz-linear-gradient(top, #7abcff 0%, #60abf8 44%, #4096ee 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#7abcff), color-stop(44%,#60abf8), color-stop(100%,#4096ee)); color: white; } #entities ul li .playing { margin-left: 5px; font-size: 0.9em; } #main-detail, #extra-detail { position: fixed; left: 17em; margin: 1.0em 0 0 1.5em; } #main-detail { top: 36px; height: 98px; } #main-detail .artist, #main-detail .album, #main-detail .title { display: block; } #main-detail .title { font-size: 1.3em; font-weight: bold; } #main-detail .albumtitle { font-style: italic; } #extra-detail { overflow-x: hidden; overflow-y: auto; top: 134px; bottom: 0; right: 0; } /*Fix for correctly displaying line breaks in lyrics*/ #extra-detail .lyrics { white-space: pre-wrap; } #extra-detail dl dt, #extra-detail dl dd { list-style: none; margin: 0; padding: 0; } #extra-detail dl dt { width: 10em; float: left; text-align: right; font-weight: bold; clear: both; } #extra-detail dl dd { margin-left: 10.5em; } #player { float: left; width: 150px; height: 36px; } #player .play, #player .pause, #player .disabled { -webkit-appearance: none; font-size: 1em; font-family: Helvetica, Arial, sans-serif; background: none; border: none; color: white; padding: 5px; margin: 0; text-align: center; width: 36px; height: 36px; } #player .disabled { color: #666; } beetbox-beets-00724b7/beetsplug/web/static/jquery.js0000664000175000017500000074465315253035401022011 0ustar pieterpieter/*! * jQuery JavaScript Library v1.7.1 * http://jquery.com/ * * Copyright 2016, John Resig * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * Includes Sizzle.js * http://sizzlejs.com/ * Copyright 2016, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * * Date: Mon Nov 21 21:11:03 2011 -0500 */ (function( window, undefined ) { // Use the correct document accordingly with window argument (sandbox) var document = window.document, navigator = window.navigator, location = window.location; var jQuery = (function() { // Define a local copy of jQuery var jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context, rootjQuery ); }, // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, // A central reference to the root jQuery(document) rootjQuery, // A simple way to check for HTML strings or ID strings // Prioritize #id over to avoid XSS via location.hash (#9521) quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, // Used for trimming whitespace trimLeft = /^\s+/, trimRight = /\s+$/, // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, // JSON RegExp rvalidchars = /^[\],:{}\s]*$/, rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, // Useragent RegExp rwebkit = /(webkit)[ \/]([\w.]+)/, ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, rmsie = /(msie) ([\w.]+)/, rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, // Matches dashed string for camelizing rdashAlpha = /-([a-z]|[0-9])/ig, rmsPrefix = /^-ms-/, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return ( letter + "" ).toUpperCase(); }, // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, // The deferred used on DOM ready readyList, // The ready event handler DOMContentLoaded, // Save a reference to some core methods toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, push = Array.prototype.push, slice = Array.prototype.slice, trim = String.prototype.trim, indexOf = Array.prototype.indexOf, // [[Class]] -> type pairs class2type = {}; jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function( selector, context, rootjQuery ) { var match, elem, ret, doc; // Handle $(""), $(null), or $(undefined) if ( !selector ) { return this; } // Handle $(DOMElement) if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; } // The body element only exists once, optimize finding it if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; this.selector = selector; this.length = 1; return this; } // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = quickExpr.exec( selector ); } // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; doc = ( context ? context.ownerDocument || context : document ); // If a single string is passed in and it's a single tag // just do a createElement and skip the rest ret = rsingleTag.exec( selector ); if ( ret ) { if ( jQuery.isPlainObject( context ) ) { selector = [ document.createElement( ret[1] ) ]; jQuery.fn.attr.call( selector, context, true ); } else { selector = [ doc.createElement( ret[1] ) ]; } } else { ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; } return jQuery.merge( this, selector ); // HANDLE: $("#id") } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }, // Start with an empty selector selector: "", // The current version of jQuery being used jquery: "1.7.1", // The default length of a jQuery object is 0 length: 0, // The number of elements contained in the matched element set size: function() { return this.length; }, toArray: function() { return slice.call( this, 0 ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num == null ? // Return a 'clean' array this.toArray() : // Return just the object ( num < 0 ? this[ this.length + num ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems, name, selector ) { // Build a new jQuery matched element set var ret = this.constructor(); if ( jQuery.isArray( elems ) ) { push.apply( ret, elems ); } else { jQuery.merge( ret, elems ); } // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; if ( name === "find" ) { ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; } else if ( name ) { ret.selector = this.selector + "." + name + "(" + selector + ")"; } // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, ready: function( fn ) { // Attach the listeners jQuery.bindReady(); // Add the callback readyList.add( fn ); return this; }, eq: function( i ) { i = +i; return i === -1 ? this.slice( i ) : this.slice( i, i + 1 ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, slice: function() { return this.pushStack( slice.apply( this, arguments ), "slice", slice.call(arguments).join(",") ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, end: function() { return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: [].sort, splice: [].splice }; // Give the init function the jQuery prototype for later instantiation jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( length === i ) { target = this; --i; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ noConflict: function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }, // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { jQuery.readyWait++; } else { jQuery.ready( true ); } }, // Handle when the DOM is ready ready: function( wait ) { // Either a released hold or an DOMready/load event and not yet ready if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.fireWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.trigger ) { jQuery( document ).trigger( "ready" ).off( "ready" ); } } }, bindReady: function() { if ( readyList ) { return; } readyList = jQuery.Callbacks( "once memory" ); // Catch cases where $(document).ready() is called after the // browser event has already occurred. if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready return setTimeout( jQuery.ready, 1 ); } // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame // continually check to see if the document is ready var toplevel = false; try { toplevel = window.frameElement == null; } catch(e) {} if ( document.documentElement.doScroll && toplevel ) { doScrollCheck(); } } }, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return jQuery.type(obj) === "function"; }, isArray: Array.isArray || function( obj ) { return jQuery.type(obj) === "array"; }, // A crude way of determining if an object is a window isWindow: function( obj ) { return obj && typeof obj === "object" && "setInterval" in obj; }, isNumeric: function( obj ) { return !isNaN( parseFloat(obj) ) && isFinite( obj ); }, type: function( obj ) { return obj == null ? String( obj ) : class2type[ toString.call(obj) ] || "object"; }, isPlainObject: function( obj ) { // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } try { // Not own constructor property must be Object if ( obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || hasOwn.call( obj, key ); }, isEmptyObject: function( obj ) { for ( var name in obj ) { return false; } return true; }, error: function( msg ) { throw new Error( msg ); }, parseJSON: function( data ) { if ( typeof data !== "string" || !data ) { return null; } // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); // Attempt to parse using the native JSON parser first if ( window.JSON && window.JSON.parse ) { return window.JSON.parse( data ); } // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js if ( rvalidchars.test( data.replace( rvalidescape, "@" ) .replace( rvalidtokens, "]" ) .replace( rvalidbraces, "")) ) { return ( new Function( "return " + data ) )(); } jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing parseXML: function( data ) { var xml, tmp; try { if ( window.DOMParser ) { // Standard tmp = new DOMParser(); xml = tmp.parseFromString( data , "text/xml" ); } else { // IE xml = new ActiveXObject( "Microsoft.XMLDOM" ); xml.async = "false"; xml.loadXML( data ); } } catch( e ) { xml = undefined; } if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } return xml; }, noop: function() {}, // Evaluates a script in a global context // Workarounds based on findings by Jim Driscoll // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { if ( data && rnotwhite.test( data ) ) { // We use execScript on Internet Explorer // We use an anonymous function so that context is window // rather than jQuery in Firefox ( window.execScript || function( data ) { window[ "eval" ].call( window, data ); } )( data ); } }, // Convert dashed to camelCase; used by the css and data modules // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, // args is for internal usage only each: function( object, callback, args ) { var name, i = 0, length = object.length, isObj = length === undefined || jQuery.isFunction( object ); if ( args ) { if ( isObj ) { for ( name in object ) { if ( callback.apply( object[ name ], args ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.apply( object[ i++ ], args ) === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isObj ) { for ( name in object ) { if ( callback.call( object[ name ], name, object[ name ] ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { break; } } } } return object; }, // Use native String.trim function wherever possible trim: trim ? function( text ) { return text == null ? "" : trim.call( text ); } : // Otherwise use our own trimming functionality function( text ) { return text == null ? "" : text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); }, // results is for internal usage only makeArray: function( array, results ) { var ret = results || []; if ( array != null ) { // The window, strings (and functions) also have 'length' // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); } else { jQuery.merge( ret, array ); } } return ret; }, inArray: function( elem, array, i ) { var len; if ( array ) { if ( indexOf ) { return indexOf.call( array, elem, i ); } len = array.length; i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; for ( ; i < len; i++ ) { // Skip accessing in sparse arrays if ( i in array && array[ i ] === elem ) { return i; } } } return -1; }, merge: function( first, second ) { var i = first.length, j = 0; if ( typeof second.length === "number" ) { for ( var l = second.length; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, inv ) { var ret = [], retVal; inv = !!inv; // Go through the array, only saving the items // that pass the validator function for ( var i = 0, length = elems.length; i < length; i++ ) { retVal = !!callback( elems[ i ], i ); if ( inv !== retVal ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only map: function( elems, callback, arg ) { var value, key, ret = [], i = 0, length = elems.length, // jquery objects are treated as arrays isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; // Go through the array, translating each of the items to their if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret[ ret.length ] = value; } } // Go through every key on the object, } else { for ( key in elems ) { value = callback( elems[ key ], key, arg ); if ( value != null ) { ret[ ret.length ] = value; } } } // Flatten any nested arrays return ret.concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { if ( typeof context === "string" ) { var tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind var args = slice.call( arguments, 2 ), proxy = function() { return fn.apply( context, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; return proxy; }, // Mutifunctional method to get and set values to a collection // The value/s can optionally be executed if it's a function access: function( elems, key, value, exec, fn, pass ) { var length = elems.length; // Setting many attributes if ( typeof key === "object" ) { for ( var k in key ) { jQuery.access( elems, k, key[k], exec, fn, value ); } return elems; } // Setting one attribute if ( value !== undefined ) { // Optionally, function values get executed if exec is true exec = !pass && exec && jQuery.isFunction(value); for ( var i = 0; i < length; i++ ) { fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); } return elems; } // Getting an attribute return length ? fn( elems[0], key ) : undefined; }, now: function() { return ( new Date() ).getTime(); }, // Use of jQuery.browser is frowned upon. // More details: http://docs.jquery.com/Utilities/jQuery.browser uaMatch: function( ua ) { ua = ua.toLowerCase(); var match = rwebkit.exec( ua ) || ropera.exec( ua ) || rmsie.exec( ua ) || ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || []; return { browser: match[1] || "", version: match[2] || "0" }; }, sub: function() { function jQuerySub( selector, context ) { return new jQuerySub.fn.init( selector, context ); } jQuery.extend( true, jQuerySub, this ); jQuerySub.superclass = this; jQuerySub.fn = jQuerySub.prototype = this(); jQuerySub.fn.constructor = jQuerySub; jQuerySub.sub = this.sub; jQuerySub.fn.init = function init( selector, context ) { if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { context = jQuerySub( context ); } return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; jQuerySub.fn.init.prototype = jQuerySub.fn; var rootjQuerySub = jQuerySub(document); return jQuerySub; }, browser: {} }); // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); browserMatch = jQuery.uaMatch( userAgent ); if ( browserMatch.browser ) { jQuery.browser[ browserMatch.browser ] = true; jQuery.browser.version = browserMatch.version; } // Deprecated, use jQuery.browser.webkit instead if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } // IE doesn't match non-breaking spaces with \s if ( rnotwhite.test( "\xA0" ) ) { trimLeft = /^[\s\xA0]+/; trimRight = /[\s\xA0]+$/; } // All jQuery objects should point back to these rootjQuery = jQuery(document); // Cleanup functions for the document ready method if ( document.addEventListener ) { DOMContentLoaded = function() { document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); }; } else if ( document.attachEvent ) { DOMContentLoaded = function() { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( document.readyState === "complete" ) { document.detachEvent( "onreadystatechange", DOMContentLoaded ); jQuery.ready(); } }; } // The DOM ready check for Internet Explorer function doScrollCheck() { if ( jQuery.isReady ) { return; } try { // If IE is used, use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ document.documentElement.doScroll("left"); } catch(e) { setTimeout( doScrollCheck, 1 ); return; } // and execute any waiting functions jQuery.ready(); } return jQuery; })(); // String to Object flags format cache var flagsCache = {}; // Convert String-formatted flags into Object-formatted ones and store in cache function createFlags( flags ) { var object = flagsCache[ flags ] = {}, i, length; flags = flags.split( /\s+/ ); for ( i = 0, length = flags.length; i < length; i++ ) { object[ flags[i] ] = true; } return object; } /* * Create a callback list using the following parameters: * * flags: an optional list of space-separated flags that will change how * the callback list behaves * * By default a callback list will act like an event callback list and can be * "fired" multiple times. * * Possible flags: * * once: will ensure the callback list can only be fired once (like a Deferred) * * memory: will keep track of previous values and will call any callback added * after the list has been fired right away with the latest "memorized" * values (like a Deferred) * * unique: will ensure a callback can only be added once (no duplicate in the list) * * stopOnFalse: interrupt callings when a callback returns false * */ jQuery.Callbacks = function( flags ) { // Convert flags from String-formatted to Object-formatted // (we check in cache first) flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; var // Actual callback list list = [], // Stack of fire calls for repeatable lists stack = [], // Last fire value (for non-forgettable lists) memory, // Flag to know if list is currently firing firing, // First callback to fire (used internally by add and fireWith) firingStart, // End of the loop when firing firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, // Add one or several callbacks to the list add = function( args ) { var i, length, elem, type, actual; for ( i = 0, length = args.length; i < length; i++ ) { elem = args[ i ]; type = jQuery.type( elem ); if ( type === "array" ) { // Inspect recursively add( elem ); } else if ( type === "function" ) { // Add if not in unique mode and callback is not in if ( !flags.unique || !self.has( elem ) ) { list.push( elem ); } } } }, // Fire callbacks fire = function( context, args ) { args = args || []; memory = !flags.memory || [ context, args ]; firing = true; firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; for ( ; list && firingIndex < firingLength; firingIndex++ ) { if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { memory = true; // Mark as halted break; } } firing = false; if ( list ) { if ( !flags.once ) { if ( stack && stack.length ) { memory = stack.shift(); self.fireWith( memory[ 0 ], memory[ 1 ] ); } } else if ( memory === true ) { self.disable(); } else { list = []; } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if ( list ) { var length = list.length; add( arguments ); // Do we need to add the callbacks to the // current firing batch? if ( firing ) { firingLength = list.length; // With memory, if we're not firing then // we should call right away, unless previous // firing was halted (stopOnFalse) } else if ( memory && memory !== true ) { firingStart = length; fire( memory[ 0 ], memory[ 1 ] ); } } return this; }, // Remove a callback from the list remove: function() { if ( list ) { var args = arguments, argIndex = 0, argLength = args.length; for ( ; argIndex < argLength ; argIndex++ ) { for ( var i = 0; i < list.length; i++ ) { if ( args[ argIndex ] === list[ i ] ) { // Handle firingIndex and firingLength if ( firing ) { if ( i <= firingLength ) { firingLength--; if ( i <= firingIndex ) { firingIndex--; } } } // Remove the element list.splice( i--, 1 ); // If we have some unicity property then // we only need to do this once if ( flags.unique ) { break; } } } } } return this; }, // Control if a given callback is in the list has: function( fn ) { if ( list ) { var i = 0, length = list.length; for ( ; i < length; i++ ) { if ( fn === list[ i ] ) { return true; } } } return false; }, // Remove all callbacks from the list empty: function() { list = []; return this; }, // Have the list do nothing anymore disable: function() { list = stack = memory = undefined; return this; }, // Is it disabled? disabled: function() { return !list; }, // Lock the list in its current state lock: function() { stack = undefined; if ( !memory || memory === true ) { self.disable(); } return this; }, // Is it locked? locked: function() { return !stack; }, // Call all callbacks with the given context and arguments fireWith: function( context, args ) { if ( stack ) { if ( firing ) { if ( !flags.once ) { stack.push( [ context, args ] ); } } else if ( !( flags.once && memory ) ) { fire( context, args ); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!memory; } }; return self; }; var // Static reference to slice sliceDeferred = [].slice; jQuery.extend({ Deferred: function( func ) { var doneList = jQuery.Callbacks( "once memory" ), failList = jQuery.Callbacks( "once memory" ), progressList = jQuery.Callbacks( "memory" ), state = "pending", lists = { resolve: doneList, reject: failList, notify: progressList }, promise = { done: doneList.add, fail: failList.add, progress: progressList.add, state: function() { return state; }, // Deprecated isResolved: doneList.fired, isRejected: failList.fired, then: function( doneCallbacks, failCallbacks, progressCallbacks ) { deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); return this; }, always: function() { deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); return this; }, pipe: function( fnDone, fnFail, fnProgress ) { return jQuery.Deferred(function( newDefer ) { jQuery.each( { done: [ fnDone, "resolve" ], fail: [ fnFail, "reject" ], progress: [ fnProgress, "notify" ] }, function( handler, data ) { var fn = data[ 0 ], action = data[ 1 ], returned; if ( jQuery.isFunction( fn ) ) { deferred[ handler ](function() { returned = fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); } else { newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); } }); } else { deferred[ handler ]( newDefer[ action ] ); } }); }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { if ( obj == null ) { obj = promise; } else { for ( var key in promise ) { obj[ key ] = promise[ key ]; } } return obj; } }, deferred = promise.promise({}), key; for ( key in lists ) { deferred[ key ] = lists[ key ].fire; deferred[ key + "With" ] = lists[ key ].fireWith; } // Handle state deferred.done( function() { state = "resolved"; }, failList.disable, progressList.lock ).fail( function() { state = "rejected"; }, doneList.disable, progressList.lock ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; }, // Deferred helper when: function( firstParam ) { var args = sliceDeferred.call( arguments, 0 ), i = 0, length = args.length, pValues = new Array( length ), count = length, pCount = length, deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? firstParam : jQuery.Deferred(), promise = deferred.promise(); function resolveFunc( i ) { return function( value ) { args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; if ( !( --count ) ) { deferred.resolveWith( deferred, args ); } }; } function progressFunc( i ) { return function( value ) { pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; deferred.notifyWith( promise, pValues ); }; } if ( length > 1 ) { for ( ; i < length; i++ ) { if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); } else { --count; } } if ( !count ) { deferred.resolveWith( deferred, args ); } } else if ( deferred !== firstParam ) { deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); } return promise; } }); jQuery.support = (function() { var support, all, a, select, opt, input, marginDiv, fragment, tds, events, eventName, i, isSupported, div = document.createElement( "div" ), documentElement = document.documentElement; // Preliminary tests div.setAttribute("className", "t"); div.innerHTML = "
a"; all = div.getElementsByTagName( "*" ); a = div.getElementsByTagName( "a" )[ 0 ]; // Can't get basic test support if ( !all || !all.length || !a ) { return {}; } // First batch of supports tests select = document.createElement( "select" ); opt = select.appendChild( document.createElement("option") ); input = div.getElementsByTagName( "input" )[ 0 ]; support = { // IE strips leading whitespace when .innerHTML is used leadingWhitespace: ( div.firstChild.nodeType === 3 ), // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables tbody: !div.getElementsByTagName("tbody").length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE htmlSerialize: !!div.getElementsByTagName("link").length, // Get the style information from getAttribute // (IE uses .cssText instead) style: /top/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) hrefNormalized: ( a.getAttribute("href") === "/a" ), // Make sure that element opacity exists // (IE uses filter instead) // Use a regex to work around a WebKit issue. See #5145 opacity: /^0.55/.test( a.style.opacity ), // Verify style float existence // (IE uses styleFloat instead of cssFloat) cssFloat: !!a.style.cssFloat, // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) checkOn: ( input.value === "on" ), // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) getSetAttribute: div.className !== "t", // Tests for enctype support on a form(#6743) enctype: !!document.createElement("form").enctype, // Makes sure cloning an html5 element does not cause problems // Where outerHTML is undefined, this still works html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", // Will be defined later submitBubbles: true, changeBubbles: true, focusinBubbles: false, deleteExpando: true, noCloneEvent: true, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, reliableMarginRight: true }; // Make sure checked status is properly cloned input.checked = true; support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled // (WebKit marks them as disabled) select.disabled = true; support.optDisabled = !opt.disabled; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; } catch( e ) { support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { div.attachEvent( "onclick", function() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) support.noCloneEvent = false; }); div.cloneNode( true ).fireEvent( "onclick" ); } // Check if a radio maintains its value // after being appended to the DOM input = document.createElement("input"); input.value = "t"; input.setAttribute("type", "radio"); support.radioValue = input.value === "t"; input.setAttribute("checked", "checked"); div.appendChild( input ); fragment = document.createDocumentFragment(); fragment.appendChild( div.lastChild ); // WebKit doesn't clone checked state correctly in fragments support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; // Check if a disconnected checkbox will retain its checked // value of true after appended to the DOM (IE6/7) support.appendChecked = input.checked; fragment.removeChild( input ); fragment.appendChild( div ); div.innerHTML = ""; // Check if div with explicit width and no margin-right incorrectly // gets computed margin-right based on width of container. For more // info see bug #3333 // Fails in WebKit before Feb 2011 nightlies // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right if ( window.getComputedStyle ) { marginDiv = document.createElement( "div" ); marginDiv.style.width = "0"; marginDiv.style.marginRight = "0"; div.style.width = "2px"; div.appendChild( marginDiv ); support.reliableMarginRight = ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; } // Technique from Juriy Zaytsev // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ // We only care about the case where non-standard event systems // are used, namely in IE. Short-circuiting here helps us to // avoid an eval call (in setAttribute) which can cause CSP // to go haywire. See: https://developer.mozilla.org/en/Security/CSP if ( div.attachEvent ) { for( i in { submit: 1, change: 1, focusin: 1 }) { eventName = "on" + i; isSupported = ( eventName in div ); if ( !isSupported ) { div.setAttribute( eventName, "return;" ); isSupported = ( typeof div[ eventName ] === "function" ); } support[ i + "Bubbles" ] = isSupported; } } fragment.removeChild( div ); // Null elements to avoid leaks in IE fragment = select = opt = marginDiv = div = input = null; // Run tests that need a body at doc ready jQuery(function() { var container, outer, inner, table, td, offsetSupport, conMarginTop, ptlm, vb, style, html, body = document.getElementsByTagName("body")[0]; if ( !body ) { // Return for frameset docs that don't have a body return; } conMarginTop = 1; ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;"; vb = "visibility:hidden;border:0;"; style = "style='" + ptlm + "border:5px solid #000;padding:0;'"; html = "
" + "" + "
"; container = document.createElement("div"); container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; body.insertBefore( container, body.firstChild ); // Construct the test element div = document.createElement("div"); container.appendChild( div ); // Check if table cells still have offsetWidth/Height when they are set // to display:none and there are still other visible table cells in a // table row; if so, offsetWidth/Height are not reliable for use when // determining if an element has been hidden directly using // display:none (it is still safe to use offsets if a parent element is // hidden; don safety goggles and see bug #4512 for more information). // (only IE 8 fails this test) div.innerHTML = "
t
"; tds = div.getElementsByTagName( "td" ); isSupported = ( tds[ 0 ].offsetHeight === 0 ); tds[ 0 ].style.display = ""; tds[ 1 ].style.display = "none"; // Check if empty table cells still have offsetWidth/Height // (IE <= 8 fail this test) support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); // Figure out if the W3C box model works as expected div.innerHTML = ""; div.style.width = div.style.paddingLeft = "1px"; jQuery.boxModel = support.boxModel = div.offsetWidth === 2; if ( typeof div.style.zoom !== "undefined" ) { // Check if natively block-level elements act like inline-block // elements when setting their display to 'inline' and giving // them layout // (IE < 8 does this) div.style.display = "inline"; div.style.zoom = 1; support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); // Check if elements with layout shrink-wrap their children // (IE 6 does this) div.style.display = ""; div.innerHTML = "
"; support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); } div.style.cssText = ptlm + vb; div.innerHTML = html; outer = div.firstChild; inner = outer.firstChild; td = outer.nextSibling.firstChild.firstChild; offsetSupport = { doesNotAddBorder: ( inner.offsetTop !== 5 ), doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) }; inner.style.position = "fixed"; inner.style.top = "20px"; // safari subtracts parent border width here which is 5px offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); inner.style.position = inner.style.top = ""; outer.style.overflow = "hidden"; outer.style.position = "relative"; offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); body.removeChild( container ); div = container = null; jQuery.extend( support, offsetSupport ); }); return support; })(); var rbrace = /^(?:\{.*\}|\[.*\])$/, rmultiDash = /([A-Z])/g; jQuery.extend({ cache: {}, // Please use with caution uuid: 0, // Unique for each copy of jQuery on the page // Non-digits removed to match rinlinejQuery expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), // The following elements throw uncatchable exceptions if you // attempt to add expando properties to them. noData: { "embed": true, // Ban all objects except for Flash (which handle expandos) "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", "applet": true }, hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; return !!elem && !isEmptyDataObject( elem ); }, data: function( elem, name, data, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var privateCache, thisCache, ret, internalKey = jQuery.expando, getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, isEvents = name === "events"; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { return; } if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { elem[ internalKey ] = id = ++jQuery.uuid; } else { id = internalKey; } } if ( !cache[ id ] ) { cache[ id ] = {}; // Avoids exposing jQuery metadata on plain JS objects when the object // is serialized using JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } } // An object can be passed to jQuery.data instead of a key/value pair; this gets // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { cache[ id ] = jQuery.extend( cache[ id ], name ); } else { cache[ id ].data = jQuery.extend( cache[ id ].data, name ); } } privateCache = thisCache = cache[ id ]; // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined // data. if ( !pvt ) { if ( !thisCache.data ) { thisCache.data = {}; } thisCache = thisCache.data; } if ( data !== undefined ) { thisCache[ jQuery.camelCase( name ) ] = data; } // Users should not attempt to inspect the internal events object using jQuery.data, // it is undocumented and subject to change. But does anyone listen? No. if ( isEvents && !thisCache[ name ] ) { return privateCache.events; } // Check for both converted-to-camel and non-converted data property names // If a data property was specified if ( getByName ) { // First Try to find as-is property data ret = thisCache[ name ]; // Test for null|undefined property data if ( ret == null ) { // Try to find the camelCased property ret = thisCache[ jQuery.camelCase( name ) ]; } } else { ret = thisCache; } return ret; }, removeData: function( elem, name, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var thisCache, i, l, // Reference to internal data cache key internalKey = jQuery.expando, isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, // See jQuery.data for more information id = isNode ? elem[ internalKey ] : internalKey; // If there is already no cache entry for this object, there is no // purpose in continuing if ( !cache[ id ] ) { return; } if ( name ) { thisCache = pvt ? cache[ id ] : cache[ id ].data; if ( thisCache ) { // Support array or space separated string names for data keys if ( !jQuery.isArray( name ) ) { // try the string as a key before any manipulation if ( name in thisCache ) { name = [ name ]; } else { // split the camel cased version by spaces unless a key with the spaces exists name = jQuery.camelCase( name ); if ( name in thisCache ) { name = [ name ]; } else { name = name.split( " " ); } } } for ( i = 0, l = name.length; i < l; i++ ) { delete thisCache[ name[i] ]; } // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { return; } } } // See jQuery.data for more information if ( !pvt ) { delete cache[ id ].data; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it if ( !isEmptyDataObject(cache[ id ]) ) { return; } } // Browsers that fail expando deletion also refuse to delete expandos on // the window, but it will allow it on all other JS objects; other browsers // don't care // Ensure that `cache` is not a window object #10080 if ( jQuery.support.deleteExpando || !cache.setInterval ) { delete cache[ id ]; } else { cache[ id ] = null; } // We destroyed the cache and need to eliminate the expando on the node to avoid // false lookups in the cache for entries that no longer exist if ( isNode ) { // IE does not allow us to delete expando properties from nodes, // nor does it have a removeAttribute function on Document nodes; // we must handle all of these cases if ( jQuery.support.deleteExpando ) { delete elem[ internalKey ]; } else if ( elem.removeAttribute ) { elem.removeAttribute( internalKey ); } else { elem[ internalKey ] = null; } } }, // For internal use only. _data: function( elem, name, data ) { return jQuery.data( elem, name, data, true ); }, // A method for determining if a DOM node can handle the data expando acceptData: function( elem ) { if ( elem.nodeName ) { var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; if ( match ) { return !(match === true || elem.getAttribute("classid") !== match); } } return true; } }); jQuery.fn.extend({ data: function( key, value ) { var parts, attr, name, data = null; if ( typeof key === "undefined" ) { if ( this.length ) { data = jQuery.data( this[0] ); if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) { attr = this[0].attributes; for ( var i = 0, l = attr.length; i < l; i++ ) { name = attr[i].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.substring(5) ); dataAttr( this[0], name, data[ name ] ); } } jQuery._data( this[0], "parsedAttrs", true ); } } return data; } else if ( typeof key === "object" ) { return this.each(function() { jQuery.data( this, key ); }); } parts = key.split("."); parts[1] = parts[1] ? "." + parts[1] : ""; if ( value === undefined ) { data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); // Try to fetch any internally stored data first if ( data === undefined && this.length ) { data = jQuery.data( this[0], key ); data = dataAttr( this[0], key, data ); } return data === undefined && parts[1] ? this.data( parts[0] ) : data; } else { return this.each(function() { var self = jQuery( this ), args = [ parts[0], value ]; self.triggerHandler( "setData" + parts[1] + "!", args ); jQuery.data( this, key, value ); self.triggerHandler( "changeData" + parts[1] + "!", args ); }); } }, removeData: function( key ) { return this.each(function() { jQuery.removeData( this, key ); }); } }); function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : jQuery.isNumeric( data ) ? parseFloat( data ) : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} // Make sure we set the data so it isn't changed later jQuery.data( elem, key, data ); } else { data = undefined; } } return data; } // checks a cache object for emptiness function isEmptyDataObject( obj ) { for ( var name in obj ) { // if the public data object is empty, the private is still empty if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { continue; } if ( name !== "toJSON" ) { return false; } } return true; } function handleQueueMarkDefer( elem, type, src ) { var deferDataKey = type + "defer", queueDataKey = type + "queue", markDataKey = type + "mark", defer = jQuery._data( elem, deferDataKey ); if ( defer && ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { // Give room for hard-coded callbacks to fire first // and eventually mark/queue something else on the element setTimeout( function() { if ( !jQuery._data( elem, queueDataKey ) && !jQuery._data( elem, markDataKey ) ) { jQuery.removeData( elem, deferDataKey, true ); defer.fire(); } }, 0 ); } } jQuery.extend({ _mark: function( elem, type ) { if ( elem ) { type = ( type || "fx" ) + "mark"; jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); } }, _unmark: function( force, elem, type ) { if ( force !== true ) { type = elem; elem = force; force = false; } if ( elem ) { type = type || "fx"; var key = type + "mark", count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); if ( count ) { jQuery._data( elem, key, count ); } else { jQuery.removeData( elem, key, true ); handleQueueMarkDefer( elem, type, "mark" ); } } }, queue: function( elem, type, data ) { var q; if ( elem ) { type = ( type || "fx" ) + "queue"; q = jQuery._data( elem, type ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !q || jQuery.isArray(data) ) { q = jQuery._data( elem, type, jQuery.makeArray(data) ); } else { q.push( data ); } } return q || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), fn = queue.shift(), hooks = {}; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift( "inprogress" ); } jQuery._data( elem, type + ".run", hooks ); fn.call( elem, function() { jQuery.dequeue( elem, type ); }, hooks ); } if ( !queue.length ) { jQuery.removeData( elem, type + "queue " + type + ".run", true ); handleQueueMarkDefer( elem, type, "queue" ); } } }); jQuery.fn.extend({ queue: function( type, data ) { if ( typeof type !== "string" ) { data = type; type = "fx"; } if ( data === undefined ) { return jQuery.queue( this[0], type ); } return this.each(function() { var queue = jQuery.queue( this, type, data ); if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; return this.queue( type, function( next, hooks ) { var timeout = setTimeout( next, time ); hooks.stop = function() { clearTimeout( timeout ); }; }); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, object ) { if ( typeof type !== "string" ) { object = type; type = undefined; } type = type || "fx"; var defer = jQuery.Deferred(), elements = this, i = elements.length, count = 1, deferDataKey = type + "defer", queueDataKey = type + "queue", markDataKey = type + "mark", tmp; function resolve() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } } while( i-- ) { if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { count++; tmp.add( resolve ); } } resolve(); return defer.promise(); } }); var rclass = /[\n\t\r]/g, rspace = /\s+/, rreturn = /\r/g, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, getSetAttribute = jQuery.support.getSetAttribute, nodeHook, boolHook, fixSpecified; jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); }, removeAttr: function( name ) { return this.each(function() { jQuery.removeAttr( this, name ); }); }, prop: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.prop ); }, removeProp: function( name ) { name = jQuery.propFix[ name ] || name; return this.each(function() { // try/catch handles cases where IE balks (such as removing a property on window) try { this[ name ] = undefined; delete this[ name ]; } catch( e ) {} }); }, addClass: function( value ) { var classNames, i, l, elem, setClass, c, cl; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).addClass( value.call(this, j, this.className) ); }); } if ( value && typeof value === "string" ) { classNames = value.split( rspace ); for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 ) { if ( !elem.className && classNames.length === 1 ) { elem.className = value; } else { setClass = " " + elem.className + " "; for ( c = 0, cl = classNames.length; c < cl; c++ ) { if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { setClass += classNames[ c ] + " "; } } elem.className = jQuery.trim( setClass ); } } } } return this; }, removeClass: function( value ) { var classNames, i, l, elem, className, c, cl; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).removeClass( value.call(this, j, this.className) ); }); } if ( (value && typeof value === "string") || value === undefined ) { classNames = ( value || "" ).split( rspace ); for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { className = (" " + elem.className + " ").replace( rclass, " " ); for ( c = 0, cl = classNames.length; c < cl; c++ ) { className = className.replace(" " + classNames[ c ] + " ", " "); } elem.className = jQuery.trim( className ); } else { elem.className = ""; } } } } return this; }, toggleClass: function( value, stateVal ) { var type = typeof value, isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { return this.each(function( i ) { jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } return this.each(function() { if ( type === "string" ) { // toggle individual class names var className, i = 0, self = jQuery( this ), state = stateVal, classNames = value.split( rspace ); while ( (className = classNames[ i++ ]) ) { // check each className given, space separated list state = isBool ? state : !self.hasClass( className ); self[ state ? "addClass" : "removeClass" ]( className ); } } else if ( type === "undefined" || type === "boolean" ) { if ( this.className ) { // store className if set jQuery._data( this, "__className__", this.className ); } // toggle whole className this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; } }); }, hasClass: function( selector ) { var className = " " + selector + " ", i = 0, l = this.length; for ( ; i < l; i++ ) { if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { return true; } } return false; }, val: function( value ) { var hooks, ret, isFunction, elem = this[0]; if ( !arguments.length ) { if ( elem ) { hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; } ret = elem.value; return typeof ret === "string" ? // handle most common string cases ret.replace(rreturn, "") : // handle cases where value is null/undef or number ret == null ? "" : ret; } return; } isFunction = jQuery.isFunction( value ); return this.each(function( i ) { var self = jQuery(this), val; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { val = value.call( this, i, self.val() ); } else { val = value; } // Treat null/undefined as ""; convert numbers to string if ( val == null ) { val = ""; } else if ( typeof val === "number" ) { val += ""; } else if ( jQuery.isArray( val ) ) { val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; // If set returns undefined, fall back to normal setting if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); } }); jQuery.extend({ valHooks: { option: { get: function( elem ) { // attributes.value is undefined in Blackberry 4.7 but // uses .value. See #6932 var val = elem.attributes.value; return !val || val.specified ? elem.value : elem.text; } }, select: { get: function( elem ) { var value, i, max, option, index = elem.selectedIndex, values = [], options = elem.options, one = elem.type === "select-one"; // Nothing was selected if ( index < 0 ) { return null; } // Loop through all the selected options i = one ? index : 0; max = one ? index + 1 : options.length; for ( ; i < max; i++ ) { option = options[ i ]; // Don't return options that are disabled or in a disabled optgroup if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } // Fixes Bug #2551 -- select.val() broken in IE after form.reset() if ( one && !values.length && options.length ) { return jQuery( options[ index ] ).val(); } return values; }, set: function( elem, value ) { var values = jQuery.makeArray( value ); jQuery(elem).find("option").each(function() { this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; }); if ( !values.length ) { elem.selectedIndex = -1; } return values; } } }, attrFn: { val: true, css: true, html: true, text: true, data: true, width: true, height: true, offset: true }, attr: function( elem, name, value, pass ) { var ret, hooks, notxml, nType = elem.nodeType; // don't get/set attributes on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } if ( pass && name in jQuery.attrFn ) { return jQuery( elem )[ name ]( value ); } // Fallback to prop when attributes are not supported if ( typeof elem.getAttribute === "undefined" ) { return jQuery.prop( elem, name, value ); } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // All attributes are lowercase // Grab necessary hook if one is defined if ( notxml ) { name = name.toLowerCase(); hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); } if ( value !== undefined ) { if ( value === null ) { jQuery.removeAttr( elem, name ); return; } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { elem.setAttribute( name, "" + value ); return value; } } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return ret === null ? undefined : ret; } }, removeAttr: function( elem, value ) { var propName, attrNames, name, l, i = 0; if ( value && elem.nodeType === 1 ) { attrNames = value.toLowerCase().split( rspace ); l = attrNames.length; for ( ; i < l; i++ ) { name = attrNames[ i ]; if ( name ) { propName = jQuery.propFix[ name ] || name; // See #9699 for explanation of this approach (setting first, then removal) jQuery.attr( elem, name, "" ); elem.removeAttribute( getSetAttribute ? name : propName ); // Set corresponding property to false for boolean attributes if ( rboolean.test( name ) && propName in elem ) { elem[ propName ] = false; } } } } }, attrHooks: { type: { set: function( elem, value ) { // We can't allow the type property to be changed (since it causes problems in IE) if ( rtype.test( elem.nodeName ) && elem.parentNode ) { jQuery.error( "type property can't be changed" ); } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { // Setting the type on a radio button after the value resets the value in IE6-9 // Reset value to it's default in case type is set after value // This is for element creation var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { elem.value = val; } return value; } } }, // Use the value property for back compat // Use the nodeHook for button elements in IE6/7 (#1954) value: { get: function( elem, name ) { if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { return nodeHook.get( elem, name ); } return name in elem ? elem.value : null; }, set: function( elem, value, name ) { if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { return nodeHook.set( elem, value, name ); } // Does not return so that setAttribute is also used elem.value = value; } } }, propFix: { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", "class": "className", maxlength: "maxLength", cellspacing: "cellSpacing", cellpadding: "cellPadding", rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", frameborder: "frameBorder", contenteditable: "contentEditable" }, prop: function( elem, name, value ) { var ret, hooks, notxml, nType = elem.nodeType; // don't get/set properties on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); if ( notxml ) { // Fix name and attach hooks name = jQuery.propFix[ name ] || name; hooks = jQuery.propHooks[ name ]; } if ( value !== undefined ) { if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { return ( elem[ name ] = value ); } } else { if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { return elem[ name ]; } } }, propHooks: { tabIndex: { get: function( elem ) { // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ var attributeNode = elem.getAttributeNode("tabindex"); return attributeNode && attributeNode.specified ? parseInt( attributeNode.value, 10 ) : rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 0 : undefined; } } } }); // Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; // Hook for boolean attributes boolHook = { get: function( elem, name ) { // Align boolean attributes with corresponding properties // Fall back to attribute presence where some booleans are not supported var attrNode, property = jQuery.prop( elem, name ); return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? name.toLowerCase() : undefined; }, set: function( elem, value, name ) { var propName; if ( value === false ) { // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); } else { // value is true since we know at this point it's type boolean and not false // Set boolean attributes to the same name and set the DOM property propName = jQuery.propFix[ name ] || name; if ( propName in elem ) { // Only set the IDL specifically if it already exists on the element elem[ propName ] = true; } elem.setAttribute( name, name.toLowerCase() ); } return name; } }; // IE6/7 do not support getting/setting some attributes with get/setAttribute if ( !getSetAttribute ) { fixSpecified = { name: true, id: true }; // Use this for any attribute in IE6/7 // This fixes almost every IE6/7 issue nodeHook = jQuery.valHooks.button = { get: function( elem, name ) { var ret; ret = elem.getAttributeNode( name ); return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? ret.nodeValue : undefined; }, set: function( elem, value, name ) { // Set the existing or create a new attribute node var ret = elem.getAttributeNode( name ); if ( !ret ) { ret = document.createAttribute( name ); elem.setAttributeNode( ret ); } return ( ret.nodeValue = value + "" ); } }; // Apply the nodeHook to tabindex jQuery.attrHooks.tabindex.set = nodeHook.set; // Set width and height to auto instead of 0 on empty string( Bug #8150 ) // This is for removals jQuery.each([ "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { set: function( elem, value ) { if ( value === "" ) { elem.setAttribute( name, "auto" ); return value; } } }); }); // Set contenteditable to false on removals(#10429) // Setting to empty string throws an error as an invalid value jQuery.attrHooks.contenteditable = { get: nodeHook.get, set: function( elem, value, name ) { if ( value === "" ) { value = "false"; } nodeHook.set( elem, value, name ); } }; } // Some attributes require a special call on IE if ( !jQuery.support.hrefNormalized ) { jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { get: function( elem ) { var ret = elem.getAttribute( name, 2 ); return ret === null ? undefined : ret; } }); }); } if ( !jQuery.support.style ) { jQuery.attrHooks.style = { get: function( elem ) { // Return undefined in the case of empty string // Normalize to lowercase since IE uppercases css property names return elem.style.cssText.toLowerCase() || undefined; }, set: function( elem, value ) { return ( elem.style.cssText = "" + value ); } }; } // Safari mis-reports the default selected property of an option // Accessing the parent's selectedIndex property fixes it if ( !jQuery.support.optSelected ) { jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { get: function( elem ) { var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } return null; } }); } // IE6/7 call enctype encoding if ( !jQuery.support.enctype ) { jQuery.propFix.enctype = "encoding"; } // Radios and checkboxes getter/setter if ( !jQuery.support.checkOn ) { jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { get: function( elem ) { // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified return elem.getAttribute("value") === null ? "on" : elem.value; } }; }); } jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { set: function( elem, value ) { if ( jQuery.isArray( value ) ) { return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); } } }); }); var rformElems = /^(?:textarea|input|select)$/i, rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, rhoverHack = /\bhover(\.\S+)?\b/, rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|contextmenu)|click/, rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, quickParse = function( selector ) { var quick = rquickIs.exec( selector ); if ( quick ) { // 0 1 2 3 // [ _, tag, id, class ] quick[1] = ( quick[1] || "" ).toLowerCase(); quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); } return quick; }, quickIs = function( elem, m ) { var attrs = elem.attributes || {}; return ( (!m[1] || elem.nodeName.toLowerCase() === m[1]) && (!m[2] || (attrs.id || {}).value === m[2]) && (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) ); }, hoverHack = function( events ) { return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); }; /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { add: function( elem, types, handler, data, selector ) { var elemData, eventHandle, events, t, tns, type, namespaces, handleObj, handleObjIn, quick, handlers, special; // Don't attach events to noData or text/comment nodes (allow plain objects tho) if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { return; } // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; } // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure and main handler, if this is the first events = elemData.events; if ( !events ) { elemData.events = events = {}; } eventHandle = elemData.handle; if ( !eventHandle ) { elemData.handle = eventHandle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events eventHandle.elem = elem; } // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); types = jQuery.trim( hoverHack(types) ).split( " " ); for ( t = 0; t < types.length; t++ ) { tns = rtypenamespace.exec( types[t] ) || []; type = tns[1]; namespaces = ( tns[2] || "" ).split( "." ).sort(); // If event changes its type, use the special event handlers for the changed type special = jQuery.event.special[ type ] || {}; // If selector defined, determine special event api type, otherwise given type type = ( selector ? special.delegateType : special.bindType ) || type; // Update special based on newly reset type special = jQuery.event.special[ type ] || {}; // handleObj is passed to all event handlers handleObj = jQuery.extend({ type: type, origType: tns[1], data: data, handler: handler, guid: handler.guid, selector: selector, quick: quickParse( selector ), namespace: namespaces.join(".") }, handleObjIn ); // Init the event handler queue if we're the first handlers = events[ type ]; if ( !handlers ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add to the element's handler list, delegates in front if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, global: {}, // Detach an event or set of events from an element remove: function( elem, types, handler, selector, mappedTypes ) { var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), t, tns, type, origType, namespaces, origCount, j, events, special, handle, eventType, handleObj; if ( !elemData || !(events = elemData.events) ) { return; } // Once for each type.namespace in types; type may be omitted types = jQuery.trim( hoverHack( types || "" ) ).split(" "); for ( t = 0; t < types.length; t++ ) { tns = rtypenamespace.exec( types[t] ) || []; type = origType = tns[1]; namespaces = tns[2]; // Unbind all events (on this namespace, if provided) for the element if ( !type ) { for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } special = jQuery.event.special[ type ] || {}; type = ( selector? special.delegateType : special.bindType ) || type; eventType = events[ type ] || []; origCount = eventType.length; namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; // Remove matching events for ( j = 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !namespaces || namespaces.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { eventType.splice( j--, 1 ); if ( handleObj.selector ) { eventType.delegateCount--; } if ( special.remove ) { special.remove.call( elem, handleObj ); } } } // Remove generic event handler if we removed something and no more handlers exist // (avoids potential for endless recursion during removal of special event handlers) if ( eventType.length === 0 && origCount !== eventType.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { handle = elemData.handle; if ( handle ) { handle.elem = null; } // removeData also checks for emptiness and clears the expando if empty // so use it instead of delete jQuery.removeData( elem, [ "events", "handle" ], true ); } }, // Events that are safe to short-circuit if no handlers are attached. // Native DOM events should not be added, they may have inline handlers. customEvent: { "getData": true, "setData": true, "changeData": true }, trigger: function( event, data, elem, onlyHandlers ) { // Don't do events on text and comment nodes if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { return; } // Event object or event type var type = event.type || event, namespaces = [], cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; // focus/blur morphs to focusin/out; ensure we're not firing them right now if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } if ( type.indexOf( "!" ) >= 0 ) { // Exclusive events trigger only for the exact event (no namespaces) type = type.slice(0, -1); exclusive = true; } if ( type.indexOf( "." ) >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); type = namespaces.shift(); namespaces.sort(); } if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { // No jQuery handlers for this event type, and it can't have inline handlers return; } // Caller can pass in an Event, Object, or just an event type string event = typeof event === "object" ? // jQuery.Event object event[ jQuery.expando ] ? event : // Object literal new jQuery.Event( type, event ) : // Just the event type (string) new jQuery.Event( type ); event.type = type; event.isTrigger = true; event.exclusive = exclusive; event.namespace = namespaces.join( "." ); event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; // Handle a global trigger if ( !elem ) { // TODO: Stop taunting the data cache; remove global events and always attach to document cache = jQuery.cache; for ( i in cache ) { if ( cache[ i ].events && cache[ i ].events[ type ] ) { jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); } } return; } // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data != null ? jQuery.makeArray( data ) : []; data.unshift( event ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) eventPath = [[ elem, special.bindType || type ]]; if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; old = null; for ( ; cur; cur = cur.parentNode ) { eventPath.push([ cur, bubbleType ]); old = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( old && old === elem.ownerDocument ) { eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); } } // Fire handlers on the event path for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { cur = eventPath[i][0]; event.type = eventPath[i][1]; handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); } // Note that this is a bare JS function and not a jQuery handler handle = ontype && cur[ ontype ]; if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { event.preventDefault(); } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { // Call a native DOM method on the target with the same name name as the event. // Can't use an .isFunction() check here because IE6/7 fails that test. // Don't do default actions on window, that's where global variables be (#6170) // IE<9 dies on focus/blur to hidden element (#1486) if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method old = elem[ ontype ]; if ( old ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; elem[ type ](); jQuery.event.triggered = undefined; if ( old ) { elem[ ontype ] = old; } } } } return event.result; }, dispatch: function( event ) { // Make a writable jQuery.Event from the native event object event = jQuery.event.fix( event || window.event ); var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), delegateCount = handlers.delegateCount, args = [].slice.call( arguments, 0 ), run_all = !event.exclusive && !event.namespace, handlerQueue = [], i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; // Use the fix-ed jQuery.Event rather than the (read-only) native event args[0] = event; event.delegateTarget = this; // Determine handlers that should run if there are delegated events // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861) if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) { // Pregenerate a single jQuery object for reuse with .is() jqcur = jQuery(this); jqcur.context = this.ownerDocument || this; for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { selMatch = {}; matches = []; jqcur[0] = cur; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; sel = handleObj.selector; if ( selMatch[ sel ] === undefined ) { selMatch[ sel ] = ( handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) ); } if ( selMatch[ sel ] ) { matches.push( handleObj ); } } if ( matches.length ) { handlerQueue.push({ elem: cur, matches: matches }); } } } // Add the remaining (directly-bound) handlers if ( handlers.length > delegateCount ) { handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); } // Run delegates first; they may want to stop propagation beneath us for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { matched = handlerQueue[ i ]; event.currentTarget = matched.elem; for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { handleObj = matched.matches[ j ]; // Triggered event must either 1) be non-exclusive and have no namespace, or // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { event.data = handleObj.data; event.handleObj = handleObj; ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) .apply( matched.elem, args ); if ( ret !== undefined ) { event.result = ret; if ( ret === false ) { event.preventDefault(); event.stopPropagation(); } } } } } return event.result; }, // Includes some event props shared by KeyEvent and MouseEvent // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), fixHooks: {}, keyHooks: { props: "char charCode key keyCode".split(" "), filter: function( event, original ) { // Add which for key events if ( event.which == null ) { event.which = original.charCode != null ? original.charCode : original.keyCode; } return event; } }, mouseHooks: { props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), filter: function( event, original ) { var eventDoc, doc, body, button = original.button, fromElement = original.fromElement; // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && original.clientX != null ) { eventDoc = event.target.ownerDocument || document; doc = eventDoc.documentElement; body = eventDoc.body; event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); } // Add relatedTarget, if necessary if ( !event.relatedTarget && fromElement ) { event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && button !== undefined ) { event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); } return event; } }, fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } // Create a writable copy of the event object and normalize some properties var i, prop, originalEvent = event, fixHook = jQuery.event.fixHooks[ event.type ] || {}, copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; event = jQuery.Event( originalEvent ); for ( i = copy.length; i; ) { prop = copy[ --i ]; event[ prop ] = originalEvent[ prop ]; } // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) if ( !event.target ) { event.target = originalEvent.srcElement || document; } // Target should not be a text node (#504, Safari) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) if ( event.metaKey === undefined ) { event.metaKey = event.ctrlKey; } return fixHook.filter? fixHook.filter( event, originalEvent ) : event; }, special: { ready: { // Make sure the ready event is setup setup: jQuery.bindReady }, load: { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, focus: { delegateType: "focusin" }, blur: { delegateType: "focusout" }, beforeunload: { setup: function( data, namespaces, eventHandle ) { // We only want to do this special case on windows if ( jQuery.isWindow( this ) ) { this.onbeforeunload = eventHandle; } }, teardown: function( namespaces, eventHandle ) { if ( this.onbeforeunload === eventHandle ) { this.onbeforeunload = null; } } } }, simulate: function( type, elem, event, bubble ) { // Piggyback on a donor event to simulate a different one. // Fake originalEvent to avoid donor's stopPropagation, but if the // simulated event prevents default then we do the same on the donor. var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true, originalEvent: {} } ); if ( bubble ) { jQuery.event.trigger( e, null, elem ); } else { jQuery.event.dispatch.call( elem, e ); } if ( e.isDefaultPrevented() ) { event.preventDefault(); } } }; // Some plugins are using, but it's undocumented/deprecated and will be removed. // The 1.7 special event interface should provide all the hooks needed now. jQuery.event.handle = jQuery.event.dispatch; jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { if ( elem.removeEventListener ) { elem.removeEventListener( type, handle, false ); } } : function( elem, type, handle ) { if ( elem.detachEvent ) { elem.detachEvent( "on" + type, handle ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !(this instanceof jQuery.Event) ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // Create a timestamp if incoming event doesn't have one this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; function returnFalse() { return false; } function returnTrue() { return true; } // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { preventDefault: function() { this.isDefaultPrevented = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if preventDefault exists run it on the original event if ( e.preventDefault ) { e.preventDefault(); // otherwise set the returnValue property of the original event to false (IE) } else { e.returnValue = false; } }, stopPropagation: function() { this.isPropagationStopped = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if stopPropagation exists run it on the original event if ( e.stopPropagation ) { e.stopPropagation(); } // otherwise set the cancelBubble property of the original event to true (IE) e.cancelBubble = true; }, stopImmediatePropagation: function() { this.isImmediatePropagationStopped = returnTrue; this.stopPropagation(); }, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse }; // Create mouseenter/leave events using mouseover/out and event-time checks jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, bindType: fix, handle: function( event ) { var target = this, related = event.relatedTarget, handleObj = event.handleObj, selector = handleObj.selector, ret; // For mousenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if ( !related || (related !== target && !jQuery.contains( target, related )) ) { event.type = handleObj.origType; ret = handleObj.handler.apply( this, arguments ); event.type = fix; } return ret; } }; }); // IE submit delegation if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { setup: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Lazy-add a submit handler when a descendant form may potentially be submitted jQuery.event.add( this, "click._submit keypress._submit", function( e ) { // Node name check avoids a VML-related crash in IE (#9807) var elem = e.target, form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; if ( form && !form._submit_attached ) { jQuery.event.add( form, "submit._submit", function( event ) { // If form was submitted by the user, bubble the event up the tree if ( this.parentNode && !event.isTrigger ) { jQuery.event.simulate( "submit", this.parentNode, event, true ); } }); form._submit_attached = true; } }); // return undefined since we don't need an event listener }, teardown: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Remove delegated handlers; cleanData eventually reaps submit handlers attached above jQuery.event.remove( this, "._submit" ); } }; } // IE change delegation and checkbox/radio fix if ( !jQuery.support.changeBubbles ) { jQuery.event.special.change = { setup: function() { if ( rformElems.test( this.nodeName ) ) { // IE doesn't fire change on a check/radio until blur; trigger it on click // after a propertychange. Eat the blur-change in special.change.handle. // This still fires onchange a second time for check/radio after blur. if ( this.type === "checkbox" || this.type === "radio" ) { jQuery.event.add( this, "propertychange._change", function( event ) { if ( event.originalEvent.propertyName === "checked" ) { this._just_changed = true; } }); jQuery.event.add( this, "click._change", function( event ) { if ( this._just_changed && !event.isTrigger ) { this._just_changed = false; jQuery.event.simulate( "change", this, event, true ); } }); } return false; } // Delegated event; lazy-add a change handler on descendant inputs jQuery.event.add( this, "beforeactivate._change", function( e ) { var elem = e.target; if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { jQuery.event.add( elem, "change._change", function( event ) { if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { jQuery.event.simulate( "change", this.parentNode, event, true ); } }); elem._change_attached = true; } }); }, handle: function( event ) { var elem = event.target; // Swallow native change events from checkbox/radio, we already triggered them above if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { return event.handleObj.handler.apply( this, arguments ); } }, teardown: function() { jQuery.event.remove( this, "._change" ); return rformElems.test( this.nodeName ); } }; } // Create "bubbling" focus and blur events if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler while someone wants focusin/focusout var attaches = 0, handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); }; jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { document.addEventListener( orig, handler, true ); } }, teardown: function() { if ( --attaches === 0 ) { document.removeEventListener( orig, handler, true ); } } }; }); } jQuery.fn.extend({ on: function( types, selector, data, fn, /*INTERNAL*/ one ) { var origFn, type; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = selector; selector = undefined; } for ( type in types ) { this.on( type, selector, data, types[ type ], one ); } return this; } if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return this; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return this.each( function() { jQuery.event.add( this, types, fn, data, selector ); }); }, one: function( types, selector, data, fn ) { return this.on.call( this, types, selector, data, fn, 1 ); }, off: function( types, selector, fn ) { if ( types && types.preventDefault && types.handleObj ) { // ( event ) dispatched jQuery.Event var handleObj = types.handleObj; jQuery( types.delegateTarget ).off( handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type, handleObj.selector, handleObj.handler ); return this; } if ( typeof types === "object" ) { // ( types-object [, selector] ) for ( var type in types ) { this.off( type, selector, types[ type ] ); } return this; } if ( selector === false || typeof selector === "function" ) { // ( types [, fn] ) fn = selector; selector = undefined; } if ( fn === false ) { fn = returnFalse; } return this.each(function() { jQuery.event.remove( this, types, fn, selector ); }); }, bind: function( types, data, fn ) { return this.on( types, null, data, fn ); }, unbind: function( types, fn ) { return this.off( types, null, fn ); }, live: function( types, data, fn ) { jQuery( this.context ).on( types, this.selector, data, fn ); return this; }, die: function( types, fn ) { jQuery( this.context ).off( types, this.selector || "**", fn ); return this; }, delegate: function( selector, types, data, fn ) { return this.on( types, selector, data, fn ); }, undelegate: function( selector, types, fn ) { // ( namespace ) or ( selector, types [, fn] ) return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); }, trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { if ( this[0] ) { return jQuery.event.trigger( type, data, this[0], true ); } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, guid = fn.guid || jQuery.guid++, i = 0, toggler = function( event ) { // Figure out which function to execute var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); // Make sure that clicks stop event.preventDefault(); // and execute the function return args[ lastToggle ].apply( this, arguments ) || false; }; // link all the functions, so any of them can unbind this click handler toggler.guid = guid; while ( i < args.length ) { args[ i++ ].guid = guid; } return this.click( toggler ); }, hover: function( fnOver, fnOut ) { return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); } }); jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { if ( fn == null ) { fn = data; data = null; } return arguments.length > 0 ? this.on( name, null, data, fn ) : this.trigger( name ); }; if ( jQuery.attrFn ) { jQuery.attrFn[ name ] = true; } if ( rkeyEvent.test( name ) ) { jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; } if ( rmouseEvent.test( name ) ) { jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; } }); /*! * Sizzle CSS Selector Engine * Copyright 2016, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, expando = "sizcache" + (Math.random() + '').replace('.', ''), done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true, rBackslash = /\\/g, rReturn = /\r\n/g, rNonWord = /\W/; // Here we check if the JavaScript engine is using some sort of // optimization where it does not always call our comparison // function. If that is the case, discard the hasDuplicate value. // Thus far that includes Google Chrome. [0, 0].sort(function() { baseHasDuplicate = false; return 0; }); var Sizzle = function( selector, context, results, seed ) { results = results || []; context = context || document; var origContext = context; if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } if ( !selector || typeof selector !== "string" ) { return results; } var m, set, checkSet, extra, ret, cur, pop, i, prune = true, contextXML = Sizzle.isXML( context ), parts = [], soFar = selector; // Reset the position of the chunker regexp (start from head) do { chunker.exec( "" ); m = chunker.exec( soFar ); if ( m ) { soFar = m[3]; parts.push( m[1] ); if ( m[2] ) { extra = m[3]; break; } } } while ( m ); if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context, seed ); } else { set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) { selector += parts.shift(); } set = posProcess( selector, set, seed ); } } } else { // Take a shortcut and set the context if the root selector is an ID // (but not if it'll be faster if the inner selector is an ID) if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } if ( context ) { ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray( set ); } else { prune = false; } while ( parts.length ) { cur = parts.pop(); pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; } } if ( !checkSet ) { checkSet = set; } if ( !checkSet ) { Sizzle.error( cur || selector ); } if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } else if ( context && context.nodeType === 1 ) { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); } if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); } return results; }; Sizzle.uniqueSort = function( results ) { if ( sortOrder ) { hasDuplicate = baseHasDuplicate; results.sort( sortOrder ); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { if ( results[i] === results[ i - 1 ] ) { results.splice( i--, 1 ); } } } } return results; }; Sizzle.matches = function( expr, set ) { return Sizzle( expr, null, null, set ); }; Sizzle.matchesSelector = function( node, expr ) { return Sizzle( expr, null, null, [node] ).length > 0; }; Sizzle.find = function( expr, context, isXML ) { var set, i, len, match, type, left; if ( !expr ) { return []; } for ( i = 0, len = Expr.order.length; i < len; i++ ) { type = Expr.order[i]; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { left = match[1]; match.splice( 1, 1 ); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace( rBackslash, "" ); set = Expr.find[ type ]( match, context, isXML ); if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; } } } } if ( !set ) { set = typeof context.getElementsByTagName !== "undefined" ? context.getElementsByTagName( "*" ) : []; } return { set: set, expr: expr }; }; Sizzle.filter = function( expr, set, inplace, not ) { var match, anyFound, type, found, item, filter, left, i, pass, old = expr, result = [], curLoop = set, isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); while ( expr && set.length ) { for ( type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { filter = Expr.filter[ type ]; left = match[1]; anyFound = false; match.splice(1,1); if ( left.substr( left.length - 1 ) === "\\" ) { continue; } if ( curLoop === result ) { result = []; } if ( Expr.preFilter[ type ] ) { match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; } else if ( match === true ) { continue; } } if ( match ) { for ( i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); pass = not ^ found; if ( inplace && found != null ) { if ( pass ) { anyFound = true; } else { curLoop[i] = false; } } else if ( pass ) { result.push( item ); anyFound = true; } } } } if ( found !== undefined ) { if ( !inplace ) { curLoop = result; } expr = expr.replace( Expr.match[ type ], "" ); if ( !anyFound ) { return []; } break; } } } // Improper expression if ( expr === old ) { if ( anyFound == null ) { Sizzle.error( expr ); } else { break; } } old = expr; } return curLoop; }; Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; /** * Utility function for retrieving the text value of an array of DOM nodes * @param {Array|Element} elem */ var getText = Sizzle.getText = function( elem ) { var i, node, nodeType = elem.nodeType, ret = ""; if ( nodeType ) { if ( nodeType === 1 || nodeType === 9 ) { // Use textContent || innerText for elements if ( typeof elem.textContent === 'string' ) { return elem.textContent; } else if ( typeof elem.innerText === 'string' ) { // Replace IE's carriage returns return elem.innerText.replace( rReturn, '' ); } else { // Traverse it's children for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { ret += getText( elem ); } } } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } } else { // If no nodeType, this is expected to be an array for ( i = 0; (node = elem[i]); i++ ) { // Do not traverse comment nodes if ( node.nodeType !== 8 ) { ret += getText( node ); } } } return ret; }; var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ }, leftMatch: {}, attrMap: { "class": "className", "for": "htmlFor" }, attrHandle: { href: function( elem ) { return elem.getAttribute( "href" ); }, type: function( elem ) { return elem.getAttribute( "type" ); } }, relative: { "+": function(checkSet, part){ var isPartStr = typeof part === "string", isTag = isPartStr && !rNonWord.test( part ), isPartStrNotTag = isPartStr && !isTag; if ( isTag ) { part = part.toLowerCase(); } for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { if ( (elem = checkSet[i]) ) { while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? elem || false : elem === part; } } if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function( checkSet, part ) { var elem, isPartStr = typeof part === "string", i = 0, l = checkSet.length; if ( isPartStr && !rNonWord.test( part ) ) { part = part.toLowerCase(); for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; } } } else { for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } }, "": function(checkSet, part, isXML){ var nodeCheck, doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !rNonWord.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); }, "~": function( checkSet, part, isXML ) { var nodeCheck, doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !rNonWord.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); } }, find: { ID: function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 return m && m.parentNode ? [m] : []; } }, NAME: function( match, context ) { if ( typeof context.getElementsByName !== "undefined" ) { var ret = [], results = context.getElementsByName( match[1] ); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { ret.push( results[i] ); } } return ret.length === 0 ? null : ret; } }, TAG: function( match, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( match[1] ); } } }, preFilter: { CLASS: function( match, curLoop, inplace, result, not, isXML ) { match = " " + match[1].replace( rBackslash, "" ) + " "; if ( isXML ) { return match; } for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { if ( !inplace ) { result.push( elem ); } } else if ( inplace ) { curLoop[i] = false; } } } return false; }, ID: function( match ) { return match[1].replace( rBackslash, "" ); }, TAG: function( match, curLoop ) { return match[1].replace( rBackslash, "" ).toLowerCase(); }, CHILD: function( match ) { if ( match[1] === "nth" ) { if ( !match[2] ) { Sizzle.error( match[0] ); } match[2] = match[2].replace(/^\+|\s*/g, ''); // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); // calculate the numbers (first)n+(last) including if they are negative match[2] = (test[1] + (test[2] || 1)) - 0; match[3] = test[3] - 0; } else if ( match[2] ) { Sizzle.error( match[0] ); } // TODO: Move to normal caching system match[0] = done++; return match; }, ATTR: function( match, curLoop, inplace, result, not, isXML ) { var name = match[1] = match[1].replace( rBackslash, "" ); if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } // Handle if an un-quoted value was used match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); if ( match[2] === "~=" ) { match[4] = " " + match[4] + " "; } return match; }, PSEUDO: function( match, curLoop, inplace, result, not ) { if ( match[1] === "not" ) { // If we're dealing with a complex expression, or a simple one if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); if ( !inplace ) { result.push.apply( result, ret ); } return false; } } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, POS: function( match ) { match.unshift( true ); return match; } }, filters: { enabled: function( elem ) { return elem.disabled === false && elem.type !== "hidden"; }, disabled: function( elem ) { return elem.disabled === true; }, checked: function( elem ) { return elem.checked === true; }, selected: function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, parent: function( elem ) { return !!elem.firstChild; }, empty: function( elem ) { return !elem.firstChild; }, has: function( elem, i, match ) { return !!Sizzle( match[3], elem ).length; }, header: function( elem ) { return (/h\d/i).test( elem.nodeName ); }, text: function( elem ) { var attr = elem.getAttribute( "type" ), type = elem.type; // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); }, radio: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; }, checkbox: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; }, file: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; }, password: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; }, submit: function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && "submit" === elem.type; }, image: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; }, reset: function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && "reset" === elem.type; }, button: function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && "button" === elem.type || name === "button"; }, input: function( elem ) { return (/input|select|textarea|button/i).test( elem.nodeName ); }, focus: function( elem ) { return elem === elem.ownerDocument.activeElement; } }, setFilters: { first: function( elem, i ) { return i === 0; }, last: function( elem, i, match, array ) { return i === array.length - 1; }, even: function( elem, i ) { return i % 2 === 0; }, odd: function( elem, i ) { return i % 2 === 1; }, lt: function( elem, i, match ) { return i < match[3] - 0; }, gt: function( elem, i, match ) { return i > match[3] - 0; }, nth: function( elem, i, match ) { return match[3] - 0 === i; }, eq: function( elem, i, match ) { return match[3] - 0 === i; } }, filter: { PSEUDO: function( elem, match, i, array ) { var name = match[1], filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; for ( var j = 0, l = not.length; j < l; j++ ) { if ( not[j] === elem ) { return false; } } return true; } else { Sizzle.error( name ); } }, CHILD: function( elem, match ) { var first, last, doneName, parent, cache, count, diff, type = match[1], node = elem; switch ( type ) { case "only": case "first": while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) { return false; } } if ( type === "first" ) { return true; } node = elem; case "last": while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) { return false; } } return true; case "nth": first = match[2]; last = match[3]; if ( first === 1 && last === 0 ) { return true; } doneName = match[0]; parent = elem.parentNode; if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } parent[ expando ] = doneName; } diff = elem.nodeIndex - last; if ( first === 0 ) { return diff === 0; } else { return ( diff % first === 0 && diff / first >= 0 ); } } }, ID: function( elem, match ) { return elem.nodeType === 1 && elem.getAttribute("id") === match; }, TAG: function( elem, match ) { return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; }, CLASS: function( elem, match ) { return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, ATTR: function( elem, match ) { var name = match[1], result = Sizzle.attr ? Sizzle.attr( elem, name ) : Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : elem.getAttribute( name ), value = result + "", type = match[2], check = match[4]; return result == null ? type === "!=" : !type && Sizzle.attr ? result != null : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value !== check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false; }, POS: function( elem, match, i, array ) { var name = match[2], filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } } } }; var origPOS = Expr.match.POS, fescape = function(all, num){ return "\\" + (num - 0 + 1); }; for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); } var makeArray = function( array, results ) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { results.push.apply( results, array ); return results; } return array; }; // Perform a simple check to determine if the browser is capable of // converting a NodeList to an array using builtin methods. // Also verifies that the returned array holds DOM nodes // (which is not the case in the Blackberry browser) try { Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; // Provide a fallback method if it does not work } catch( e ) { makeArray = function( array, results ) { var i = 0, ret = results || []; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); } else { if ( typeof array.length === "number" ) { for ( var l = array.length; i < l; i++ ) { ret.push( array[i] ); } } else { for ( ; array[i]; i++ ) { ret.push( array[i] ); } } } return ret; }; } var sortOrder, siblingCheck; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; return 0; } if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { return a.compareDocumentPosition ? -1 : 1; } return a.compareDocumentPosition(b) & 4 ? -1 : 1; }; } else { sortOrder = function( a, b ) { // The nodes are identical, we can exit early if ( a === b ) { hasDuplicate = true; return 0; // Fallback to using sourceIndex (in IE) if it's available on both nodes } else if ( a.sourceIndex && b.sourceIndex ) { return a.sourceIndex - b.sourceIndex; } var al, bl, ap = [], bp = [], aup = a.parentNode, bup = b.parentNode, cur = aup; // If the nodes are siblings (or identical) we can do a quick check if ( aup === bup ) { return siblingCheck( a, b ); // If no parents were found then the nodes are disconnected } else if ( !aup ) { return -1; } else if ( !bup ) { return 1; } // Otherwise they're somewhere else in the tree so we need // to build up a full list of the parentNodes for comparison while ( cur ) { ap.unshift( cur ); cur = cur.parentNode; } cur = bup; while ( cur ) { bp.unshift( cur ); cur = cur.parentNode; } al = ap.length; bl = bp.length; // Start walking down the tree looking for a discrepancy for ( var i = 0; i < al && i < bl; i++ ) { if ( ap[i] !== bp[i] ) { return siblingCheck( ap[i], bp[i] ); } } // We ended someplace up the tree so do a sibling check return i === al ? siblingCheck( a, bp[i], -1 ) : siblingCheck( ap[i], b, 1 ); }; siblingCheck = function( a, b, ret ) { if ( a === b ) { return ret; } var cur = a.nextSibling; while ( cur ) { if ( cur === b ) { return -1; } cur = cur.nextSibling; } return 1; }; } // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ // We're going to inject a fake input element with a specified name var form = document.createElement("div"), id = "script" + (new Date()).getTime(), root = document.documentElement; form.innerHTML = ""; // Inject it into the root element, check its status, and remove it quickly root.insertBefore( form, root.firstChild ); // The workaround has to do additional checks after a getElementById // Which slows things down for other browsers (hence the branching) if ( document.getElementById( id ) ) { Expr.find.ID = function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; } }; Expr.filter.ID = function( elem, match ) { var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); // release memory in IE root = form = null; })(); (function(){ // Check to see if the browser returns only elements // when doing getElementsByTagName("*") // Create a fake element var div = document.createElement("div"); div.appendChild( document.createComment("") ); // Make sure no comments are found if ( div.getElementsByTagName("*").length > 0 ) { Expr.find.TAG = function( match, context ) { var results = context.getElementsByTagName( match[1] ); // Filter out possible comments if ( match[1] === "*" ) { var tmp = []; for ( var i = 0; results[i]; i++ ) { if ( results[i].nodeType === 1 ) { tmp.push( results[i] ); } } results = tmp; } return results; }; } // Check to see if an attribute returns normalized href attributes div.innerHTML = ""; if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { Expr.attrHandle.href = function( elem ) { return elem.getAttribute( "href", 2 ); }; } // release memory in IE div = null; })(); if ( document.querySelectorAll ) { (function(){ var oldSizzle = Sizzle, div = document.createElement("div"), id = "__sizzle__"; div.innerHTML = "

"; // Safari can't handle uppercase or unicode characters when // in quirks mode. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } Sizzle = function( query, context, extra, seed ) { context = context || document; // Only use querySelectorAll on non-XML documents // (ID selectors don't work in non-HTML documents) if ( !seed && !Sizzle.isXML(context) ) { // See if we find a selector to speed up var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { // Speed-up: Sizzle("TAG") if ( match[1] ) { return makeArray( context.getElementsByTagName( query ), extra ); // Speed-up: Sizzle(".CLASS") } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { return makeArray( context.getElementsByClassName( match[2] ), extra ); } } if ( context.nodeType === 9 ) { // Speed-up: Sizzle("body") // The body element only exists once, optimize finding it if ( query === "body" && context.body ) { return makeArray( [ context.body ], extra ); // Speed-up: Sizzle("#ID") } else if ( match && match[3] ) { var elem = context.getElementById( match[3] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id === match[3] ) { return makeArray( [ elem ], extra ); } } else { return makeArray( [], extra ); } } try { return makeArray( context.querySelectorAll(query), extra ); } catch(qsaError) {} // qSA works strangely on Element-rooted queries // We can work around this by specifying an extra ID on the root // and working up from there (Thanks to Andrew Dupont for the technique) // IE 8 doesn't work on object elements } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { var oldContext = context, old = context.getAttribute( "id" ), nid = old || id, hasParent = context.parentNode, relativeHierarchySelector = /^\s*[+~]/.test( query ); if ( !old ) { context.setAttribute( "id", nid ); } else { nid = nid.replace( /'/g, "\\$&" ); } if ( relativeHierarchySelector && hasParent ) { context = context.parentNode; } try { if ( !relativeHierarchySelector || hasParent ) { return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); } } catch(pseudoError) { } finally { if ( !old ) { oldContext.removeAttribute( "id" ); } } } } return oldSizzle(query, context, extra, seed); }; for ( var prop in oldSizzle ) { Sizzle[ prop ] = oldSizzle[ prop ]; } // release memory in IE div = null; })(); } (function(){ var html = document.documentElement, matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; if ( matches ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9 fails this) var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), pseudoWorks = false; try { // This should fail with an exception // Gecko does not error, returns false instead matches.call( document.documentElement, "[test!='']:sizzle" ); } catch( pseudoError ) { pseudoWorks = true; } Sizzle.matchesSelector = function( node, expr ) { // Make sure that attribute selectors are quoted expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); if ( !Sizzle.isXML( node ) ) { try { if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { var ret = matches.call( node, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || !disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9, so check for that node.document && node.document.nodeType !== 11 ) { return ret; } } } catch(e) {} } return Sizzle(expr, null, null, [node]).length > 0; }; } })(); (function(){ var div = document.createElement("div"); div.innerHTML = "
"; // Opera can't find a second classname (in 9.6) // Also, make sure that getElementsByClassName actually exists if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { return; } // Safari caches class attributes, doesn't catch changes (in 3.2) div.lastChild.className = "e"; if ( div.getElementsByClassName("e").length === 1 ) { return; } Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function( match, context, isXML ) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; // release memory in IE div = null; })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var match = false; elem = elem[dir]; while ( elem ) { if ( elem[ expando ] === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ elem[ expando ] = doneName; elem.sizset = i; } if ( elem.nodeName.toLowerCase() === cur ) { match = elem; break; } elem = elem[dir]; } checkSet[i] = match; } } } function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var match = false; elem = elem[dir]; while ( elem ) { if ( elem[ expando ] === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { elem[ expando ] = doneName; elem.sizset = i; } if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; break; } } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { match = elem; break; } } elem = elem[dir]; } checkSet[i] = match; } } } if ( document.documentElement.contains ) { Sizzle.contains = function( a, b ) { return a !== b && (a.contains ? a.contains(b) : true); }; } else if ( document.documentElement.compareDocumentPosition ) { Sizzle.contains = function( a, b ) { return !!(a.compareDocumentPosition(b) & 16); }; } else { Sizzle.contains = function() { return false; }; } Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; var posProcess = function( selector, context, seed ) { var match, tmpSet = [], later = "", root = context.nodeType ? [context] : context; // Position selectors must be done after the filter // And so must :not(positional) so we move all PSEUDOs to the end while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet, seed ); } return Sizzle.filter( later, tmpSet ); }; // EXPOSE // Override sizzle attribute retrieval Sizzle.attr = jQuery.attr; Sizzle.selectors.attrMap = {}; jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.filters; jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; })(); var runtil = /Until$/, rparentsprev = /^(?:parents|prevUntil|prevAll)/, // Note: This RegExp should be improved, or likely pulled from Sizzle rmultiselector = /,/, isSimple = /^.[^:#\[\.,]*$/, slice = Array.prototype.slice, POS = jQuery.expr.match.POS, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.fn.extend({ find: function( selector ) { var self = this, i, l; if ( typeof selector !== "string" ) { return jQuery( selector ).filter(function() { for ( i = 0, l = self.length; i < l; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }); } var ret = this.pushStack( "", "find", selector ), length, n, r; for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique for ( n = length; n < ret.length; n++ ) { for ( r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; } } } } } return ret; }, has: function( target ) { var targets = jQuery( target ); return this.filter(function() { for ( var i = 0, l = targets.length; i < l; i++ ) { if ( jQuery.contains( this, targets[i] ) ) { return true; } } }); }, not: function( selector ) { return this.pushStack( winnow(this, selector, false), "not", selector); }, filter: function( selector ) { return this.pushStack( winnow(this, selector, true), "filter", selector ); }, is: function( selector ) { return !!selector && ( typeof selector === "string" ? // If this is a positional selector, check membership in the returned set // so $("p:first").is("p:last") won't return true for a doc with two "p". POS.test( selector ) ? jQuery( selector, this.context ).index( this[0] ) >= 0 : jQuery.filter( selector, this ).length > 0 : this.filter( selector ).length > 0 ); }, closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; // Array (deprecated as of jQuery 1.7) if ( jQuery.isArray( selectors ) ) { var level = 1; while ( cur && cur.ownerDocument && cur !== context ) { for ( i = 0; i < selectors.length; i++ ) { if ( jQuery( cur ).is( selectors[ i ] ) ) { ret.push({ selector: selectors[ i ], elem: cur, level: level }); } } cur = cur.parentNode; level++; } return ret; } // String var pos = POS.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; while ( cur ) { if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { ret.push( cur ); break; } else { cur = cur.parentNode; if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { break; } } } } ret = ret.length > 1 ? jQuery.unique( ret ) : ret; return this.pushStack( ret, "closest", selectors ); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; } // index in selector if ( typeof elem === "string" ) { return jQuery.inArray( this[0], jQuery( elem ) ); } // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used elem.jquery ? elem[0] : elem, this ); }, add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? all : jQuery.unique( all ) ); }, andSelf: function() { return this.add( this.prevObject ); } }); // A painfully simple check to see if an element is disconnected // from a document (should be improved, where feasible). function isDisconnected( node ) { return !node || !node.parentNode || node.parentNode.nodeType === 11; } jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return jQuery.nth( elem, 2, "nextSibling" ); }, prev: function( elem ) { return jQuery.nth( elem, 2, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( elem.parentNode.firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : jQuery.makeArray( elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ); if ( !runtil.test( name ) ) { selector = until; } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); } ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { ret = ret.reverse(); } return this.pushStack( ret, name, slice.call( arguments ).join(",") ); }; }); jQuery.extend({ filter: function( expr, elems, not ) { if ( not ) { expr = ":not(" + expr + ")"; } return elems.length === 1 ? jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : jQuery.find.matches(expr, elems); }, dir: function( elem, dir, until ) { var matched = [], cur = elem[ dir ]; while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { matched.push( cur ); } cur = cur[dir]; } return matched; }, nth: function( cur, result, dir, elem ) { result = result || 1; var num = 0; for ( ; cur; cur = cur[dir] ) { if ( cur.nodeType === 1 && ++num === result ) { break; } } return cur; }, sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { r.push( n ); } } return r; } }); // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { // Can't pass null or undefined to indexOf in Firefox 4 // Set to 0 to skip string check qualifier = qualifier || 0; if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); return retVal === keep; }); } else if ( qualifier.nodeType ) { return jQuery.grep(elements, function( elem, i ) { return ( elem === qualifier ) === keep; }); } else if ( typeof qualifier === "string" ) { var filtered = jQuery.grep(elements, function( elem ) { return elem.nodeType === 1; }); if ( isSimple.test( qualifier ) ) { return jQuery.filter(qualifier, filtered, !keep); } else { qualifier = jQuery.filter( qualifier, filtered ); } } return jQuery.grep(elements, function( elem, i ) { return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; }); } function createSafeFragment( document ) { var list = nodeNames.split( "|" ), safeFrag = document.createDocumentFragment(); if ( safeFrag.createElement ) { while ( list.length ) { safeFrag.createElement( list.pop() ); } } return safeFrag; } var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, rtagName = /<([\w:]+)/, rtbody = /", "" ], legend: [ 1, "
", "
" ], thead: [ 1, "", "
" ], tr: [ 2, "", "
" ], td: [ 3, "", "
" ], col: [ 2, "", "
" ], area: [ 1, "", "" ], _default: [ 0, "", "" ] }, safeFragment = createSafeFragment( document ); wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; // IE can't serialize and