pax_global_header00006660000000000000000000000064147732551510014524gustar00rootroot0000000000000052 comment=a8ee38880fa8ec21eeab188756fdc082b46eda76 sptlrx-1.2.3/000077500000000000000000000000001477325515100130635ustar00rootroot00000000000000sptlrx-1.2.3/.github/000077500000000000000000000000001477325515100144235ustar00rootroot00000000000000sptlrx-1.2.3/.github/workflows/000077500000000000000000000000001477325515100164605ustar00rootroot00000000000000sptlrx-1.2.3/.github/workflows/release.yml000066400000000000000000000011451477325515100206240ustar00rootroot00000000000000name: goreleaser on: push: tags: - '*' permissions: contents: write jobs: goreleaser: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.24.1' - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser version: latest args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} sptlrx-1.2.3/.gitignore000066400000000000000000000005041477325515100150520ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ dist/ # Built executable sptlrx # IDE files .vscode/sptlrx-1.2.3/.goreleaser.yaml000066400000000000000000000006771477325515100161670ustar00rootroot00000000000000before: hooks: - go mod tidy builds: - env: - CGO_ENABLED=0 goos: - linux - windows - darwin - freebsd goarch: - "386" - amd64 - arm64 - arm ignore: - goos: windows goarch: arm checksum: name_template: "checksums.txt" snapshot: name_template: "{{ incpatch .Version }}-next" changelog: sort: asc filters: exclude: - "^docs:" - "^test:" sptlrx-1.2.3/LICENSE000066400000000000000000000020461477325515100140720ustar00rootroot00000000000000MIT License Copyright (c) 2022 Denis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sptlrx-1.2.3/README.md000066400000000000000000000146731477325515100143550ustar00rootroot00000000000000

sptlrx

Synchronized lyrics in your terminal

## Features - Compatible with Spotify, MPD, Mopidy, MPRIS and browsers. - Works well with long lines & Unicode characters. - Easy to customize. - Allows piping to stdout. - Single binary & cross-plaftorm. ## Installation **Linux** - Arch Linux ([@BachoSeven](https://github.com/BachoSeven)) ``` yay -S sptlrx-bin ``` - NixOS ([@MoritzBoehme](https://github.com/MoritzBoehme)) ``` nix-env -iA nixos.sptlrx ``` or if using nixpkgs ``` nix-env -iA nixpkgs.sptlrx ``` - Other ``` curl -sSL instl.sh/raitonoberu/sptlrx/linux | bash ``` **Windows** ``` iwr instl.sh/raitonoberu/sptlrx/windows | iex ``` **macOS** ``` curl -sSL instl.sh/raitonoberu/sptlrx/macos | bash ``` You can also download the binary from the [Releases](https://github.com/raitonoberu/sptlrx/releases/latest) page or [build it yourself](./building.md). ## Configuration Config file will be created at the first launch. On Linux it's located in `~/.config/sptlrx/config.yaml`. Run `sptlrx -h` to see the full path.
Show config contents (with descriptions) ```yaml ### Global settings ### # Your Spotify cookie. Only needed if you are going to use Spotify as a player. cookie: "" # Player that will be used. Possible values: spotify, mpd, mopidy, mpris. player: spotify # Host of lyrics API to be used in case the cookie is not provided. host: lyricsapi.vercel.app # Whether to ignore errors instead of showing them. ignoreErrors: true # Interval of the internal timer. Determines how often the terminal will be updated. timerInterval: 200 # Interval for checking the position. Doesn't really affect the precision. updateInterval: 2000 ### Style settings ### style: # Horizontal alignment of lines. Possible values: left, center, right. hAlignment: center # Style of the lines before the current one. before: # The colors can be either in HEX format, or ANSI 0-255. background: "" foreground: "" bold: true italic: false underline: false strikethrough: false blink: false faint: false # Style of the current line. current: # The colors can be either in HEX format, or ANSI 0-255. background: "" foreground: "" bold: true italic: false underline: false strikethrough: false blink: false faint: false # Style of the lines after the current one. after: # The colors can be either in HEX format, or ANSI 0-255. background: "" foreground: "" bold: false italic: false underline: false strikethrough: false blink: false faint: true ### Pipe settings ### pipe: # Maximum line length. 0 - unlimited. length: 0 # How to handle overflowing strings. Possible values: word, none, ellipsis. overflow: word ### MPD settings ### mpd: # MPD server address with port. address: 127.0.0.1:6600 # MPD server password (if any). password: "" ### Mopidy settings ### mopidy: # Mopidy server address with port. address: 127.0.0.1:6680 ### MPRIS settings ### mpris: # Whitelist of MPRIS players. First available is used if empty. players: [] ### Browser extension settings ### browser: # Port on which the server will be started. port: 8974 ### Local lyrics source ### local: # Folder for scanning .lrc files. Example: "~/Music". folder: "" ```
### Spotify ```yaml # config.yaml cookie: player: spotify ``` If you want to use Spotify as your player or lyrics source, you need to specify your cookie. 1. Open your browser. 2. Press F12, open the `Network` tab and go to [open.spotify.com](https://open.spotify.com/). 3. Click on the first request to `open.spotify.com`. 4. Scroll down to the `Request Headers`, right click the `cookie` field and select `Copy value`. 5. Paste it to your config. You can also set the `SPOTIFY_COOKIE` environment variable or pass the `--cookie` flag. **TREAT YOUR COOKIE LIKE A PASSWORD AND NEVER SHARE IT** ### MPD ```yaml # config.yaml player: mpd mpd: address: 127.0.0.1:6600 password: "" ``` MPD server will be used as a player. ### Mopidy ```yaml # config.yaml player: mopidy mopidy: address: 127.0.0.1:6680 ``` Mopidy server will be used as a player. ### MPRIS ```yaml # config.yaml player: mpris mpris: players: [] ``` Linux only. System player that supports MPRIS protocol will be used. You can also specify a whitelist of players to use, example: `players: [rhythmbox, spotifyd, ncspot]`. Run `playerctl -l` to get the names. ### Browser ```yaml # config.yaml player: browser browser: port: 8974 ``` You need to install a [browser extension](https://wnp.keifufu.dev/extension/getting-started). If you don't change the default port, no further configuration is required. Otherwise, create a custom adapter in the extension settings. **You can only run one instance on one port.** ### Local ```yaml # config.yaml local: folder: "" ``` If you want to use your local collection of `.lrc` files to display lyrics, specify the folder to scan. The application will use files with the most similar name. All other lyrics sources will be disabled. ## Information ### Source If you specify your Spotify cookie, the lyrics will be fetched using your account. Otherwise, the API [hosted by me](https://github.com/raitonoberu/lyricsapi) will be used. It is also possible to host your own API or use local `.lrc` files. ### Piping Run `sptlrx pipe` to start printing the current lines to stdout. This can be used in various status bars and other applications. ### Flags You can pass flags to override the style parameters defined in the config. Example: ```sh sptlrx --current "bold,#FFDFD3,#957DAD" --before "104,faint,italic" --after "104,faint" ``` List of allowed styles: `bold`, `italic`, `underline`, `strikethrough`, `blink`, `faint`. The colors can be either in HEX format, or ANSI 0-255. The first color represents the foreground, the second represents the background. Run `sptlrx --help` to see all the flags. ## License **MIT License**, see [LICENSE](./LICENSE) for additional information. sptlrx-1.2.3/building.md000066400000000000000000000004521477325515100152030ustar00rootroot00000000000000## Building sptlrx Make sure you have [Go 1.18+](https://go.dev/) installed. ### Clone the repository ```sh git clone https://github.com/raitonoberu/sptlrx cd sptlrx ``` ### Fetch dependencies ```sh go get ``` ### Build it ```sh go build -ldflags '-w -s' ``` ### Run it ```sh ./sptlrx ``` sptlrx-1.2.3/cmd/000077500000000000000000000000001477325515100136265ustar00rootroot00000000000000sptlrx-1.2.3/cmd/pipe.go000066400000000000000000000033351477325515100151160ustar00rootroot00000000000000package cmd import ( "fmt" "strings" "github.com/raitonoberu/sptlrx/config" "github.com/raitonoberu/sptlrx/lyrics" "github.com/raitonoberu/sptlrx/pool" "github.com/muesli/reflow/wordwrap" "github.com/muesli/reflow/wrap" "github.com/spf13/cobra" ) var pipeCmd = &cobra.Command{ Use: "pipe", Short: "Start printing the current lines to stdout", RunE: func(cmd *cobra.Command, args []string) error { conf, err := loadConfig(cmd) if err != nil { return fmt.Errorf("couldn't load config: %w", err) } player, err := loadPlayer(conf) if err != nil { return fmt.Errorf("couldn't load player: %w", err) } provider, err := loadProvider(conf, player) if err != nil { return fmt.Errorf("couldn't load provider: %w", err) } ch := make(chan pool.Update) go pool.Listen(player, provider, conf, ch) for update := range ch { printUpdate(update, conf) } return nil }, } func printUpdate(update pool.Update, conf *config.Config) { if update.Err != nil { if !conf.IgnoreErrors { fmt.Println(update.Err.Error()) } return } if update.Lines == nil || !lyrics.Timesynced(update.Lines) { fmt.Println("") return } line := update.Lines[update.Index].Words if conf.Pipe.Length == 0 { fmt.Println(line) return } switch conf.Pipe.Overflow { case "none": s := wrap.String(line, conf.Pipe.Length) fmt.Println(strings.Split(s, "\n")[0]) case "word": s := wordwrap.String(line, conf.Pipe.Length) fmt.Println(strings.Split(s, "\n")[0]) case "ellipsis": s := wrap.String(line, conf.Pipe.Length) lines := strings.Split(s, "\n") if len(lines) == 1 { fmt.Println(lines[0]) return } s = wrap.String(lines[0], conf.Pipe.Length-3) fmt.Println(strings.Split(s, "\n")[0] + "...") } } sptlrx-1.2.3/cmd/root.go000066400000000000000000000122221477325515100151370ustar00rootroot00000000000000package cmd import ( "errors" "fmt" "os" "strings" "github.com/raitonoberu/sptlrx/config" "github.com/raitonoberu/sptlrx/lyrics" "github.com/raitonoberu/sptlrx/player" "github.com/raitonoberu/sptlrx/pool" "github.com/raitonoberu/sptlrx/services/hosted" "github.com/raitonoberu/sptlrx/services/local" "github.com/raitonoberu/sptlrx/services/spotify" "github.com/raitonoberu/sptlrx/ui" tea "github.com/charmbracelet/bubbletea" "github.com/spf13/cobra" ) const banner = ` _ _ ___ _ __ | |_ | | _ __ __ __ / __|| '_ \ | __|| || '__|\ \/ / \__ \| |_) || |_ | || | > < |___/| .__/ \__||_||_| /_/\_\ |_| ` const help = ` 1. Open your browser. 2. Press F12, open the 'Network' tab and go to open.spotify.com. 3. Click on the first request to open.spotify.com. 4. Scroll down to the 'Request Headers', right click the 'cookie' field and select 'Copy value'. 5. Paste it into your config file.` var ( FlagCookie string FlagPlayer string FlagConfig string FlagStyleBefore string FlagStyleCurrent string FlagStyleAfter string FlagHAlignment string FlagVerbose bool ) var rootCmd = &cobra.Command{ Use: "sptlrx", Short: "Synchronized lyrics in your terminal", Long: "A CLI app that shows time-synchronized lyrics in your terminal", Version: "v1.2.3", SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { conf, err := loadConfig(cmd) if err != nil { return fmt.Errorf("couldn't load config: %w", err) } player, err := loadPlayer(conf) if err != nil { return fmt.Errorf("couldn't load player: %w", err) } provider, err := loadProvider(conf, player) if err != nil { return fmt.Errorf("couldn't load provider: %w", err) } ch := make(chan pool.Update) go pool.Listen(player, provider, conf, ch) _, err = tea.NewProgram( &ui.Model{ Channel: ch, Config: conf, }, tea.WithAltScreen(), ).Run() return err }, } func loadConfig(cmd *cobra.Command) (*config.Config, error) { if cmd.Flags().Changed("config") { // custom config path config.Path = FlagConfig } conf, err := config.Load() if err != nil { if cmd.Flags().Changed("config") || !errors.Is(err, os.ErrNotExist) { return nil, err } // create new config conf = config.New() fmt.Print(banner + "\n") fmt.Printf("Config file location: %s\n", config.Path) config.Save(conf) } if envCookie := os.Getenv("SPOTIFY_COOKIE"); envCookie != "" { conf.Cookie = envCookie } if FlagCookie != "" { conf.Cookie = FlagCookie } if FlagVerbose { conf.IgnoreErrors = false } if cmd.Flags().Changed("player") { conf.Player = FlagPlayer } if cmd.Flags().Changed("before") { conf.Style.Before = parseStyleFlag(FlagStyleBefore) } if cmd.Flags().Changed("current") { conf.Style.Current = parseStyleFlag(FlagStyleCurrent) } if cmd.Flags().Changed("after") { conf.Style.After = parseStyleFlag(FlagStyleAfter) } if cmd.Flags().Changed("halign") { conf.Style.HAlignment = FlagHAlignment } return conf, nil } func loadPlayer(conf *config.Config) (player.Player, error) { player, err := config.GetPlayer(conf) if err != nil { if errors.Is(err, spotify.ErrInvalidCookie) { fmt.Println("If you want to use Spotify as your player, you need to set up your cookie.") fmt.Println(help) } return nil, err } return player, nil } func loadProvider(conf *config.Config, player player.Player) (lyrics.Provider, error) { if conf.Local.Folder != "" { return local.New(conf.Local.Folder) } if conf.Cookie == "" { return hosted.New(conf.Host), nil } if spt, ok := player.(*spotify.Client); ok { // use existing spotify client return spt, nil } // create new spotify client return spotify.New(conf.Cookie) } func parseStyleFlag(value string) config.Style { var style config.Style for _, part := range strings.Split(value, ",") { switch part { case "bold": style.Bold = true case "italic": style.Italic = true case "underline": style.Underline = true case "strikethrough": style.Strikethrough = true case "blink": style.Blink = true case "faint": style.Faint = true default: if style.Foreground == "" { style.Foreground = part } else if style.Background == "" { style.Background = part } } } return style } func init() { rootCmd.PersistentFlags().StringVarP(&FlagCookie, "cookie", "c", "", "your cookie") rootCmd.PersistentFlags().StringVarP(&FlagPlayer, "player", "p", "spotify", "what player to use") rootCmd.PersistentFlags().StringVar(&FlagConfig, "config", config.Path, "path to config file") rootCmd.Flags().StringVar(&FlagStyleBefore, "before", "bold", "style of the lines before the current one") rootCmd.Flags().StringVar(&FlagStyleCurrent, "current", "bold", "style of the current line") rootCmd.Flags().StringVar(&FlagStyleAfter, "after", "faint", "style of the lines after the current one") rootCmd.Flags().StringVar(&FlagHAlignment, "halign", "center", "initial horizontal alignment (left/center/right)") rootCmd.PersistentFlags().BoolVarP(&FlagVerbose, "verbose", "v", false, "force print errors") rootCmd.AddCommand(pipeCmd) } func Execute() { if err := rootCmd.Execute(); err != nil { os.Exit(1) } } sptlrx-1.2.3/config/000077500000000000000000000000001477325515100143305ustar00rootroot00000000000000sptlrx-1.2.3/config/config.go000066400000000000000000000102121477325515100161200ustar00rootroot00000000000000package config import ( "fmt" "github.com/raitonoberu/sptlrx/player" "github.com/raitonoberu/sptlrx/services/browser" "github.com/raitonoberu/sptlrx/services/mopidy" "github.com/raitonoberu/sptlrx/services/mpd" "github.com/raitonoberu/sptlrx/services/mpris" "github.com/raitonoberu/sptlrx/services/spotify" "os" "path" "strconv" "strings" gloss "github.com/charmbracelet/lipgloss" "github.com/creasty/defaults" "gopkg.in/yaml.v2" ) var Directory string var Path string func init() { d, err := os.UserConfigDir() if err != nil { panic(err) } Directory = path.Join(d, "sptlrx") Path = path.Join(Directory, "config.yaml") } type Config struct { Cookie string `yaml:"cookie"` Player string `default:"spotify" yaml:"player"` Host string `default:"lyricsapi.vercel.app" yaml:"host"` IgnoreErrors bool `default:"true" yaml:"ignoreErrors"` TimerInterval int `default:"200" yaml:"timerInterval"` UpdateInterval int `default:"2000" yaml:"updateInterval"` Style struct { HAlignment string `default:"center" yaml:"hAlignment"` Before Style `default:"{\"bold\": true}" yaml:"before"` Current Style `default:"{\"bold\": true}" yaml:"current"` After Style `default:"{\"faint\": true}" yaml:"after"` } `yaml:"style"` Pipe struct { Length int `yaml:"length"` Overflow string `default:"word" yaml:"overflow"` } `yaml:"pipe"` Mpd struct { Address string `default:"127.0.0.1:6600" yaml:"address"` Password string `yaml:"password"` } `yaml:"mpd"` Mopidy struct { Address string `default:"127.0.0.1:6680" yaml:"address"` } `yaml:"mopidy"` Mpris struct { Players []string `default:"[]" yaml:"players"` } `yaml:"mpris"` Browser struct { Port int `default:"8974" yaml:"port"` } `yaml:"browser"` Local struct { Folder string `yaml:"folder"` } `yaml:"local"` } func New() *Config { var config = &Config{} defaults.Set(config) return config } func Load() (*Config, error) { file, err := os.Open(Path) if err != nil { return nil, err } defer file.Close() var config = &Config{} err = yaml.NewDecoder(file).Decode(config) return config, err } func Save(config *Config) error { err := os.MkdirAll(Directory, os.ModePerm) if err != nil { return err } file, err := os.Create(Path) if err != nil { return err } defer file.Close() return yaml.NewEncoder(file).Encode(config) } // https://stackoverflow.com/a/56080478 func (c *Config) UnmarshalYAML(f func(interface{}) error) error { defaults.Set(c) type plain Config if err := f((*plain)(c)); err != nil { return err } return nil } type Style struct { Background string `yaml:"background"` Foreground string `yaml:"foreground"` Bold bool `yaml:"bold"` Italic bool `yaml:"italic"` Underline bool `yaml:"underline"` Strikethrough bool `yaml:"strikethrough"` Blink bool `yaml:"blink"` Faint bool `yaml:"faint"` } func (s Style) Parse() gloss.Style { var style gloss.Style if s.Background != "" && validateColor(s.Background) { style = style.Background(gloss.Color(s.Background)) style.ColorWhitespace(false) } if s.Foreground != "" && validateColor(s.Foreground) { style = style.Foreground(gloss.Color(s.Foreground)) } if s.Bold { style = style.Bold(true) } if s.Italic { style = style.Italic(true) } if s.Underline { style = style.Underline(true) } if s.Strikethrough { style = style.Strikethrough(true) } if s.Blink { style = style.Blink(true) } if s.Faint { style = style.Faint(true) } return style } func validateColor(color string) bool { if _, err := strconv.Atoi(color); err == nil { return true } if strings.HasPrefix(color, "#") { return true } return false } // GetPlayer returns a player based on config values func GetPlayer(conf *Config) (player.Player, error) { switch conf.Player { case "spotify": return spotify.New(conf.Cookie) case "mpd": return mpd.New(conf.Mpd.Address, conf.Mpd.Password), nil case "mopidy": return mopidy.New(conf.Mopidy.Address), nil case "mpris": return mpris.New(conf.Mpris.Players) case "browser": return browser.New(conf.Browser.Port) } return nil, fmt.Errorf("unknown player: \"%s\"", conf.Player) } sptlrx-1.2.3/demo.gif000066400000000000000000006315321477325515100145100ustar00rootroot00000000000000GIF89a X1       !!"$ #!$"%'#$'%)',2(.+// - ,!+! H"+"/$".$"1$"6%"3%#5%$8&$0&%6'$3'$5(%4(&2)&5*(8+)5,)9,*6.+<.,90-<1.?2/=30A42>52C63B85F86B;8G<9J<:H=;J=;P=;L?OB?MDAPDASECZEElFDXGDUGEYHDWHETHEVHFZIFWIG[IIxJFZJGVJGXJH[JH\KHYKIWMJ\NKZNL`OL]OMaOP|PL`PM\PM^PN`PNdQMcQN]QN_SP`URbUSgUSiVRfVSdVSVThVTjWTcWTeWTgYVg[V[Xg[Xj\Zh^Z^[k_\m`]l`]`^ta^oa_sb^tb_pb_b`vbarbatc_sc`oebsebwfcrfctfdxfdzgduge{hevhezie{ifwifyig}jgujh|jh~khyki}kilh|lizli{ljxlj~ljmimj{mkmkml}nj~nk|nlznlol}olonplpm~pnpnqn}rnrospurwtyvzw|y}z~{}ôƸȻ̽! NETSCAPE2.0!, X       !!"$ #!$"%'#$'%)',2(.+// - ,!+! H"+"/$".$"1$"6%"3%#5%$8&$0&%6'$3'$5(%4(&2)&5*(8+)5,)9,*6.+<.,90-<1.?2/=30A42>52C63B85F86B;8G<9J<:H=;J=;P=;L?OB?MDAPDASECZEElFDXGDUGEYHDWHETHEVHFZIFWIG[IIxJFZJGVJGXJH[JH\KHYKIWMJ\NKZNL`OL]OMaOP|PL`PM\PM^PN`PNdQMcQN]QN_SP`URbUSgUSiVRfVSdVSVThVTjWTcWTeWTgYVg[V[Xg[Xj\Zh^Z^[k_\m`]l`]`^ta^oa_sb^tb_pb_b`vbarbatc_sc`oebsebwfcrfctfdxfdzgduge{hevhezie{ifwifyig}jgujh|jh~khyki}kilh|lizli{ljxlj~ljmimj{mkmkml}nj~nk|nlznlol}olonplpm~pnpnqn}rnrospurwtyvzw|y}z~{}ôƸȻ̽?H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνËOӫ_Ͼ˟O_t(h`ς 6`?(Vhfv ($h(&B :(ch8<@)$.3BC6PF)TViE(;H&W)dih v`)Dp&pΩgwpfJlމ瞄f,)(hu/ 4@.Ov\^p @p@))֪J/$q3P (Jj9B!)qḓO?#($p y0),"ZV;t 8 ,F*/L2ɼ|D;d JD,qwȷ-k.2PDL?TP\A )2@A, xD4`I>r M_0йn\A $ H@CO8(B`u[w7lkBeߴO=caym9k+-?D`2ݠ=޴t]|Jt&PAm@<<`>W$aP;`Ry h.i`N$03ا- ْ>Gt8^cp:qV4-i"1s>xC BЁi (̴evA$Cܘ69ץ!HvLDX !A 9!ɇ@`$H%@IKE82bJ\V6hE+U+zɍx$L*/nIie<.K#)H^$](GQ<19da@( RF8*SIʉ @Z$,wC%/>If:Ќ4IjZ̦6nz 8IrL:v~ @JЂMBІ:D'JъZͨF7юz HGJҒ(MJWҖ0LgJӚ8ͩNwӞ@ PJԢHMRԦ:PTJժZXͪVծz` XJֲhMZֶp\J׺xͫ^׾ `KMb:d'KZͬf7z hGKҚMjWֺlgKͭnw pKMr:ЍtKZͮvz xKMz|Kͯ~LN;'L [ΰ7{ GL(NW0gL8αw@L"HN&;PL*[Xβ.{`L2hN6pL:xγ>πMBЈNF;ѐ'MJ[Ҙδ7N{ӠGMRԨNWVհgMZָεw^MbNf;ЎMj[ζn{MrNvMzη~NO;'N[ϸ7{ GN(^OW0=8Ϲwe@ЇNG3Oҗ;PԧN[XϺַ{`NhOq!,W!,W!,W(($@6ǰÇ pȱ 1L#Ǐ!E^h?ȜI0ZBDӦO6t?JhŤ>2eXOQN( 0M[_>IcҨ!3Z7vnxRUӀ5z}FNqV;tLSg ^C ACNU{~@ J moaw%>p.sg>;˴#۽q ^Zu2I7|g:2Q' p;<- |ɧN|ZԝC*"=df&5@&ώ##u&g8<ld59g05LOfXWEv&qEgSi~YfU{&)V0.4u{BNM,|ĠR"@i4piV# 3&T꫰%Q]AeS뮸VH Hl !,W!,h(($;H@~)\Ȱ?k83H BV3 ⇏ ^̈qcG CZLHҡRtCFd2LjSN3 rqm ѤKen*<ԀRWՔVwbE@t 0`9ǒ !jwڵlr&l֏WO0 L*]㦘lڸa@jo殓~Lp`Ѥ85fĠ7[tR- ݪ{ ᕫ vN߃N%,6pH*͓O;5 KF^0rUmlP AxC VhAƠ*݅!Kvhj!d%8 Q 4DS6M5BXРcDid?dPF)P.iW~cpe`~d@!,W!,W!,('$uH[Ȱ~Iyt:iCG\y@:ywoWѷ>qA3s5_nC)q<,Р]v@6D>挰f#)s.-0;)w2Du\ 4$= Cx/0+`1 2yӃR$&P\IޖQyfCة&RiʩO) @~'48"PjāV6Vfxf)E}ҧ *ʩ!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,($n;H*D@@ŋ3j8q?j )#ɒOreK/K9cM77dϋ;9L9bPEA&U(ХN6俫bʕҭ!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,)(" H*\`JHŋ !FȱǏj ɓ7I˗?p͙0sdx͞; ҔO,o)SGy-:ODFZ՘_O*E*Tϱdv6-[f-VXhm*,\rb ߼[o6Fpⵏf;ɔ 8t-fZeҭVf-3ճ;=aW}ܝ' 0^¡Ke>[2]}CC}͑bawxSE5hdMT]~ojn c Ηbzh!(U5>EuThX:&. TPVIVfZv^Z!,W!,W!,W!,W!,W!,W!,W!,{( H*\p$papȱG `@(SJ 0  xCCJB #]ʴ pYfAk0ördhxJĀ-đW퉂H5`lCIB͡R8*NH(҉C, Cl˘6.Cnzp.D>{ !*F0hg_y݌LPyg}v 6b,Q 9"A'mo [?/ 'DQ59ÎlpB 3=۸,J;U:sE6(9T;xS_ Q p퀼Q. āa A7: H1 LPpL l@ aPM H1&n4}H}FsAJMt-t@E7k 0R>K,BcB 4384O@bL3gJ L:,2q9j)фS$8`!0̄HfphȈ^4A}o8>uPL4xP,p>@@Pp0 sn9D ) !h#`mh0L+ #FآT-̈ % "3l3Nq tB/:q@"cP\A8P+b\ ! '\  $a:#Ot0 ̀7R6xY~c8 B@"y>~C cY<$~ (Bc|ste?1|y[F;ymHMẓ?1Zy>A Lp r.h&R=$ Ha8`#`@6Z|a6!{RHG6*X G/}AMCt:&Pl@^6H_<|ChA89 Hi( 2^UCL, G;!{C8B0qv`R6`$<;[v")Qwv8h)IC:xp1!@3L (W-(` (qQ1[H71]wádPi|ȇ5P̣Hx=AvwwPvC:6±Gg\,H bucX:r[p 2FqaazF  $xHIpPL/`8̎Ct@M828 :r@ eج@ `u%{ s;шFb+&8p!0'7aR@@aqBث:P ğՁ A$S)J A 61qc :V8#["HBÜ分" >#1Jێn|FBhDG5Lh; JΐSBdcD1rK-, GAr HGJbG4āT&`xBƚsCRh@\[;!q36(1oxF/6cdu٨AؼeXڨ$SAbxvZ@5 @{AUlV*@ s | d'nЍ| *{ OP0| Fv  aixMG=ȡ k;7GqL@y X}f:6r3 hG[XJS,ccbp% /rh'x6pW|8~13P`Y80 GaK)e`h9%bY6 >f `x/,WUg( HА Ȉa\@ 8P## p 3@u[ P 0* tKpz?OP\f@ #]mLbh8 @ 0q8@}(|CApEm>03Ui\/1Ѐ@ ,0 f=:0nZ SW6/8D('P0pP xX rA1`,1i q7P"U  ycu ,f `(%}کPuv3#vօ,p rF CIIy 0 z )DjhIzLʙ!)@mY]EQ p`*iap P q se }E `Pw .!0!(h07,9-6$up * nipc :!8D{ri0X(EpJaPZڐmZ5:(ኘX銤ٮQ 0L7kN _szYph# 0"& ,?Z` @ .f!+y ,@-+/ےwt xZ=ۓIpp  y 1 0 Z<Nе*l @[yG / # % )o{  Gx z+ʣ[;Gz -p7\#(b>$(Qm p R CpA%op%בwig DXph|kr {ƪ{@ ` sI[+4(P0P"zmL~ ;'T `Pp:hf0 Z 0 a|0!P!  ' X|yۈ@I p %lgspL0 z:-pZ n9)!ǫiQ;A` %@`XEcq,jp\!ņs1x <*vP  Np ӠWҀɠGQ p p "}4 0Mq` ۀ"P1ǍxFb $qݠ N=*0b ` p[ vޠ [<w  PZ P 9"a)͈{*R _ЀѶ".͍͹9L ذٵ.O/fG`N; "  X>Q ń+ 'ШVU]-* F] mA uZ @&`i=iM&p@0mE]=3Hz0⠜]gqB9|c^s`m,L>J`Q}06m`Z*)p` tV ]ڐQ=٠Lpى+ +LY0֦52A?pPFDZu cg Noeq gb8fb#kp TCh J @ 0( QHGv*1C@ @ tP\PF@R͹@נPFa`ꝮTP @ Y0y cgՀ5P`Y Roz~[PpqL8!` J@a+pZQE,X,``0b=_ A$ E T@#f rIprI2r?9.pEL} JtMو'PNKJ`G\L@8GCEoHU6H0PKJp{)C6PGPLP#@0Mr? F 9JPJbAE3K0O60NP¦81b!q!fL4aEQ6w]F=b 4I@@TRdF 7؁2CpB7b0>UTU^tC~ F \U/3x -\{gC (xPN;`fVzU\#_MC {jxA Fܑċ7= +la$z% avU` v衻U U⽟>4X 9f}MwuZ~@{a0B '0yy2}Ʊ OD1EWOy&P@Pdzޑ"?2H!PwAk J+lywġH0quG˲M7̒nGo%Q "yY28%0Aygva|g(h34SM7('QaygkvpSW_5t"hGyg{!,5Xa倂-zGz  aXkeP"Rd(„~6]u`hgyEj_8@ %_P8p@P/F `||Jc,89*5mdS֠enYtr(X3H|Թ9H%PN1#h ):7Y9N ވG#Kjšk*Ii!khuk`em9kB)&7qNHHb<ڀ$f7fA*Ə(Sjd jop+g{N hglb `$L~R"q `j'q"8D>f %Nѥ@浄 π)2a䥈%ED $Y^4 (T#? ka$a̯~?0op3x@"b% l AIh[؆$)d!8'P#ИBGj}VaB~ßUD!E pF XD>N%` (^[#@E+b#  nde|d6q}M |Hb8)Nrle)BJZe؂3qt+BJĒ;f'IZEtS8q ɎҔtC䞳UOF#PNRi̦Sx,Fśb4! R#&$f8Ϡ6b"I 3$a6,Pż8 [U#B3h1N&Eh1 UHGJ1 =:B1`+Txi"$o38r?,eHG@P w0(PO43R 0A=!#X4t eja;j{, cD" Ei8?DXHU,nvJ <  p8Mx%9[P )hͨ^$-:fP-f8B2^Yh,qA ihv"Cn6Ptdj\8 FCA$HhLAq 4(#9[7p* P6 aHI@P hh [8^OxG,׌AWR*kVSm`FWHalFT)1]O ХaA@ h7g[I` Q=A@Ki,iC Q>liLc Ϋ784Ԋs$lGc Y40^jI(u2<0h`{}j )¼T~F#j0H0DZրVv H)t.B% )0!|P5,EȲȎ0hψ-A xg -? @^`PF-.Y`ihO4A 0)`πd5p3"@O4$adApNБ lA8H1G4CRp?4o"p&fL+j3;)#[g?{ 8 `O+h?REhxc @kS?)(i-'-`jx̚)pqCxiX #H(PA:fx$Жʤl% hsڀ%Q ]L'x»+8(p_`F H[- '1. hjhūkЂ%8fH=l h׻ ðijp!hjx90g%ЍPUE( P`) hh- D k8 pPLDh>P#Gjl[5 3E `M()fEmw`R?GG7-XTDE B`P8Xh#yi_CFɍBf?-ج&N;sEHHPC`ԍHRC.H5B`8"خ1CSDF%Xh\# Sr kp  ܏V87HpH\]^4 Sl#&bigilpi:;!أ H? 'fҀ`7Q Pcوh҂O? H"3 ip&( P{ Hkp.yB$FH&4%PDfˬ ̆_ ī-CD HxH<i -a`%hfiCa4#10p ;Pd#ț,1h`M2xS0=Ҁj` `Z$u$8kxQ΢EH\khG 8h8i(W_'юp3fp Mlz pPܰ؂h0K5R7KЀ`.%Cl;,(=5)8&8` `>Pϫ#kS'Ph pz)Y-Gu͎ؔ12H pb.KTc)p#X'O*銃aSj  \hPV`OE|h.()JPPh8FRԃҲ8oMPh߼j5'RH+FPu +߹lul)xXqX8lXu5f@َһC" %T݈LYY2fPSL !#c(Ԧ!Hhj`-_j&h"8,Z+^Tb[p-H `k[zHOԲՁF?]?*1~|n~,Xg8,h&Ȃ{chH]2i88$mP&|XJ*H>isNo.ih`|-XLA@hT\XضɁfkZXkbO҆A9%J-fke^D3٦p#hl_+Hq _,0:c2-j,Wjx~TyH hZ0;>ng1R_hfܦThՀh 8P1ki8.X\6)6XǑڽ@]X@*\j!VZj[jIJqo"#HZx1؀çȫ;z xRc] & ۄqXG,&-zl87x*pkh1ރhY8hλeYgvYfx&, $ XpkP di;"5C 58j@LIX1r)*w#3P&x(>hCX)rA h]-؀q)c(쌀*<8#u:hm3耊Q BHop,ؾ!  ca r,PS1"Pp `8#‹PIkؚS*eL Fظa< x X? ,*`M8Xg,hkpr hvlnP]tq;`Ps܎=G-xfh 8_y%H&1\[ P ϊ#ڂXo"qTX8b8;H#@P+B8A|0 =,'u f%K3%O8CRz\={$;Ⲟ~$""C*9 P @c适Jԣф(Lc*ұ@Q $ )ӡ ~XCL5( ]PxiTtf=+Z35C5MU+\BӲ,`x&x`̆hJ2fX " S\ c Z$awfiiS2(Px+kc h%ZH 08e+܏јB J!M4*8 [p5: Sтb:E0F :ge[+kԘ'A 0pΗ24!-[`4&:xA oQ'}[1%ZC3,`.~1yؽ($K CEKsWk :15| )ڪҏp4cBfP,fֲ4p70?E$}Yjf Jf8gAm51- a4¨r:Sp(`qC[:*PPo6jQ`%Y?Q ̧5\-Qk.vV_[~6hScu5#2VA jzuz[```kLxF7 +-$ -P90!Vx{90[cƁ t4"f p ø@:`9(5!r R(-Q>mDcS QSl \CX^ͧU84 vB 0?&H%Uzv 5pVum/x{4@~,გ,1P\mks@BBPѧr'j# Y e?fZV`~Ax.d 0t@y%"D#Y}ʔmZA/Tfe',@-şU `3XCR`4@T fp06\\@!B@ B6("h& @(N$.a!!6LTaz *!RF ހ &\1L W\!rNp*(@#2$JQ#&"'.]L#B&'`n]@@A1mAHA85DNOX&T3 P4 ̍/JA <A@J@"O E (( S!4Pq @HVN@3"AY<"B]@/BA  K""DA R̎ c`GPMf G\I 0\b{T-An] l*̤X-HNxLY 7}D65ȉ6XC5>c˓0CDJUGH4T 48裵0lC,@C^,C5H0TM3HR>ޡ #Q]B5ˉP  0 bAM$p $!h85 5Dre#$Er!P?Z`A#(W6HAD#$`A2  2/ B5Z}o4PC+$ \W37vDC4H0Zս/a,3NCD-HPB@(X80SWZ,̖A`$l8C$HC)t@ .0$4ā4# q qQqnKD [DJ,H@D(A0$h/C)xqCP/$IXc^4 1(`/ U"DGDn 1Tf,3/S5(W5^q@;I7X_X3Y' 0V7O@iX hADkyb ت8-`-$8C ݳB$Og'Am Hi9eD04l;xLcD @?â j9y@4xJnH|=9@$TC#!`Q2$(Ɓz6_xz'-NA_H|yHt@$d)w/Hv-`CB@ wЍI -09*$(A @ B<3dJXf#0AlXL @# {OXr۬/ @ $,]bA5 4kio{W֛mA pJ d,4A p28A 4"=d p}L4hP2pOD5`~p@uuSOX&-A $H`@B X37@8`A&TaC!F-iѤeԘ'!:PLchˆdFx`@耏3Ӝii ` C~]-4EAAxIrГg&KV@"+ˬE!S Т#8Φ ŨN:-΃"`3r#L vfR 5s0"ifhh5F\ j$M / 426ԑ eGlK5\ J"W3R$O/^ O7n& <1j֙)IO>; fCf$"` h,H0C*h"gih%Z 0d&PқA2H#i>"DBgN,%@ EDaN#30"ge(A/=Fh7#4(!j(R0`d-FϠ \0aL`ofF)  ` e"B zgFO,ǫ[qJ_KažBVX:W_dyAa `YJЖb%V^y 7"e\s]6Xg XfEv\i{_p ke(%ބ!^`k!F s-m倃 6PYe-e\fǛ F]!B:h}6HWnji&{~z! `&#hDn~!4Oh:сּ\ /u(` f 1\ `3%J69O]You9 ia (߁^BffO^1A'hb z_.){/Y pdߏp X@i@[B8 [(lA .@5a &p>A`.Цl&8B8A҈ -DE_llfa ?D\i S% 8@(W0`9 وFƄ8@I#Y@ >, ې\M]% ,HՈD. ĠРA(LfjZt;I!B6M.P@X5 <`s3?hՀתVQMg,Q{Ɔ.h'0PтēIpF6Q, )xdҋQŨxl*RSGxP3Ӥ4!E4-5NeFс P@85` 8Eu8dl3` P x01`m}k\ ԀFz(/uG;fq0v Z;tdqn\G*3¶5.lp8I (hř !jaa;@l^(!PAd̀ t nu}]UX%`#C?P#wz^ "?0cX;!wMABP j@(x$3jPBOH,O$h A%6` ]*5-`h x&1dlA _jh0(14Ɛ\ {9'H7<03 Fp@ B]j|=5*)=f \.0`@0e` ԭla-t-S E rim:@h-@f@D *@A8FO 8B) "tָ H|&PLXX.BA?ehH# ,!M Qdp]݈h(E5*Q(tM`u7l"sQsY(E5l'[xP!@aqA ,[*"C# ,|$ gsXTI*0DDl`xW1 EȀO085@(D̀0A 6Z" tAI *Pp g\*)o`@PpB)ސA:"j IJTJ@ P*b@2Cp(`  #B  Kp !#BXDE`N! A@S/ !1Tm &qP 0 M`BzFq .D QL J BN4@pXEa ֺK*aC" q)'8I˂`Y&:maТ.zf Qia`J".0 u;ƨ5!-1C )8 0g4"` @Q$?@ )fZlZ` ư'çt((e膀` *^6!` | -,2*rA.J .S0q 1<1O',3"F fo $2.4WJ!ZA"$`!rŸxS!@D!|`/@p:Le K͠6! 6!ړ-޳)"*!ֲ4I`?? +Oy s0031932%.'4C=s@t4pЬV@aT!Xr&)b܀82>aܠ7TI(T02 # Lxa T,3M糵)v?[@O0A ;PQ2B1!r#;@RsUCB  r @EEMiT0Uu !. !`ޤ >V'lh>Jb8d`AD$)$!nZt"uMԧ1\?bVKuuP33^# s"`BU"(" j Cr`I`65mE{EGՈ&V7Q5*nhNDYI'o5̠H: ]v!uT$}T5@ lN LBZMhQD ((R vNk`@c@Ak1l,lf: &H>V`-4i@o66_TbMUpp j&o@ A* "Ws6 `s cm`arBb ,O@21v[iWMq8 R |Z4_:$ $` @5صyz#   z_xjQ f R  W,NNL`"  B}f rsf< `f@ bfc!}2N!!y>0{&KHޔtA &P)$,ɶ!@G"AlAb"8t._ ALC AL5ka AIlFlQ{y!6SAJa ,rИ8>(ab$OA6Tޠ$@ES $f% lGr8 `hw<kna (fޠej"8Vf6 $alY,D @a `!88Dq?u%P" a!AnB!ACT "$X FbZyAd bUo aA[Z S>d r􉥡s` xB@ ; ̠`i" (@ ` `a נ ~HW ) \@@BN v @  ZR@ ͂w HI⽙@Z ր h.  Ȁ @ XnJ \w ao< @ @ۜ` L` ZB l| , F a)[z8G!xf_ b~l} .~~& fV'f4@|=jFO!!ާ8gP&}<4`gc#cFVBg `Ώ;@hOܰa .6ͣ'& "!n1@)!V]ٽ` F=]|ٽݽ)~@@! }0A #>9@!`-~. @N!|/>E^0|'p+ǀ#8kT~iHmxHldž}@lrJGalG?@6zݍ>>WDSaQF  :4B+VuCAܾz  C` 8:6~ 4p5 vo 4mq V""A { Z~x mG> ``^I_4@6%`N:^k\TE< 0 ; 4}sUtRna ma`;?y <0… :4x!4?.4<ؐl[`\A0h[:|<2ʕ,[|AhPx,pA;L(vkp^W:+eҴ8"ݑ@3O$$>O8F$T T]4$<3*xI(Rl@S #HMx"L$HqȰ!~8 j0ZPZmC327:2  #`Ҍ4|2a)[ @!##[H@!i1r tx 5TBa(j`AL 4B'4!‚P(YDq( 88##|AAP$عjto0*A",q!V$4RȨ ,@pmy5PY 6H9&PM6\1~Ц@0\3/5 C`4,6q0আPcMA"XM5BtZ#  8H ;Ac T 0 8r5Al5ج26|Y!T6cp$3(7,S 6/GP"MZ/|x4XM5p6yLh#47%l@CD `BA4 g#54`@J; CHy6s E03m+3ϵC+̈́xp3Ẍ16Y{VHDڣ q0ֈP BEPQ 5hAB^p4`(XYC'(V$`B M!n 2 0 2!w 4Ȣig/1ʏ3s-nP 0 w@ pif[l29vw luGo ;2cr` spC I jekio @  ] ڧ-@@ 2u0 Or 1' P'p &  4-p"2UVڨ٪ f3@R;tYp Z057vXz wA ?@K 0%Xc @{.0(њ  KCE_`.$ A@  n `CD\5)U G3S0 P0t ?~X< ັ.a3k3|@I P`i-sP PZ0L 37pOj&FA@ ? q eE<x}M?c P Ovh)ƚ2?Qv:0 r$a(` Mw`Λ{HZd {  -Z'cKoT6G ?LJ~dʖ:] `PBH7~ 0À[K ` p `\0S  7@yW-\ `Q*oqΐ!&6 oy>  0ɀ: >SS0p=S  C O l  3\+zvr/̏- b zc )I   7sS R z 3pW0 P.ؐ鬧 :MЊ\R7Ie0 0wLsI5˪PȆP͠; fDan ` LT y3P @͏! ˠ <(L k`M  CpCW Z \\4@M @ M)0z )}@ P dbJ02C [k o@͠|dP wP G1 p }PbC0 ːi9\9d qO.! f!m=aJcuiI<np }PBLp P%ƀ3M(ߤVc ^ ^0hFV+$n b^1Nh( n-Nh63>b3րqZ a(vlIh a1ae0Aa`g!>jf⏑uVkj.tv^nm^jn~Q| }^bl֕N>cn꧎ꩮ.Nn뷎빮.Nnǎɮ.Nn׎ A` ༮yU`AwMq` i~CpfЫ~DcNua ` Qw(sNp`͐ ׿(8xHZGP^w[0n/c0>P,r;π JCR9Gʩ4=?J)4/H'J ! J_`[p. P)~ q) }y|pR bRF!pWLT lKM/~t J\9Hsb^pT75ÑpoOp_VsA5 @āXX1oh/1z@@_+o&s!4,05ÕfdO֏_HIA/ó^A4\!„ NLDC ;$YI)UdeJPj$?I$'.dȲk[,a*? ?=SI"28∑\],1 "I%ёU%K:ZIq "GrbN#j萑8uSr AdIjϔ\e ,πm)s/ӈ O(9bV!W6Wlfp"H'bgD !HXuh D2&p`dIX'i{χsfMxr6ڵk e  kf7@(_Y#@)&h9"BpfD(#ikF lI!,h`F9E :7kE0`?g(^@a 0F aFX*# NB #&`(h7ĩxs&hD0Pͅ1tfވ!9)FxJi&R4 A Qs@hf!D&X"e~>fuYh?%ZljhXtiFi᪃;TiZѢ ahEg85C)Dcb9BbfT,V `)f<FEҖ!Ehwqy=.A`(9ERY!bٓXD]}CGe" 9dĭƖ#g _rlQ-]H%i.@`TH䠄VqF_X~-;h#A^ci}%kWbF5tS'>cc/ #OxH f v("X((h`?b(e B'_H! p ,X:H"fhvM|`F3DCpB"hPP?g~,X0y /ЁP`~(18s(jDBo$8E40\`$6h" @'IrB`fPZ[(1 8`-`(%,F`3` ˘'fHa\Aiv[5@/t5f,EROLX klJBZ)[  )`Fd[Aa\pF],Bj4?THE)#4ORy60!'4_qA@L&x%1 > pB\̡mz$O084 XA  ^ 1L@ ]H:&cKB+AZ8VT`peq%:'<3qn:J`ըA-s9!%0cFX0/"BOa p$&{G@"؀',wL5%6#&xۥwoK\40 cJ "4hs"x56@|HN^7|'4B! TA?.JH>i]lq2:sf,c@ JL@CЌf8[@a X6}hrP08>Z0kx;Zة86!F*;L̎ObۂgH2ghL$݂Wl_P8Wu[;6-{p&0epƣ]L$ªR`# 1w ?!: # wn*e(%@5@H60 4\@"blhf{m&_ϝu׮\Xte)c=Ȃ"~iBx75 Uk4 ȼ4۹.=\nQ>pEJ{U惘ycg8+񹨓I]#,,qg@A ԇܑ?KSP \X/PUjw{oknx%ڠc#+7z#h23 icx*6>L iU7 pkA?>C[;t;,;yC@%2$( H kH" $!+.ڀ؄3+I' :̸O2>"`hpjU XlВ"\pi" (ueWύ$&(=] ""=Ot(` P'(&py߅(p&8;P&P^'H"P^ՄHm^E^U(8Ѐ^ !`(x%E&P**!@^m#KT(M !`'!(|8UIX& ep'8Mv\"npHb%N橒-ljb` x0E(Blb%v*f$1>0Z%v10v"4*>4ր1:02b+֥IcA%=mcHyk P* tb@cr0bu@JN&0J"neSaX>YvYge_e_}efLe` hk Hfifjfk$X H> 8kgr.gs> d>xGcOCgzg{g}%HNQ`e|h.hVS7PH@,)d>hhXI1z.hh li%刮?h^i%u \n`va ꭘhc9,kHV"/OІd0C_PĆP`+(jjAk6QphYa_ր[eLeW`g: j#ji(l% h`TEWրj"Xhep5k% ̉#-av}ܢ - hi ghneSnb&Y`n.(GʶF$n (o^I8ibEJo QojpO>dzo W `ou oZ g_"qpVokHX+~ P;E3)RЗJ;"I(VZ7Vm>E!y. <8[%P0„)?9,`OPZЅSP)7cfB$OxH7[,PGHrQ c)F&F#([?0ŤF\ߐfeXua``>ּ[H/q?9HHt^V/qPzkVM ;hb2'p81XfA>0[ L.2UxThFL6qޛCxi"k78g gC XP!-`PdGy(1f@ SDblvAaS:l_hg(O5R "7O­ &pEHX܋X!(&oPj02W%8k8%8ȈP,&*"h?"M(l-( [J,'hQH|{"ÅJ0?(B磌-p35C#o7G"?@I (p+x2M`N?j_ gE .d`0?xHA %8seB/Z4D=JTbG!<6Ȇ %D5DE )BTP ,low2gXT0"Ǧitt  j&ŁE%Ehj<̙J4f7Ҥ-hD ȁj6HZ 7+Z)Px噪0r ǵf5V!JeP"mg' .|8Ə#O|9 J`9˂[-ՄŸВ V]hМ(x0 '$fXOxi.0a $м1]A!\H dĔS"50iEDXcuVZ"Li@,p*hxu 50Xa%cAd̐5@ # `>XL( 5c`32sYwt1 Dq0A 0@cEzI{iC@RqkJґ J,a4ADS!0(E@(ā))! "D3 er)b.!#EՁO"!4N,p(b(5)zɺދEulUL[ XnXx-źQP_dtHF0lA31h1Vd˨~tŅ 8E WH]O28~񼳅z@kwDI5.P I 5 4#~c1R{ٚ-\ Z$@bQvH-o̼U?9 l8`5!3Z]&0:X@WV  & $  -@ OFRʑ fC"~ M` P:Z$F3pU @DjAB X!я2IU,!,PP@YIZ9jpA`B@QX2^Lt-JW(ٚJ@'H `0jF+rp3$E`v8<Avk8RP dUY%̆ X|U¨`!:'HH n00dՐ(`"m،i8Ќg̡JPYHKA$ [5 U40$( 2>cV" ,,Zh]-lfH.P3) TkS' 6A jաr07 #tEDήj@MH1em ]$"Yq"+_>n!h݁!! Al(#BX39#8˵-Vtvg& ?8k T!Ӏ5a tnA`31o;5 6$h1 [hwBM5݌-J_r Z"R*Pj&qD)6- ASBxC&pDl1CC%75!h#NqJAq@ QB}`^14-*;bQ@2dC H C 's\x8EZdJDH 0@CJ LA58G #T3H@dRf@#HA0 hȎԤR !&jV8 H#`3\Aqe\f6`B5h $U 3h8ɥKd("C4E8H$ 圴%0f6e^^Y_Vr`n%gn`6xB)VdV%^\fogjEY9Z`津&LA6HmZ&a"o6gw.gf"T3Lcw(d4j{{rzȧ{ʉz'} %QJLTAz^VI,$rghB%@@A6D8{Bm* $hrTzP(~zU~VnEW(0ΧzzzwRxBB @48@`88`crp4AJ<hT%,\@i&HNHhLX4r)(hA\<X"\-DA` dH@UAj'/GdԌa$B4@d<N4HA`@叜N@** $Ar* L*D)i $6]@5d5<$<Z h'@CQ!HZ_5$A(Lüѫ b *x4~B@ @-"@W$F  \]bhq  , P L2x4DC tȀ),d$?l@ EObWh&T@ؐ٦$@f%@Kv l4@ R ,A44 0d@ @x30-4(0 IH:Z6C TDeг=3$pNHB)95l10|N$@!@ @5`@7FBċ (4kaF[q#2!FQdlR-FhjLÖi& &f:7x>`:A9Dc$FH*& 57J"`,>Ѝ;{ q+O XeZm`N#fhiA& 4 9YbFj!" 5 FćeFE%g)%腤kf0h(9\(T.-Iq񶲥]iB 0h|+." S/0Myz@A +x-iI]nr8>0 !a !R[3.G(`Ak#8pΰFlED;13ХDCU `L 4!8)EZĪ-A4g+-4,pk " !'A APEb0,a#C_dAt MF51A Blx(0F@5LNX I'q0YF FB+hH p DkT:SkbwG   c8!E40f$#] *`[H5TlF?B c!PTE9Xt6P9`QƍhrDzg+F5`:l.ҢHbd38jh3p)gH" y;/53O0(6fXmDyFhXa-fX-xiXY #p0`5JF"i!2PD7ҁDsQv .!!4hA> pF5Agcn'kD!!hmFw4P)5?aR/FC0aj;ep  pL0Q\{"אh@0Rb C&@+w.:#pC4 C0q_a @`zn}5t_C)qH y9 AAr?`c@ , `l\q@ d!@ jj"aA9 CA4)oz64@u`EAG60 \ h a\00\!2xjP@Y4>=C?ڞFrj! @ T-l30wDhh[ցԲыv-]dΖ*`Eµ~~mZuI]'U/i\ )#k)9 |0vINqG9>"pk5TY#;j^?'O Es@:˓u=8;An%'^wukX6mq` ?vx_ƃ|V&?gutV2(yӟWY  ?8 j@bŭy{^kD30FO|?ї~HbЈo>}:/'!sЂr?~?G,_!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,{)= H*\p!  \hpD3j,ItD%:qN H>ܬpNyW@7SO>\cO=ޏ !?l@&V#O8PA ʃ~3y= !C$1;SN5F(p?,q;3;ؿ# VSdިN9@FP7R`HpuC4A 1_AkcXG<228'1 07O .'8=c`:^@ ьoh $"yc5h a;alL r{׋G5臙##_4'LU|7ֱqx $!tOD 4;pH!FyR2 ?X2 x{;0ͣU<\Zǎ܇K?6` wc &$ġ-f}و~1,n؈k:USk8OJrl} ` 0]`=si؈59XG걫wliW0-.F+p(B")2hC Ќd$2 HoMk NzCL ؔ8v @|sȃFzоw|C82$P :;#X ?pvGbuZ9T[tA1|C÷8 4 GBu8L`T wh7H0G8aգH#X@ {/)Ar0vԃaJ!jj1t`KP,̈jgEA څD ; DBX#Ɂ  `Cr$aU l +4 0  =`dH"PG yC ؅;A wt#v78.:p@8( @cBHǍBp`F&  " n  87w \/'tOs6Lffa  @p]!g70R# #p"+ 6 p"oPH*xO@T%Qy+[p'@k R tZPvMU2Lt" ܐH;{/D m| P n*owp~\`0XVaNW1P-   UhԂ0@ipE-@Q3OJSTZpYWEc)1Y@Xf'0 ,Q .[a8vc   +o(0_00{=%1u$Eg*87艠h}B, ~T!WA0,A0c~΀qA`sj>. Uqp'¤0?1 p - pЎDwx3`fd3 aXw Ww`w Y+B &U 8Z|%T7#i%9 u  cpX1fԐ M9Ah|>؉Ǖa bQ~(8b$-" J@ Kxq3 ` B  B `:P % ݠpf'LQq;`m\ 0\0++031᠛[w]5թP ސ") 6)`p/qq8 "B݅ 4 I5jh^`يRʠe9Z%>$ٰ 2zC%l ޠ P@ T]\f߀ pY)@5R[SJ3xXvp]4 kʄ' 0Y%qPwdH  eN:1@  zP W1EP ( 3-j.W9ZZxAfsXPH*U1r=@~5 ~ P+ gz)]Pp QP< Թ 3 7KPpu U1P ᐣ {1 U 5 P F0)Gb8#A. ͡ -` `k ˋ"`  >зë% JF' 4|TXI[yb+f@XKak*#pk%`ҠP!y Ka' 'Y}۷EwMy0l.vp $4Q`XJPMP `LN,S8S@ )('°i l 71 l d@YA@ \L%"\m8@k0`p [ץDLw X@ W"!P @Y `URJ JVPƚU9Z%@ PM bՌnu` |5 # ȐEн1,94r@@~@`\0 ~% R\0KtFw6 !Ne[2Y@@8P0}P^@Z'1w& ɠ:@M U0,!# |f  C" 6;P|_ rJpVr qǁ0 ` %PM"pf{L<   $Fpu  @}֧M* =iMpӍZ7@8I>@߀ $` ! W z87%N'pMC"qPM9@-m`i4ӣb3HpM+Qp- K Aа}@{@b wbAUp0TM0#B̐0#H?\p>u @~ڐv ly OL0HQ>Q A n {6p)0 `1q&(YPP)ѐb`'nA Yݠ[moY P2P P~\pxp$V ; PP: qtv d]{ͅ , 5Pـ@]U ս PY` 0! . @` N 0 pjCL0 / ]P @ CPб#@̐F 00xM ( p #@}L<]O ` ` ^; Cɗa$؏ ~d\p%0 P *@, ۠a @, 2{ C@op PHoq p+rᆺ _P8`@A @CA :0$0|/B8R%C8VH l@@9 `.б(2!D8s`,$!AB\0A$N޾o)24ؠ@L r*!: p:V @t:(aAFZj֭Ow[삳mG& 81Gwrq8\za'|2J)ЙlHNzɨD3M5t uGpykp\O?\-eRruGA4RI'u"YB7Tz4TQGmSN#I5>7bpԁPw̩& d6X; iaGzaGRxRXiZjAa& &pG`aABW揧 4U>hEF?ҁ!ppCx䚊Hr|DqqƱr`!~ =FՀ \PBpCbR.7Pi<X0d` j PqCHNC4Ni@'h  N p-NP"`Ml HJQB\ a.PM%(jft1(rPyzī;q@) X R&bԔf<QjTKJ R*E9I9Fn`bPVCA7(D(@Z=0N;GJVwLJhF%.l 2 ՠ禼ӟ- fb#A ahcXG6 gxb";f,#o8Th ?l& ;7ˆ6D8- `|b vi8S< & ?A#J f 0.ڂ!>P9h-6d$ь:hښ L; Ў #8 )h Ϥ>H}ȣhF+諀 h<*vSAh-`"ɀ"0p44fH)1 `\h7 X!d)9@ (nϴr!`fآPlZԆG$PdhRD2!Li?C(a% 4T=ᄒ7\8p>я~c v:~8PĊ-xC\9n8\ݐ?_B8f:o|F@9p8CpDv[=8f-1}܃ۀ  uÁG=?0`pA%|[;,sF;ooA?@0t8*Qdc\&pHB8{<'g@G>AvCvGLZG?D3{=qϣj) wc D Ybj~G;{ki= ʐL;H5GюnʅB7!}  .DFϙ{l1lPvxXuPu(yhd8"؂,! hx~ȓX# |8Ѐ&|0@vhp[ `ۆ^}xjXzXvXዢciy { ~wBvi))`pkd)ypqh;ֈ?={pwP7bb3H}v}pM||f8 Ƞ@HXxdzCXpB-dw~@X#' Cz(A0f \s8XphHh:b1X}2dwo@>+'Q' ܇v aۇs؂ ~||w،Qjxp pr$[pBuK=$ext@?PEaePFm!w( (9E!@ fo(Ji#z[pO0rЂ[}tM].pʆuȇn(!HȇwhTYWJjx{ x,ilj]ph}o0J(i0M  Ȃu(oNpyDր$A]kPp3AGqqRxtP٢DQ92r@oxM)ޢGh8H؄mppۂz(lNhnfEjvz%0a!xW(|XgЃDP8F)r X8p8r8t3i~shKa)LsDGkyWӇs%pwN@nt;HrO`o؟xTw"p{t4qЇv8,Pq؇q`Xx,)x(8*kl؀Hع ʂ f؇wp8Pw  /p0ȆH0X 3oO-p8hwTsPH@xmniH(Y<&xC=p ܆h@"pP9@Op!QBahGxr` Ή+nTp02[( %x?xt(H x(;$8U^o,(HqLq({-pwhHΚ#5NmVKGk7j*lgk(t?xCmho8>}&(PAxqXx5Y*%.ڟ/PnӸ(>ʆԲpȒ(`ӂ`x|mp"Gנ*p`'0w٪Kz@'2x pdz؂dg&ϫ 4H,#0k嵁ȡma, s&@}xP˪AܔD`I%` yh1! M 8P| kvyo}ЂFH0&{n y8/Ƞq"\2c&G Ho1u™ i Ouh#]b{@:|<|0 PBۇ{}:j7.p|h:{>؀f="0XDl @oȒ-PMpdQDoKLSO0 zX Xz;thԐ#ezMbq|,v `Be^ pha.y ÄƬh,_؆3fs&@Pp ,Hv0?T`L08|8mJL`W І AL"rĨ^sv&a8'6ޖ~(%![;w{r jP7iww@h!yxqzhDzj@{pz ؀&;ix*W8lk,ɂkFdv_ʵ?%}$QvlUlS "xqPq7-hP{(jh Cp_e7`vmlHAYؔlX#aQ($ip :qxt-OȔxw77@o2xo$B[|Vyxxx@nC20,{%xV鉉ppAAH9q@,&qX;$@ox؆fg0xhp3Xvh@&8q7Z@8|v&Wo xEJhocz܂p& Sr8k/zdu&1GAEPΒ/icr9 HS%ۆ >Gupk=rv؂Dw mh,th}tLit2e!\o`m-\TM% eAili>q ~ݲa^;)`$rqin7;lPh9|% f=$}H7H9ˎFF=p byםՀxqvj(>GO⃽ u+9VOZ({# QћgQϜ 2ؐ7 6>trp,OhTEt:~4U47TVZqt_8H 聎>hsGK3;{sN7cNB@7SMAܴF M>@CBrPJ* 1TNpSO?aPIRM=% Tu8Gyn= %u`Y \05uֳE:AhWI@=x@O=$FPRQv[ ԙ=h250QMЌgrq$|3EZܳ $E9sJmtuSO6=P ZyzqtA)`)kO918pvpSr437hi:\k9I[jVn3xqÉM6 1*%P>hѡ!l GpI.r SO51MXjYjoC<`CDAGcOۄN5$mJ*L4$C+TcM;=i5AY 0Z6#Xg4t:aJU8:^W@Pod(O )fP D?| ?1h'ag `M.13 nc9SWj@ fTrP58J=@s,e5 pZ(IRW:@Izp:8D3T޵؂VaNfP}|C T pt x  t 9T5-A?@s#h%|@E|XM +}"|83K5 6\ u x8@" ؆@,L 9c=P_MR.xH5G$l ލ@phAA%ցx>u0Eq(6A8xBN,BYʢI ʺ iG6p'&J#EU7Y:qv%C7lsX# : 7gp?ܡ86Vр0yG6Pf츆*>CS-az7@ E[F9sC0Tpرk 08q nlv LC0'!%A&&(a.?!%0|_5 .8?ݤN`:J81˔xwBLz`̈́"h$ Jx"pbod M t\[ | sءWt1 2AqA7u u6Ђ" L8JYhG{jMAf %8a 3PΞ ACw3A %Z3}JPV/gxP(P ] E-nEظ㄁z@O7 DoT $xcMtRFDyMP\mmD?Vl_`QHH Nzm4,y |8C;A=C@̃3$ *Sԃ'hF̥8XRl ПVEU GID{H VtZi܀ H?aP^ )lyaT_ra<."#6#>"$F$> ;X`6C;8UID@8:`HB$]CO, $b>\!./N!./#11#$VbOT( @Dh0$7u`*8<d݃D2b#?#-3=4B$`3|:|[8M("-1S$"*!C5$T2p9`?JD:<>;Cqj tIʤΣVv"$zY%Z>>9H  9;3-2X@%xC:[Ȝ6%#cF&T#=LNIfn&?<)04@2Px$3 &tg>"D2&2q&qpjf(3 `aq6s"@@:@ :2u@ @I"LwuNs"gZ@4+e }@YN@LID@'M6c~cFx"'{ c8愦.#]Vj]0E@Aب_HBy8hM84)inYg}J>Le~jE"il@@X$m68I!d^C606)5?j 6H V 0T6H-4ܢzd>ᅊ鐚c @4#v@Ā4H)Z(`C3X&lB'<5`-&4@cj)*= 6@tpNE5@./8k򌪨ZVbz5LAv/^(#R(I4DBF2T0,@.\ܥ49z@ >bp+bW lA1&<4A]Fj$r"k-0<>B2hCA6)B%8@zFǂX(E#8C6r ƖkR4 p϶,K+?mm-(3hA>-0`xJdC(dmnmJ&V*hIقB#45-˪V>Th$H\\$*n?nᢆ*g.m~j_T.<.l6A >A6|ll/jABlJP/F鞮}.GT@3\ ʭ.t~/T.'LQkl o?_oP^ vlo*o>لDF6('HA6JÍ@m+w D1lg p+no/n+`!qoAp @4=Fq ?W?CqPq v0ߍj0.T2xCx8X( u~L6@bd`jm:r Y;<X d* V2A,GGomDHC%([Jhg!@$44!s4N0/+8դH &.OuJ`ş(x&,ztK#Salpo |4ZTLp07DC)@u@4yB5TBiCC 6,34;ѮE:#lS5+DA5Bc \U8$dCB@~{^n(,@f>̀"P"DM@P >sim3 ,@T5ܜ2+ɓXʧvyl4v>kh5B?53z_}қ@$PXYV`տA 8T1P@l߿\:2 )L`Ԛ#ؐEh,D 5Bņ/a~8_L4m漩3gA>YSh̙FieA 8=q Ih9 }AJhHACәa;B!)ӟu@jA\i~A2_Ϣmi`OwAZ1~&-_j&Bՙ]d]0L {R 8X``4ZsiRhf ſċ8lC$j >M{c] (gԴ1%L:(8*a jhξ a!*bkpAAn.;0tê$zb0DDj zehftdj˰"kA k l< l 3l (M49%iH%d-pӍ74T\*a E< %`yNIN ~.bF|IOy@#-&RBq3,H@ڱ-eS?m`fB\8%,.EQ' [o$WGb2?aݪZ*fQgs/h ?Jh$1-<"B?PIJ s,,Hh6qB?fB[)ް&f0f#V;Aφ- tޒ-8p)zlA2UTRFfHTWmOh&pAeFLi~ hdh 9!h& *Qvw^rް]8'^. X)*hl!*?p!#E~ %7\'?K-3l$GBp 駟Nj j0L!.`bFO yP>tɢ X+`bJf 4=h^X;ɚ)*۬h́pBaL T,+Y?0Ѹ  87@FN9D\D4ߎ8hnsKtK^ xCBEDca ( pvk@gbS)JX.Ƽ:@r6?i cHRKa>H};Knva~k" '8Vd`B'3w9~6 TEAYl; 0f aH&wkaR<`S2l׉y3>N91:.`ِDZr4#jN8H0݉}(8p qDF,H@ c$Ѐ#]Qyۉąi8lLzҀ-8GX?@hDAB& 8o e7 oC5PNH* RXP !@D) &"ܲJ`cO7Q6dtX Stc P `lC V@U`# !$L-:MrZDLWg=̆3k'T,`?) Xo8~j< dp - *J2P %˰ DqT! E@.  BjG*y.@ӌ12XY$ ͘4hi3|0J  F)Ԉ  f4~1D  B4T٭!B ˃2uQ`7`? Ȑ-cꭻ|BW)6A5@~U3;EPcx`p' #,0cT ҔƮrhIvEPF%`A fP`+P$9 ,f ERɘE8SXCC%"!Q ?(wk$8}PYcrUX#pfha3tv 0_, fTJ4dHpAOK(HiH fݕ$xqa 21J5]XC$njz]@\XO{ Z1[2A9Dӈ\CЌj YXQ_UY409(B͸,i8 a,pYOnrsַW lCe6a x7$13ܦs7j `5\6 :4AS5wx&`A֜NCw$z$!6Q Ea)f: 2ÎRRP$(`3mh pF6 x5!D]K2!d4(tLհEmuha85A77%ɪĂA`C0&! fL.nvP~aiA&VK"P:ꐈPa%6g&a ``, ('.` Ԁ` l& ѸPB &i%  ` x/.<4 |!\"Z W Aa _Z` ` .4@ ߪ^  P@ T& 0Ԡ ZÂ`a )``VvA ~H)8 A JAl% Ơ(` B` cC / c @ )2 V f0Q1x&P͔V[@!@WM W5 3n>2 P`^{Lc"a_\ s!0-h!]L'ΐ2b@ wUT_Ua_>C fG aLev01v@ ̠jJ ~.b07 :" cCUEWKU'*B,efuh27<$u 6h6TV0!FM j Nz'vdhq7-kkEYoTA6xva?6sn!tvoQWGU`Ԧ@ʶx#Z$*) hXr"JF vk]8@J8lky %xx[ qZKx#x{g~z"l|5, G\ &W@!vAm?xU4LnsS=/5m |!B A&@  RS'@ `@,"@xa"Q#t@ ^q-`a!jbk%U l ~@zBT8 lQ>( a}s Yb \ /&.r`` `0`kKě+A u'aBA kB kL"a Hlb!Հn!R"@H$E aA@W?ZA DhH9LjCɜbVp~9^%"B :% (2֘sAO_⺘@I:#$bm5b@a=,  DHB৭C #>@ ` <1 `mHp@ 6aR J"A~A`h%/P;N:AS{ e+A"azZ%a|N'0``N' ZaN N .[@ 5l` !,ݠƃa ij fZ`ր@#hAN@ ` $B@5w怵Ѥ*#W 0V Rc <@1Za9a""A.@4u) *rI@ `<@NǨht V`p{c+%CՊ2A 8 +W VpT#J  0{ R1'7Gs< @'""M Tf6?wǿs:3Ee|~ȥR 8`&9zf ꊳH˳0l/a@">!Prє(d9S@`<>!}آ@4f ⇼y` A  6x.:&Z@D!&g `'=?Ʒ/qFJ"&CWٻ*8` f%TNۡG AQ ~g@A `RBmCq6ߩ bR Gd& %2;">`)A 6Rkqϻ#H  @ 6!)`taA 0>B[!dng'G$it0ZJ'L!ĉ&xDZ"r(*$npё MQnt%#<{"05'6B  yVZ3֭\z 6رdϢ 5QemJzf9' &Q ڛ5@ilȅ `c䁧:6gKU!F5hf!\yFKIĉ"L[7Φ]Ӗ-xk 5ǁDhFPVCJIr\![|TpVAAA~1Zu{ Al=#3+C%&B 0u@(DJ! ,FwRJn` WEV?5Z>1 5jjd eUieHc6ވc|m%\t a3[ŗ_:D3vLligOM(8@";`ҡ=t]Uj5)4sWӥizycâ ZrȍI5J)/@d2Gx}\ MwzU+DH/< dn D3^\2CTTSIL4$L[ 1  >$`M|$_ SlQ[Vq , h5qnI@ ! gdM~HhS>H#HA2Ӛ$ `(kόSByHAhF|'AZ0M%NZf :PQD(,b3@S#10eACM(?ȽMAZІa|uF@0`9pcw# E5Aa &A%jw)F&/P#!3NĀ jK B kTtI x v7Ai$CAdcr2" F 0q͕ہT!.0Y,X>$J­N@a9*5V1::t!-ƫ lb"cL3DV0QruY ^yf.jjxi0F%0҈v8̀ $PP:xB4_V [@OchAFfbzgъ50Dd?{IɃmVKg"zyBteH-M.yCNs-kBÊ5VEhbiKīm75╈΂_}(Sod #M2ZV Fr|Z/VW=R "[0/ڕ A Cr+_/I-M(KGԟ a8س>Ϗo?"@ p .D6@(@R.0UP@23F{(H nTX!(#H%-7 Q\\Cr=q}&(3H50GPG3v1hCHEhˇK}3vD DuP @Zh[ܢC9ytTFf[m@20Z@!cɗ#Oq% 8uFV'ĆneN` 0g]BNS0%7yzx#N` PWRЀf? ׀ <}8xRfs"蒉 ?"[a Zg7H#  ` X61ʘ-8 $ p HqYDo@>k&QgI0sp}rsIq!Gx4-qV#0GPxf p x"` " ̠ 3G2-pQ'#5 cm6C @]X6]ēW@fY Sq8XTH2(#Ϣ аOh3i}Ŗn9],ə @ 45vi$әJ83&0b?RDHN)F\Yɛ1P) Ey^A$ #I#90` Ѐ7Ĺ6Uyiz / )xH$Ȗр o83P_5' 2`<&$P8[ 4301` 5<.&f0&r -:._F!0ТhA0ClP RmQ.˿+g $2=O kSokq0+`-fEP |0F հ fPd+P Vbi* 9PnJw l@ p} Ȼp =ĥ?~Π 8JA03@ V v> + PʧG0 ~-: NPJ  LG02ـ@54Iƈ|˒V a8 ,IƖs?U J;!1@ \ {gPMMs6q PjV@ Հ*4s?`ɥT/r@/J!+& Հ#~+g%N(;  MJ˔Lyt wXY; @`b`, @:j   R8 Ҁ$%2gt  @!?qа @Q@P<0@2P Ԁ,!|]b4 !;|mW \c~:Y SPo А!Xّ@ M;Os $!gPWVEt7>weVP@~X p ;@<I#G ,tIS' y|øz-;/`M!`}zCau=  X  p\ pGAJ@ ΀ 00 @~b}@ @a}#P } q*̱L C0 pfG  0; 2@Zm#|<םm+Mj~&` hذ E紓@P Gll8x .; Z` Q2JC H\\D}ë ,4[&p0 I  FaSwIJF`fp l k\Kse0 ' ?.3`Eq}(^=˃mu=,ej#/⠄1b+[,-Tltf2(q4(*f0f%j JPC8!>8Pd"W1j"X)*"=Jh(h>l0?ab ,W a$ +0 CՀSqݞXf)79ŰZf"pCGdGjW T9™fXW#mzҨ%b2T)f59 P:ލ FX! Պfi/ZcM|S1/L2x`[#дfHEd0<umn3gb-7ꬻ5\Q e;8/UY>_"Opl-R/rB )C 9U:SQpN$GZF!7#ddH콠hN3 th$9<`vJ&Xi]*F\nz{K 0AjLrhH)Sf2=PR$e Ҁ8@΀&p"3>6Ɛ7o;UoVj&Vwu5d<`$tI6Q ?`M,е !0 @IWźtMF3Ѐqdk$и^/EFH%q/N1p( @hb1E{~F$r.zq{4! hhS-`ָ(pke="qxFE<PTf,`0ȖR  x3aM`Q0[4ьPGpL5$@ MVGLHB6(h{"vVĊLh윐Ӥu#J0F?J\.&8 .t-4Tw։ 35Tq,AR4 C pI jqb9"CؓP i@ #߲M`>8B DV)9db9, 2N=bg|5hqȬ8 ā̟͹ S|*i Adp4a\@kF0*GPm"]ME9%E0̘LÃqcFh\8&Nvj'ьJ@xFcdO?D+  Jb!E5TOh3p !T- [/e4BX*Ƈ#D5 HBB)Lqp_X% te0CDԸ n( - *: 'oUD MͲ&+b9 ЌkbG _\7 ldC&M`q`_6Ae@bh5ɷ!4! g\#x'F-EJ1E@D1 U4AXЁ0 s8pFJ0H{  h<"\4̨F6! Z3Jp~alLCRA"j$J0FA\K$dB)j . 0玁$<3]_S伸 @4>PqK$3%jpV0O`o0 'Xөt S kԺ@cb LO  o~)tkCpzԟ~ `"0%d `Bj;I ;R.<(@.X#4 D <7 €A",NzX <@`% .%` `˂"X["#'8-PC &0 (, 1a'X@& 04 $t;2P4d 3#S-x ̂!X ?& K%2Ӎ;&x[-sCP`DAD;| h@l &2 h@B .Dt9 Gdpy%DRtآ@ࡿ `ZO\V2dCE$Xly [dF:JJ?TݐE%\DaԿQi&be PL[tEK%Nl? Dl qTFf[\L DmT[8>G(@Ȁ2ܵ$4҂#HHN\HH&>t) d3ǵnjI,IJ-ـ9e ;08;XUI`1X ]cesaU70}ɥOePpML`P"յ+0G? B Fʙ'7Ѳ؄HXUW7H~W%CpICx (FJp? @޸E?)!`CuPM}JPY@)Udqs6(W+` jhhc`Zg[x:*`kD j@9lR8 1˂_ȯg՟Q%amh` m;f#g8-ϞX&g0`(O!0lP5ZhعC:g XP[i- Xr;cPRji`Y!ȴ`a JlYBԠ_%d]h]8PSm$i>a0(,hgu[&@ڞh3xj(.p,1*%_E= SC0(X 9&8+p;`TAa(j(y*gD_eP`P]p`ʉ+-@唄lpA % Exl`2fD(pH10Pe kbş^dPg>R&e?0 <0H*.-Q삀(x[`;)F lH2ۑ^2͂`f$8ȆOXsEPX`xVt4 &O'XPD9& 8 HE0dP5 `H_HGQ` #khp:G15fh(hX䰅8Hd&_."WONfĆblUE&賤C]e\(h Q.X $(@ Pf̱ ;.aЀ8ІFPg 1h` H iXǐ]&H Д18h0.Վ#.A+i0(;!i7܀(eFN(i# DiB;;+)T'5MDM F07o6Seiрj.e6`FgZ!b kf8jVu!HXtEot^{tkG`X"U6l`1pv-u%G6b8`pRQ]gQ^Z_pjCA@A ,8Y)b΍j7 j8 ?HxPj8*sr 47R&Q0MUDx|_hl7ngt>|tG"XaI87~Vx2MhEPmyr aF6Fg٠w$85;8Dx8u-heXͯ7 hjri*uPDIqw|OEL&M9'r A?ٯ&;8_<$@C905(r$ɒ&!*ddB!Hk& $(کř!I5M D- 4va-ӠzrU% jQYre28kvD@CÂ?0)QZJ86d EDA{9fͤPX̘lPOQ!i0YA!|6ΟC7VzqbWGGfXBJL9pСn&~sBeIAM3N,PD 5sTE~A sa7Z3DMWIqUD5[l BT6TCx$X%t$9Y%3DaL5PXB0#gEZkXWtDM4`I5Psp!$[-gzZbt!b HGEgH:w!TL2]E cr@B ``J  eKH(@%8Ƞ6̐ciFk\z4?`сU $4yINܟZW]7]Jl1G#CX)eH.Q 4.3,tPHccbӾ5˜ (!ym>QQاk3I(3O~R v@md&) ` Ɠq Gh4< MX&?XZx 1f HlP,`'`f\yƟ pAF$21$!`B3*Aŀ 02T($$8$=> G_I ?BC %JPD1񨩍Ͱ.WM" `s4a "SAֱ$$C1ʟBz\OR. `JAdHQ1ԩYUy P `H]*Y+Up LLO[S EPjX?ā `h3Huru+R7ƪdtj#d j$H٫V?)eUdTAT{s kiWV|Jj{`Gmfڙak[V ʀl> ׵-sK]|9ry[ -{7}1J/80z%L/C8], aP4l1 8"1K,a p3h(&1kl9y4J,ɱ92l#1A\ R2lhZB/9-gz4 5wm.܀(9yih8( @"qY$8 d .TϚ%t4 rS?Oh6kxz3e"̀P`Dh|~Mfu_Uq@sKrHH6Q[BYkxƾon0E?@`,A$iB1oԵ.\啝Htnf͢gsD<DH'y.ejZ ^jrGMjd6"ˢg۞*BI4PA>?*=x_y֋^Y|ӣ 5{z}tO ~NA&xgDmiY4p, ȀA$耬1Ƣ&,9h&әA\$?K L t uZ(,ATs@ * @v PX,AB  *?!, ZZA.|` $ HߍџAA@Ou4\58&}853H?@_P|Y541$Jb%̹Eaq h*P I@-@)R0 3p5D1 LR#XC6`6_0Fh.@ 5 |9F#A|HB3L5L-AP\4Y5T]&5D. 4 76A\,6\C``C6d6`dT@$h$"Z4Q `!$/U)X- |#4/B{4@0,=N!b9 O.CPJ#5=|R0l2-2D58$F.44-1NMˌc0nA5@D(A3DQ̪@---,F+^hXn@* >Q`VD$@d#Dkl.yExn\MT< A)4T 4`,ښ&3@.*́3H\e/cl00pj$G:Jښm֭3onK@(,4A͙)DfCA5\@d5Clx0i#$sp ),14P(K cΚr pNI-4Bx/@3(sqKx1"o1AϱpW._ #0]{\}I$$O2@%h9{A p n*2I@)@CquL<-Z]I P?@ x(sSi33oJRs5m6qҫ6C 3:HH@6.N Wl3NQ@TB5ƪJEL M($t84X+:4A0@+0w!P'ho&Du\@,C54EƢ40H@XAL3&4SN~c+6 u~$&&mB\3BA3&{uE ,0C(4nD#$9(43;>??6PcHjL [].P6X(AS@ LA%<AX`B GD A62 t@/~*' 5~+؇@\ 34!8gE0L7ZM3l\2}xOA5ګUHvp7ʸ--jX0Ę4hհU3Ȇ (Hάaf A)Ns XXDl3=^횖[~AI$hת5;KG0Q6{ZeV[vlXcɖ5{gU-_:m\(_ZmAÉ"M8QDZ}0褉"^j -AbDҺ=MqIEa?(P鐖<9a}d`#(d&I\dᄒ'0&,ѤI'RB Nȫ\F˜H ӕbC b^;Bh-䊋  x" BЊvpBkl!+4 U\]lq3_zik?hڀ"+ J񺴈<$xH%{#@G3IHx:ˊ/k$)6QNk&~D6K3)$MFp= Ӂ3*Ҹ*_\uݵO`yғ_WMV`-VX) \>dr=w,_vYtuU+dy2Ƭ]ev &Ѐ 0Ȣ_xoކ~%YQiBʊ2EU^]&Jb,:~97X碍>'Y!FRΊYȣhD"i>gC ;F" Ǿ^.8h`rhrGKƸao/:^4χ/Oz@|]m5Kt AbcKijx!/KTf}^FDy&CY.–gIpwJh 1aB?!5! y$W0i@ba2̚a3oJӠlā4 ,_Af x"ƕA @`@e3rvT:?D+ 040,* vDf@()d!d`!iՒZÂh%ޑYM􃬢،iLaAs!X.a8b8F2ÌِC:)|n:"1 5g*w*36$YS|IRdQ@Ӏ1 6 @SJ3!́ɐ5[@5u>|qGRa7mͮhԀ3y 3h@odRIn6"Ap3+TD Mw JO E`ДXNg>|?9QkfE%9s ׈ t001HB$ z~`,tq Idq/A Q0BiX^df?`)%#E)8(?60&0B'$qh(L|"!MO V8'! ϾAw`4> c@!=Td`Ӏ#(p#qנ4N=|XdեuY!l ?rJıX M8*A0aNX=CBCQ(B iPc 'haLõ¶X0NZp0 بD2 V`w"l f[(F&̚r , -J0lD;hDbթkТ ><?DfP0eXc?h8eD),Xb\2P7,h@1<8~Q `A3 2Vo)HXY8 X%F)S' YKBgQ4q[ hW&zp\O?A K#(A*0 $l] Q 'M(cp@ "! OHb t+ 5J! &8d1T oneDv@ND䀠.@ U<FTD!J ePV+@k@ ( z )Bp*` $X !1ԕ1`84,}%y0nVo%O\c!Ƞ)`X@ ]- R!_mJ2@bU"2/`\a !`b31ZıtcG3M״MC"Aղ@ed  G|`tF`Q>Q%` @ATAw|HsjETM" "e BA(A !  r`H V"a4@quٜ"@IARrma]eh6 @h  Tp)Z8FA4`0 x*; x/7L%ƹx,jG4+B lG &C&/@͡2 !\/ ΔABjٜZ`Ye Ө!?2!zl H o_N@*>4qw:` yG7 4,8@@0vm "̸o4@7,>7#cN@T"zCZ0@ggyvpt@B"t`@` @}_\>`D 'u੣8<``a `@J\@@:e*k6 J@Aހ=`a #~ (lg wG;I~ 6aFUAZZD Bj!  Pvcn | R!8AH| !j%T2"B  `܋ )Ja8`~ N&1͈~! ✯F0}78۷̢aZA@ n R#(BCTè@˟3Hu`  N/!Ll+: z`#8 $*!κ=@Ae> P@ԓ>, X#x{!Ճ#T;y|w%>Uլ >}bB$! ➦?| D>! :8 aN0f!#(s`?:J!!|c J 2"0&70Zr* (~0:Ka :4,maF@%( Na HA>tpPP~Z4H(p":U(ɡO*Ң -Ƥ0-88I>A2CH*]ʴӧPJvp"ЁhDyU (~pmAx+T!BZ($UV4E[VrmbСڸxg5a:00kA'zfs`uݯHީ v, `77_ v,*JӫwzM3弞wf(&i%ـyE}%8}L9XUhf_EaR"Ea#*u8bAhti`rITJ)DilTx`6#\v` HADPb^Wim-ix0@R 4F# $喆.E狉6裐Nu,M4lWhpꨤ(!B 10ojHc_J뭸z$j+戙kO͊8u.+SlB^liJmmBhڨ(B.j [ڊԸ>/!7p{',1KCܰ=.llnx/˱n'˰s8 <-9W溜kpt'ÜζMP6 4D/}\[&Hs^GrvD"l6.[&}s^6لWtM2ރCta]yݒ,{w.a֒í驫N;҆}cӽ{G NcJ;؉vn<ޖC}3N|I_~ck.>܏; >@/3#_ۇ}g|^mt+{U_?y֗ |SI>oy ?덎0xmv3^A.pK!f(tG*Oe(~k(<=jqS7'GJsq#ŕC:H HF&K+4E0FR}$"A" ~]ĴRh)$b2OK^MgѴdg6:~-90]0<'{(K1v$4(ܹL'+>ڱ|f99wBqb;MhxdBr>O|p$=Y1 󣒣%ЧVvj|G9)Qsz-Bvix\NzҞ-d<ȓ7^W:p:i7ȃaup(6ǀ:%C4O<$dc.4׬7p='l=s7ш.V"H>;쓏J% ۠KM=L@88A6r^#a" qvBPL=B( |e7$1@#u;pjm q ƒkD!, p悬23up95 4]As~MQ  2|rʂKmhyR/ @c<M04bl;ESAMP#(҈"[@l 4|#|ꀒ" xH @IzF ̰s0|$س1(3\Fs\@~J@рHa5ڡ$P0HHu< B [)H@?4oNB1) 4( `(يG s(bx"}KR1{2 G(x9 ^+AJ~I{#)=N#<||:h@ X>>@|4E3l  [PLR]+z@E[pR pq7 Lр* (TbNZb0+LM p`-VgAbُ\ iu9 @%P 0p.͙#IT(Zp9cX1  0'>i)W/Ӑ  jNcYjm١%!jA&u(ڗ\0ТZJCC pi HbJzn א ڀ @XT%&Պ9Sy:X [0,ay-Ω|*s7AqDRpjPa瀋cjЈPV|BJ@ W@o ISYJʪ]_I|:hl󠫼JڜX&+*JsP [ `< 0 WhP | 0!0c:W4\g @` + N7AhG@s zzo"B %P  %_([[y70/+Pp}q'U?%=ʕ2 z|MkZl ri:w׵_{7  J SEPqP8s΀ 3!`rA.P100QvV۠@`@ FH 6 ?\N `Tgu @ U p Y0@C@`P"Qspd`Kq'{A @7:Yzw[M;{5w{rx  {t*6 3' 6!L+ x +REpJ~| .а q H'!ޠKqt\0s'  8 1!o@`5@ᙯ/L10@ÒV9|;Ǡ 0G p` Ƞ V"\ɜ-.vp8pP picN/YbZԀ㍛",FPfϘ1>UTU^ŚU* ~Mb_EZ 6u1f p^i& V*z)g0)E5UUW;pi$cCZنXy AV6X=/0zGuQ|7 ZkT 2'|QuGzI"Kleݪpšrؙ'}'n(]+*tܱ|qǜj@ 'xUp Q٦ni"d*8n+"X@oƹ6x@ H ŜFzR 9h 8 NMjj&Ӄ (+ xT^E˂enmAΊo.i`U(4 "0:O%("(PBn18toI]\opo.f x‰(8wTA!"N(M%|A8Рq '" mN\v~xagq٧ |=|d7#=9`zJ3Á#pZ yQ1@3q|#P4[`?Ǐo$Z A 0iHҖmݘ<1 [a}<'@( P$F0G751+A=aEAj6ɍ!5x#<|p.lcXPҁshYoa@a:Iq1l+9ꡏeԓ/o~{".9#kܜ+BA5b r$#~eg\PYEbÑEn4@tXXqcT$(8ѱ RȆ6J;f\[q,Xl5"DK*0BLcjgJ>axb3φ }s*#FD{4݅w&`O! |@q?BVePqb(g G=m&-o`1ؙqcz*A dU18pcMI ?ޟxG՛uD"m`x fb_֑!F< Sk{G6 npo(Xm(9"3)q ؀lpK#%pqQI%hGI?:zhp+s# *uu]u XF؆phzhpo6qoxh:r!oz h~PoqfPІy?;37 @up up? nƀ|xh<Pwpv:w!0s;&wMj؇/CpxHHj1 ЀCsntwp$s Lnꫛc!+(</tt 8sv`Ăm(Lt;'wX NP|PD'td:KJ)P%:@H#`$6hGx*Yk"`,+)tc xZx\-Hp@lTVpr o=%h +| h&tL rЇS,H+'(P59w@zX ytȂ5Q X&{Ja%L0wn.0 njf؇Q 8%BRLʆ{VCI,t ؂up`iUp/⌕xX Rpy$ wκ,lmi>dxU*tyA3YxqĄO0]{ XYzxިhwЇmp xd(Ȏ:s2t <-jPian@hTjnQzx "$TȉȇlkHlXҪ 8nȇvhV-R hQ mp܆9 [Cz=PsB(w %zCH{'ɀH$ʙK| P@BP}H!LLx;%*ڽ 8KeH؂@\ hIXЇxXc@"z ҵP-R~oUVVVUeU]eA,j&8~Їw@!(f=}fH؆& f wȇOPt~u,wxgxqphoHPDXJjh&)svPނH@ Yl|@,r`"v⾡?A@ 'tv؂Xx".'UL+s}Ն.5RVzt(sq?iE 9zqs`sNkmn`8q { x2Q(LKzPNO6.U]Rnf..ܽݍeZvjeJl({ )oxv"q{`3k x?^\njnoxny XXцl(yLb4? Xˆ lhul=8] ?r.5Zx2t= t8sӓ 4RSq:uP M:gp9s8F.HD^u@2cw?DaH5*.CO"wx"ć(0>(B2D̝{c u]Upj.1'R3wllW|s9_-CUx#X/tXoƆp]up,xt#eu;q|Hnuv&uy޾ m~phs({>p{(!h>13r ~f (dλH7Xer/E𴺒p-Ѧ'9wi)|Ioif0$n9`x5&A@X  Pz W(Pz8}h7Ϟ9, 1R.;4c\ 6>v0PKwdF¿ 0`P "@O(qA.# Eq6̳ =6FDT64S+Ac}hOΰ]43NY4_pUJꡎtCmv#Ё:α|cPǐb٣8nx`+9qtzk8@1}! ĺ%xCy8;#=5x@#zkF.0g >*eRDsC:H EC`=!Hnd<졏)3pͣ:x [a7pFu L>q`)԰>{$d܁s]QG?{ZAэCD2yڸG=H|pG:TN K q-xܣrbJ:%=h !&pd`=ғ#pị/hr_!m0AW@3{xdAX>Ъm6a@ vw8VʓG;@iQupAı 9@5u8h#HH`cF+n8݀QڎsDj Xxh0qPF )T5;AL Qњl %C91r@(36> 88XpY@Qg K::aBroü5<*$_vSa  @pܶ8ã@` 5lXDT84~(3UwcH:!(lp1'P8XAC:Qfq >!@W`\a< 5>B\p߰F@(xqp{`;H(JprsG? +h8bL2`ƽ6nž/{R3loFFj4@8b ܸEE7 jȁ6v*]n4 䡎c_873(o<0"GPVX 9oH We ՟N$`^;@P,@n<lZ@nu sEuiCuQ@@9w&7X@ >v tRKL UJ@z Rr$!p@Sˈ<<(:׿XhߺVP]mDU]A<\ @ eE\Trb l fݖ`x|`^` `Ҭ[l` ~]F$7;du$ t> M0:L@2<0YG8h@5C<8X%r@5)1=.h."06 _01#2&%@78l HdC=Rh A9`U5؀<1:( :€BX2c/<#>ϙ ?#@p8_7tC7<\;LCQhC8CP:];`Qóȃ7@. "֣ᩤK*0L$M2b,&LdU4$7;DB u@$O$.$#dJUJL^Vn%Wn@8AC9Hx@!q;6 C"tC9m!r%/Ο_fV(;F b.=V@ @ x7E Ѐ !V`@dF @!%cJĭf` @ k֦m"b,^b^bVfJ&omj g` q&r.'s6sr/=*t#08n卟V8x[hw'DmctE%"9@]=JM`u>bO4{##4C9hLUBpC:!(V5#M,$g>hI48Cb d C4,{NvYKExC8(/j@9kUmf>V&!>Tf d>hC !G0C_=؂V#8"EW0z"jeA:#N8H~Uq8?QWAlqM>4 r2>exG *{Xv_7āi7@5C<<=,3=A$'C?|NT'VC[7`nBG}@i0??h ܗDCtgGX}=`(8yAXb |dC-7ÁLT!vg_w_#Bxqoj0\:<&`C;lDP{):;x+H(8-.nt5^8h (B#( X8C;L $B"tc`!4&\C:C<`QD=ă7?|;8(a"G>10M6Ā` A35T 5[[߭LB3$7pD<(58PB"Ph$3HC8nC44%dN40l$%p( CAf 4B%H4Å`Bn6L7%5ó|8*a(pBC2hk4AC2>XC d4Aowx:U:w(?8%!%C iz8C-\g 6.@^ucЀ6:A%0P';tA_#D9?,97<@V@7(489#6|.K˺7ykrw7D'­$$@yO T!Fd8_0+q"tE _YC߇ xW܍ <@߆d%^ضϝ& ^;#aKPz u o@y( C mY7^}XຄN}to޴ P/57lƈ bNgeFX{H a( wF v㈥c4̀bHC|IŇ1$O z ! dzxX y٦-t.j-7?7s@BG9r`qQ'Wa-|iv|ɇ~$GuPzǛl{H?U,Y#lT 'Xq"I4qJ /aA}ZHF$%HY'Ǒ2*ݹҡ &S@kAJ8`ű=k]]VE=.k^Ll2wIh|ahZr@ oޑ{7 ޥ|p[@ypIn96!cy-glF2(mIm~)!]I@Awe@pbt'|ǝIFV½x1#ߥ2޸(,b'Apܩ'}ys!Tʕ>fxSv0&2@}d ֎@YmEY >G5EIPyy$#28D)%qvPX&7wsC.qa b+r; )J1͠㨈`V6am5 g?Oj ".×cu܃NqD O/]V0QAyR_?Pyؔ$H>Gv<!@AoSa}: =DE/  *8G:€HCx$6K!>1hwIvҐ8fLA{ 6a&Q!ɐ<CWL-|1Xa(Eɐp̹@ QME*3A=A"@.EOaѴ rf8@DXD gE: o``JPm!4PANa aODit8!yxZ@l*@K΁~!f~kdiΪ 4F  B) 3 r\EP<3 0e'83` D8/( 4@ 4l)Bf@ `%:@ B (s<dz 5FZ`: `0m"6= //Fe3v$t3S<ɳ;k^8EF`BmO86ASk6`3O2Z g4,3"x S/F;w34 igj"(n1uH;^""`* 6@J #`4(`ר8K);vԋ2*"*zb("M/洠oJ!1P 6/.5&tQOO *LH+(u"40P%I9N-ULQ4A" V'AB#;0՗XIX%sYYYZZZeS`[5\u\ցa \\U2]u^^[UY5R__D !0)`5^6b_%bu_Y)b9cT@NA`<\!ve]Hcee^0[ucg6gVt`ޡb@tvY[6iWVߘi 'ijݕN@́DҁVIul%j6gfmmU* .Nni[a}oevbZWpL@l1#be+_5&w՗Lo2\6s7rp3 ` S's'wvui 3 7[mqL2A vseSsDSv mA@ vizwIUI&`{/Ԥs/y%\5tGi14@ yZ Pf^D (o{#uu: p`6lmv\ Z tA Fb_ 8O]@h7uZ` >mV3"Cc] U0!0a t ywoYhw}w)bJ u׋T%} xĚ`f %j~.wCZ9@8όX؋6L[YE؏Xcc^n`$y5`T N!2V>9YZ]Wu+KWc9xj7, ڎ9ED@a ma mNԂ'6@eH0Z _,)BXNJ`nӠcד[J`z36DD.`U(CEzGR?` `lZA4"Zvou֘ C/%(`>BDzFD>ĚD@/ZYȫpXE pft >t*"z {yBy鬿z5{"bL {7֚=ۗ@Ě!:I  !µ# "Zoø!"@ Av"@.ؗJ@ h\V "0`)@ RyR4>!\f%P0A`y`a `A` ™ %aai1 A<@7sI  NX  @l?@`#`!^`H\Bi2oAaT9 !@+" 'iYY P!'b`< D`-`-"B &`)"*A35c9!6I Jʲ@A' 8=bC ͪ9߂9RC>6 # 3$?| %JbTa ZBL <;8MQ@g PSr QR>4J1Y@aG%hs&4H8(ce95gkF$ "E=5 V}vhCK)1[MB0K%EsK h Υ$)yK|?ãa>˛?>}w ~ Mi𒂏MPA%.QC)،@F5THS HD$.,PD5MH]q6=c[ -JD0 nHRip0(q$…qUWE"kxE]n5h&{ni՜ҁh$qК@A<~Ӕ'|/QYXsJYlBR0\'p.9E6$ ,?,E1k+(|ݗ?XK0C.詁 xlV3ő$1̠5@'Чy/ +PM7:U#?lь4B ,LRkE͔XC嗷7\u݅&_k~P 0ҩ@t@Ӈ*IKKL 41)Dl=jpaD`sE15A塚2n w"ׇk~ A3`4l}jgf-N4Y-6pD5` >Bs04S"pL 5d{6`c$s_U:x-{l&K!0q# "+J 3\L ٌ;8l&H;"xW}a]*F0@XÄ5 p`|Hrm$=9oȢ ,椃mqa3!9hlECitH5M#vLXh#(aJ`!IbCƼ*^DYz6"I׽,;zd>lpF5;kPCTl<&@N`.LTc Pۼ,Pr<ڊEaX6, Ba)j BVj|B,P f` b-I"#``f>  D& 8psIycd,42a[]072̑f#HDi@ 0`&(KZPWP&'0VЍ)K9ʔ4n(e[EKA]w.T,2A# 8M^fCZQ0=AN4jL_;J"6,@N YgbNQx_ԘK#zv~.gTS G94̟[ (I i ,iТJh \M4T/%6$1hhB;VYk_ ;B57,Yt,HcȽ5 P 3O.P`LZ _{# (Ҡ OYp m Q 1KU kQbD``~P >K015 : q p wU2xzUZWKG?c[!y,SpLpY/o|-j?P]0G[|,nc x2p^ ̡(qjqsC!PpM@~0p-|P2j0=s` &NpR@ZkDd@/Cp1 q7wI0 w2ȋwRpYSp p SVȐ*5zaXOzRz aԤ!A YWJё'] :qI1i= BKsbɔM20|.kSIB6_9ZL4UGZLi0'[ d9ِybtT#2[=wᘿ2pR '-)7)oԘZFQҚ'Q8}P (7ɛ雿 0M װ P )IM` (X)b)IiD @ " %tmsi9P a&jU96[*JdVgYbJ |Sqӡ@*U''  $J ư! +q D@'O ɐ uIƣ<&Q 0?{ ZyV p"R `uTřeJ!Tr@ 4>-z 9R` |@U}_s 9W!? ij96A !\\Gx$Fp?0 M`szT[w o0 c] da*ʩYJZu2-4@ 7$6)0J*ZҀ z S:, y[Щ+0D)/k [2"#r)R'+P z bjq(p {/+W~ 9 70 [ZAT:+kn-zOi ൚ip^R[z04 @p0 X `-Zhdk&쑥% [> '5'0k[@ q &unUpڀW 0ƀ̩is4& Y`+ui5jҼyKo4˹ ⩵0+[|Њ :#`}q}I D~]ѶoW~P;0?0羪z^0A!qo /!RMc|0)3,N`*P0o /2"o*RP%s0ЅV 53qLns$N`8OP 0+>NJ p<.5# soB>jp~~Z p52-Y0] APɣ2Q@jB,F36 P[o !@ pP3n *M а; K3 Hp 2M' s az hc;ͭ0$.110` P 00gH` 0 Ƹ[ } vl2` @ 'DX Ѷ#P ]9]ϒ' 2]6 'H4 ` pְ  hWm%7p( [pb4f p;ڀ n3F{Ӱ}v ׀ Ӱ$ Fq};S `) [!#pՐ w( [p=| 0fM` .+C@ @ s<` k܈ o -`K ~`n L$P0`fqakѰqk@=.!I\ ~I F⻙[!M 6e D0)]|` pk$ k>@I}P F(0MPuj@Ku s@nC?Zy^ 'sPI0dK0[@ P no`x  nP2 Nb ] !no @d^2NF8n@:`0}tx v' k`~--p^L - Ǽб - Mi۸mP' Հ LPOq88*& :L[P  ` LДU8%pi >n,5`%0/1j P0 LpL~@# LNN2  nP026ߟ HP{y@ s )r<0 p 0YP+& @M8 Q Y> fE3, P5@W~r#|R\5%[0 @a`  l_fpjwg=@pͰ D.~ F@ ڠ =Zpԕ- JԹ[;S Ai 0G &%`0+E,E.L,.Q`&y .a"w kpubHа AK  WM&P-@  L!~1 qg8 M?4LJr i@X̅E TU"XJ2f7׌ql[tIW/1XL!*v" BABu"if$l8ڵdߣT9PЇ p@)!g,/xxT45!6P̚Clɦ9j6?)4  2=;uٵo8*hͲ@"ZҶg[>àX#"ph#J&8! i8* #(qF Ҁ f1 (eHh?E&X XgX ?i8`Gdk$`f:h #~` ]bFni"9ᨤjhd\:n4o*RB*k `GHa.:J,& l '(g"h&l4AK# m: H0'``Jd06R`*lI;(;t]vh+/;flfl jO?08jebD LkTC)Bl(/c:|F Ɏ`f#DVїkiƕxfw \WTƍ{e5QeˏB2L)Bad&lJTyƌys™fh6OzxЬZm,hF&cR0 M9Pc'Eh&ao `p]E# bIMh!lqf Q ha gdI(gBtwzׅW^ IL6M<{ FXa xcx~c# *GXT(4 El6Ùx# |Ez~PH`UHX\Lb5q[C"_Nzh6 d@o!3h0#w,ti`#Ҁ,mM`5ERعyK  $'лy0}KذäobͨX"G ]8R#eUA`3t, P@3$p&4l¨yɅR &ʤ^3xBCض'y*Xъ#xAi8/-Q6 ;#h,S#J6bb814j0 Sja>{ド- ]#'(%,܂;Ak-CcXrh X$7( (D@-Q : 1;t.hkHCXPA|FHB'؀!xc)0 Ox(uـ:s PPf88ZR| _r[Kgxf h,hRx!x+-xG R%(iPZ8H`h'? 89H-FUH&pґ;x@59i;kFHr lDRIPd8 Z%F7+7?AF,E:d h?t2K˽| reӾ-E؀1h Ѩ䀎zHpFh ͈),M$ͳ;KM8`*ߑͦtMcM:|;MKNu NҼN+K; "Y*tG˘;1NԢ?W NNvK("S?S@ M| TB-TC=TDMTEA]TG}THTImTJTLTMIMNTP UQU5R=UTMUU]KV}3PX9;TWU9mD U%UaMU#т7`SS)e}FOהY-U/}vӕM IHPUZӋ;1"ZHU*kWmZZ':!%8aꤲZS[uȁX >h`%߄& 05 V(v`G(axa;ea:P`~v ##VTM('Ef&jRD}`×'`0Ё8kFzPkkh!Xw<-hi@Ox(V $HADl dŨh jg O`d8%8Ujp@a׉q( s PA`Ђң VhhNnIX0od`P[jxRe|,Ѕj`ـ8P.,FKao5>`>΁(hq 0fXm=),lkmNv(Zܟ+P I 04"GB)a"*Kg& l\M̨uM `kE>EX\eRrhh`M7(t<%ihңGR-R\݀8 YR>P 8SivA)Xh qf0ـaY #w,P lpXF vNlj$G % `rݪ3aohhq='-_2_i j( ltsP;x׎pZ%u%xu.(D 7uu[jf&u- UV/x j Agq[o `hx;uЂHE$)TheHg싩Yz?;'9hakIJL*rhYy, t X t)'!(=xuF؂F3@0Cf iHSc( Mܒ_\XgP!X„wH$Z6~vc0 glOijl7U폧3؀?Hm(k46w>hZހ0Ca࿂/dqfkrѩd̒A8`Ҭf$-@!˖.r՜msFda;ΦUti5G v6 `ʶA˝2]6MUNM4PTPJF :t(8fR(7p&&¡keX;tbKN :xuNңx5֮_78l:KWѸY ĭsa {(l1Q90iHțJ#Rb ݊Т3iI]Cm l$4`S8|Ŝi0AM7dK?5A)MЃƐA!( $QЄ0@AWTXeAiyq5E]x]cvXjNpdVÌGL[` 8цWboV%O٦o xH#pw\rZtq@uA)PCTB BDC*DCJ`B 0x PBXAȐ\E-0b`Z`5 €;D#h"&l2"Jl`F9@,-\! P@ #:@]1 sE@cXf'Oif-"1ah2}rQ6wS \%fMNBFNR6Eb Mp I(B`5 [!p h8`-*CH,Hd!DL%jmZbpj@ 40 WV!B4a G"ΰ,Tl`F3e\C\)rD mS`fV]sD@]D0kHC\9B 3:k3~=Ȇ6:*i@Qqƛĉd?1fDO`#a^`Bl5\lI * %qB4jTR>'4q hDb4Q4TEkT lTB R>4֠$P˿h@s4[ a!Xl4‹5PA $k:&Au^;11pa%Nrdž,t7!JV" %8f'U`. @ a `&?Pl^N Ò0 QL0 N[x0-!V` !"d \"i$<0â[2*c `؂z` Q2K`,0 $L(p V:1'aNn ``@Є'%XPMiO_j=ɝ;O)ـhl1 F7sg7~[~Ki]j>c%w&@p_`lZ }cI4y >, nppklEWlzFnr;ոoSR[\=섄Q;K0g,Mt=z;my*#>_<x A$ i <;σ>,,A,~AE>=l@Є&ph?WLc@C?_Ζ#oD>ws9Yǔ?WD3@@`' O^_ ! qSe8IB5H4P'@$\.D9 p@D%@% RD kLJN- 'X2H!Q45 JAA(`3hB0`\) A`@ l`, '`3@\_2ԜSLMa!. $5W"vQNOa Ubc(46B>` *A!s A x)PC2!b1Kd 3A Pb*1lb'_"212߲5[U-zcQTl@-),8CZE@3z`%*֠dip7ܣL@9NZ5C[LqBBȠL \Ap"GLlMDJtdUܻCǥd_?8@DB.@\uD \9q$CX$LW}@E@ 4O%@Jc?r^3D@cFcv%1$̀] <8$H!h |O] !l4͉]:h HH$VL8B$(heO9B @0B`V#\"KLT'xB(LE<#<褌]2Dg8h Lxxb2&B06~&g( f'4@}ާ~ A)6CᆞB6tFR ++m4A7m @3 0MT$$s.W04ǫ4ϫh@85(Wgh5D 8\Pg'33n:,MAoh>?@,C3LPmh6DDO4Z٤PFWrGWN>H+N6H4 |tLՠA5ܺxl-R[S#ɼ3luؙFQ! H(!Wwx5[ǵ:]K] ^ϳ^3_s?k``1zlAKl>48lg4%cǜftl8@@.dT,8Krj[0244(T5B%$TAn Gos S4T- r(oBBBx%)A1(@BBB[{77ysI~='zs{;{t||D.v~CC3w_v- H+EB,@! 窅_δ,KB4B(H340mx7K t?s3j C$ \S\5j7ؗ 6A.ACGve?ܙ66_v^1$fAX:ޱ塷尃a \)y@0+5 T/|U໥$)(ml8:WҀ0uwwȕGwD_9y{CXM`ч0vd!d8FCa@QSDm0h#X3@ ;촛9*8<{i@ W4@H0DAH `D |R'(0=0.XM5,v ؂4^ 0[|CuB0A@A?@ۼ3XA-D48A `!KW>G@N K.(5YOc}U0r h(|k8thf̘/7$=9 D|MDGRLRhڳCIh9j!<C Qăá˜af҆X:)^`1c 11C G, !˞͙ɡiXA4c\N@$ 2M4Z >Є1!o(|$=*i}Hhxywy}zٷw~|ח_Go]VMi[$ Bhohy%ih CRZq!ҺF.P9|ΑEfJ.gxˤK3جi!GR,?L2 3͌fHB 8"ׄ[hshAadx;E&TĠIsF`*=ޘfK4Ͼ\uݕ^}g9Yg /6A`YO" !cP ċ` fKH?R٠=iuG`+>aZ AnĘe`QD8X&QetE% pI*E .[|Λ` `fh9 f'>`cхq ,D),g2KaJfN'RY(ZH(A[0p-|P=_D $= w+ٯUB; 2q>-s:G&g|'%\gGOw\j0mG]͚1p'<ӥ6|='>M<"2'yXE+^Yb˲+F@iTF7&nA27GRpk# YHCYQz渽 $>0!!x IO~_9bᑢ<fi4##6>Ue'-;=A vT gT C Kg>"7 @ p0"% YNsDzx[<ݙN{ `0q,j d& P*L:Pև.\R "!B 6E< |;ŇT (B(4X OȀ!+X D OEb2U30/SChHS'OS*nJnI D~`gl9UcIeOM:`8TAjʶ2[MNX`1`[XC ")飁ZjP; h{"[aqj7Dlb&q x6?@6H<~6kox q@ gIqfU& U^W~0y@ЌiX![rN>sS{0lH /$ުjj\o[\ 7@p(|1/:J -P1-3G44qm& ZvL7BeGlv*vHӳHA0|6" q=\x1I ͕Ir%wiD\~Ls$^{4@žİ#R L@cNȯt`$,*2`ΉQ$(! FV ; 82Fp `i G`!! P`bt#a 0XliA#X׿ P+0lbJX6hl  H`-%VHPn,G E=dvг2KG$ ܗ ! Tqx;aHѐnG)PH S83&DtB82v7 /$"#_{)sӀ-T#E@ iHB{Á.K1oր〯cJ 4 8" O#F4;g׸4Hs2up+@љP럡]LB) <Sxpf cyp4y45@s&Ѕ[%1SpPa g褡hƪ%Bo.a0>NDaP0 &(Zm A60 $!S@`*~o@ `fe|`%ހY"=P``* Ԡb ]L"lY 8 ##@J` [ AV9: ld@`i <^rd4RtN # A90 G @>@h pr\b{(`fu ZxB$A'@hA`.@ B@TfP p,!f!"@AJ%Bdc "Q16&@DA |8 f ot j YGa̿Fg`%oާs< 00@ x +lb0j 4k+H@I!! B` @tF!0 A@fBhp`:&u6$K3g> a3Z vv a2v@Rx4t r X'AK@ 4X7Z7F~ dQ:F&T Ed@K`@a @L F \ 4&ܥ:'̶dZB T9`@a *J`b` t%F >`  ԰H LUk A"\BC9( %H` VTK @ E]Jba4pB H `4A$`:h賜A VI ru8+&@8<$ 8 AZAV @ |a/@^wͩvlVNYJoN'GG6@J\uN!,@') $iDB80F=>t/6=ksA|0_hT!B6/ZE 0!Del)@&O.z~  \AhVaQ+!i#$`j/%gA Lor%1{Ii임 RTV }.6CiWKLڤ!`ga =`PUG'x4K)x )X 5AgWY#pRxX U(|! dsFoR   I^Kk`WvsF 9 AJ!F!@(5AyaZ`D`i(Zaidعrz0|aK!v $̒L5v C61'=F m)ЖMRCũ ;7Tp UpOYJfR.(YY%!]E8{se2 !xl![8Ay F#`Ru @xnfa 'G`[aa l(vz< \@~Kjq`4BՂ;N$e# ~?`1GF T [zz YhhaEAKLj"^0Y| 뵵c,#![OFZT ╞G'PvVˤT8 ¡q&"GTg! ( ] x+ R/7MR DzFL &F,W: F jI6| lb<81 "A ]v+OkD)F̯3:v#e!` U0  V܎`4*ڠ1#3L泗AvS Hإ{F<#}@`BF˙U b  J̄%Gg`V}.$!q`N@@6AWk0UTJOFNpzU*J@;@TE<N]4&G0J@  3BDe>%A7'0 -QjN)j8EN4J aL DcN_ ]3bÇ9̚3Uh- CMS4B 2];IIԯgԦ40I͛8sɳϟ@ 2if4p0"j\,@aRaKv Z5lب #SM :~4!Ϊ`߿~ivP̩h׶vaC@͸hAeӸ8@!E^l44gY0ԭ A$Up(ͦmiR[lخ];N !H 5uᄟlJ?D(>tذ5loNaDDͬ @85lCsAHh4jA Mf59E05?H6$դd"!WC@)OD1h` N$Bu]0LL$4N@q!En`NuO]LɄX*C G8 a0PDLxT 6m&g A I41IEN MM( ?D gmp‘1ZMHa}i I8Pa;]V}p9fC#?:`~n;߾rɹrpPP  Ч۪AJ㰺gwP !pXJ5$6Y~q/o "qa5PB=p'â:0(YR`!{` į xdhDߍpa _HPwjsp4\HYsfD*P+8= RqV ^+z "&C0q89ʘhD1pE:1aQLc(G6 f 2a<Ǡ44! BF{4iHN^`"EP^oe#*JS򆢴$&JŐUd-wYCNztG\Md>ZkLf*-z,;&*Mp|an eO̙Jp-|f8i9be&5s4aJ%7Lvҳd93Ѓ1D0٤]%Fo2բΐ:T-iC1:τn#M9!Qmv Ҏƞ5)A)Q~'E)7WTԥ(CzԦ4~8)HuLޔT]iV *jU{P_j(MIWjݪ.?jөVe)WԵ mCV5(Oi_aISz"i@kVú]I |Vv}{-kIўedՒmq!+V}n2ٚڼ gv}m*uӺ˚άnL׺~/lKTf/mFzU^n侷jˮNWoKY¬'~[VdpiT;M\S{W ώ1ʺָhjikׁ%NJK\ˉ2(YіX62Ry\e#w8ɕP;Uem[i=E@>578|_F4 h,؟yQ2wK~(\ҐҿssF5!1aA Xq%z 8C؁ "8$X&xs`& $<+8<;*80=J*(X? KpW?-BKF'( FpD CIU"`0=(#28i~(P*i ,I; PN  ")H;"D9aH= [51J UI;ȕ-y9_ ]| +p:<0710 8*81EL@x!0 j@ s`!(ө7L7  NPwXcNP 0B}G 0I"Y PP};@"OʂɚРyIL`JC Ѡ p,@qa, sPJ@ JEFC<   Q5  f p ȏ  p#P @ N@$ S!0Uq` ;Q P| _aҩ S)\ Ln Pt, 0 sP \ %LP fBu)$  /!.| X0J  Ҡ8s@ W)  R3pԠ̻0 D` p*BἺ  q%0p 7d 0fˢ q#pP [ @ۡZP}0 ௓iz5@` IbvBP60p~ 6"Ţa>` jA# 20pک 4È q[! 1ٺ `Pݎt] ;=}0 Z+ ٰ53ގ\=fm9 Q#@ْ@W \j p?@ u܎XR ِ^v,}q 7Np =#@>$ Faڪځ } b"&G*`n b B *:-mm! 0 y `p] % р$`>F` РRbcPLy Iy61ҎЬtob \`Q` }T.? yF^6g.g| (]5p8>ٰ c%#%}psө9 = O s`{2<IBeN isE[@͍9:70 {w !8~ *Pbqa;>p #  )(!L |v6nP yqb Uk? >tAJ3]L-fg̈@`8,hjP0O4U!605, D4Q:@lAPs)Ila ѤQ5E24hEVZmݾW.Z[-{@&,l5E,l@ 4cKn$XtTTv &^ T+edC0zAr4&Є) C Xp$m~|D` 4i&m@ăA_ͤ,q:Dh%$0`K",H#<!jƚ+4 ,1 iQ(k̻-1Ҁ&!V&rtEQ$і"r & T& 92K-ˆ&kTiHa "Bb?f.`ތa´*:0 K %Cf!\2X;Bh&p -|9`hӠf1;>&$\h(‚܃o/ikh`.+(:hS%6F`Z)  Xx %`6#H `8p#f8~@!@F ƚ%2eWfy gyF 4eB-f& rk&GC7č'Ɠ-HZ؎6FN7 H&58$f!褣OJ™klC;*"^ M>SZ0))`f~aQE P[Zf+*'bf-pq-҆.C$g$`t0 (c-h) j?`( ide?e @`B$kLcCfԀ'xJT)Iud l KpQ lXgSHÁQc !P $")"! lCBjcс(}!B)alpiK039k!+4JXH k3nQ lՁ8!#E@D@  %!W)Ej0#30pkdҠEZA(&FĠrF51җ ,AR8`TD#98$` h%+  Cdta07@bo30!Fyp?8\6n: T0|EM`P0C@ (9pC#wCp*.4 A Av`; 131+Ȃ19mȀi! .C(p9TB0Q-Im @;#a 0l`8` p@]]C qJ [<RltX65-R|Vep,b/),:2lfRtMZB:]+E)k`XB8ںֶF@hߒ8nS6bmle˖VQ1!)׾5J~xE -W*4Z*8]?;JT7&p\l ?$YhF3Y 氃O<)fˊR0quc: L0PDG^ _ |~ 2b'A8TA祷.R< ]s*1 #Al<|#:O`n#Me:ft 8pr԰ 84bX-򉢊FQ#8*c5]AVEmB˥ccO;Z0V#u0@'I 5DB$$/FZ7:_ 1h:z,lйȭh)$.8/9'A.KksF T{m @0B4\D.=  i`\IK(@eMumc@+0FT~O;D@DT0Z$pv^ NoA 0ݜ9@ 04%A$pVN= V |NP^08Stirtػ]5iA;S_LpQk*09oN5۸Aܐ~DN9891 KHB8@D L  9įCGuOۨHucAK` n!a̜oCȇ7,`8~]m_:Ɓp)Bc#8! `ApfF @ j@QpPG<qr1@3hBtF@`(Ц>`>QidQ5He$vG-6q$A ioQAmhh=9m Oa9ʺ΢V~ jC hA3)~#x@ :#ۘs#Լ8 IXR:Tq!LN0؆o4< 81j0A!3! qYD%*dhGRqj#01a}CHGlB)91w+F8© *<43;"  @ Ї8HD akhJD8=(@!؇:A \4}t5 jgń@K!`)DbW:P.$ (4m,"p@\q)RTAPvE06 pCJ@<{C x& RcpF w$ D cU5 FЀ0bqt!7tpsC DI7 h B  @=0jv"da4XP9P[-1r- (U Q@[ڰ% g V@ V P AQ `/yw"ڠ@XExfx/Xlump)0~T'-#p` 0'Jr)0,# pz,DžOgU31}2 W rGݐ ,4?%`  3O P[ݰ #  'x _@ q*@zX 0$H&H(Xl\A.P& 7H0`[װ~p&` ؐ P P[⠐s4@f<"RP h脇6 ՕP#8ݰsC)2pX*A`fp   Vp  W h y| cx8`   b9(G0ڈX ` 8B*'3`a0 ϐQIY0x0p&`pNНP` @lg(Ǔt?x[`N``P8`Yw0|`E 0>%Ƨ4AΠOSpykXd8lI  6!eٙ wyЎ!%8s<~' D"p9а p&'uC@ ݉M)O@f3ӓ y;J0B7 ߀O4T)A)p% ad]hyk )  c~@CaPd'D'褘=QIWJY(\w0gd!f #RߐÒݠQPVp& m 0|ېOn J`G L90z5 + PWypGP 9o@c怢r12* @8HI:%B*Ř 5٤b:Zሥ K!eg*)ВߤYv&Ap)$y p @y˫zLp% 0yG&ܠgސpE;g:#M'`P @OyZ:" Py拸`{0tY`-`~k˚ݠ@  w 0 R A@ {!%f 9@Xk nnPy 3A4 c(zVj p3K˛[c' V`"ސTc C4PL2:!040-i l Ip;>$GIʮA}EK0ipJF@)@ lInMWKJkwG m`Fڶ!!0D OR k qL v | znZE ܰO$Ua2pKpPY[̹`bL)F@P $h4Dƺ  Ƞ4|!0Gp)~I` j@PbYe9|(r I`|3Z@\ 0Ea" 9 X0 LbEX 17@PJ$#1p vYwPpˉS=Bw _ -@)6`1i@Ӥ,` qZu@t%R@1 ߠ@gXl0ژiQVy~f BId8}\ pP!@ I%LAZc o.`0v7n"$ G`wԲLKa0:@`!]aKnV` sٱ9P!+A ӔM HW0e6@` "mJ(@N GW@ p<5c (!`T00gP_AcH5>x .w} q|p%`6`f(!U~{ =* 5n;5je ^JX0~ JUƠi? `aHUP[ @(٠"$ 8G' b K0SPp& 0M ` @ =@ H -0 p B[ 2D=SP ,`Pc0ڠ1paD-P dP!0)n !ݰp 0M[$ 5 ְ0`X @MS` N"4`TvJ `q0$ PcK̰@7[. xcpw,P[Oypu({ɣN <߿bȑ$@yI-]vP"J+_Z\N,;Pxb$ Pe)TS* f^|jP67 CvDÆ ;o6)+:ꑏghǓwM&ЁFD6{!44=09au_az #@ԁsdኲqq0;q =qp%x:!(? `z(7ļp?`fa8YEB~C $P G>ԁTz) <Ѷhȇ9p8@ 9p2quYxALAqd#=vqCp@Ti' NT9H $} \b7 ,ʥ OK` ISЀ88F  `끎@ h>p:@TZBP( /f ?yCX.S*$дi@Ԧ2cIҤ >:ԭ(ܞԟդR*Sʱĝn UzEFcW @pLT{ncTeL`>>q4U`m "?2-lK&Pn$Rkdݖٞu'hS#ے[r(a, `PD#8P" 4/ң ơc ?~Cُ# 6t Up= #t f"Q~dzۇ-@e 9D 14 + `k@?KFard(0aWX) +7 >B(YG$P o~E9h"~a! 1(9HX\'9f ` Uh](I@A b> 9qKf 9An+tG/{E`V  ~C %$GY -f?`R:}MDl"w)p ;q}o8*∇>ꡎhtD 8Ŀ &N0o :'u#DD@h` > >)>pzj8ArjQ3p41`;n7ux ɠ?F6Fxl= rp 6 vC?Dsқ"?Q؈I2*tuL@;э7 kFk@!S@Qx lx= HXt | 84X@pw`vps870Ryxw [k@wh6z y~x {h%'lyAHSr@!%P+4bvȇmҀ P= scqxyS:WȠ&v ~xAk= vЇxHx0+ 10}xxyCvs=L?}`Ax.{;3vH|J A[@zBjBwC~H 'B0P.2-x &4@wP7@i+H|wHP?X͠,@=Sp ⃵1sfqSDPBRf؆Tp0N+0 dAluYs^ PExsv$xʸрq is3H<' hf]Ɇn'W3>qxsdxȇrPh"Ȍp@i8Ah@l(|& |?htXȆ&}peio 0%@&0zځ:І 3俞|gX(Px(G fHTaXz˹}zPD(oH޴ɹI4m˂.܃;щ5xz@n,ٛ L|#pmBWHlGG]8!9&Ṳxn9d <,*z?`:kқ /08>X P2+xy3|n 8hfSa<-xM$`}3] `rxz$ExZ+q|P/ѱU*84Wl0ɿ@o-;[+#:cAc+\B.SC>SM䙂n1 V1P] H{(-$r(kr}БnAXeKݏY GekJH}k0fb΂EgpЈixjXDb&P7wЌZwx]\08k ؆xȇA쿈Fv@Qn ve܃dvPV ^x`"=ba58I!{p H1pgAh<*+ hW5<ɂxd1&yS$j!jj R@kA,VܞE/kH^K(ȆsH@X FsMhm8Lmʖ˶Оfy(mdl1yh1)R(3r8n@fR0{n>nv$L\ h|Ύ5'y~&σMz WMktv`YsnHSyvp-olllvІivm'߈p 0ΈyXDc5KoY$ :nqHeF\'^D^ gd"SQ(,08؀sh6{4ޣ{`.ۃ}ej,h\vop1(l]8'f,Jpؼ?O;F g (Xzr惰xw}kHfmp=&ȥ9h+h0!>g?Mkdi5;٫nD4$h+YJDY!Р?Kz4 <}F$P=p&9uc`sF;z8p|UpB|u8ۻ|XPJpÆjP,zh+2BzpۧтEZu#`9&QFo>0P>u|m-^>f) s谁A 9͛7Æ8 p@}0Ȼy\w{@!\u{,H\>4XC7-gڌ (qCO:GL`714@COIAA4#^47+~!f=z5ԏi y#TS<Aڊ4M?u64,,Diđ!TI0QM6X?iF:cf5dP 8PM3nG8:{e_sO;,Pd.#HS 4=Bt3ȓM Pؔs:N0,Ai$Z!4Î$2@AN=8 D  P' ' xS65h|gPwC~&ӎ7|Ou\ANCH 9':@ X1( 2̰b4sK=} #6r]X.PA]l 3|<\X:C)f ZC<<Ӎ;CeQGII=585wA8>E~ϸ6P)rqr8J 5*SN XsM4ۜs:8桟,|-8=@y0A& @򀓼:: 2 N!6Bp?3W2[3j XQVB?F=JxLs( B3DDtnRA@ FAMFbjc.A. FZ鎁$ijJ=;u  rP: +]{JAq#=<P ܰ(E9\Oq@ `â?:1!T\H?>C , GJ*!|#YxF@"kRvf30|رpL \q#PG3 ʃH 9TNJ~dwCm?0]N-p9#,;\qvN p5ֱwx !p\}r!8cX3?jd4Ѹ}8P?Ѐ`"~d؇7B&Dp!UL 0[1>RnA;f+ q &0<(pqG<;s( -Qa`=(iY9! 6?M6`tHC 4* BJ2! P4 mC0dP(8, ]f<=~Gxx@="@@$AA$P@ C3xP`P=$47؛)5(M7@@FFA"!""$Lc\L֤M%M$OO$,@4>6 `5L(4:“b8;7!(%$@;PLdZ%P\%]ehvO:;K\9==Ct] P;@A;&iH.Ii&kfA*@`9;7Vp@ C> 0_$ A3:̗>=ă:C$khNu0Yë\w~wZA)T7tC7dC3A @%pC6@<"!TB 6@"B'@$hP@l6"(Fh[:@e%rhv$D@\h@$&J0(L ,[樎d(dZgc@#h@@aƒB) B<) &N)Oh@Ti*&[OP\ hd$ (h)A4X?@**8 LgA8d80A)q\£N* Mj@jp|>,w2C?C3f>hW>C4PVP4?ò#PK"D4A8=xbWh A 9;}^g0D5hAx<3t;7Fe4<0K%XAfB֚KSC\6]C}6|9B.і&lh2@$ 8PMR6+ì8&B<,>z,p4X^D@C>^i,$$VU|ڮ"p5mD:܌`@bj+1QjJ@.P®;!@.JÒ"THe<LQTV6$V4qE7A6 eij8Â[W790d܃5T<4>q^)J2thC|S2*Rv2eWnw_64k6":b5?88A[t8:|C7x74v Ŗsi8=8g7pC qo9|7j# (C8<8CV^M8>|TEtE-96 @#|7 ewPB98|A8`jc/7t? :( d'4T6@r\{cA_I;wH ( ]??c@i;d@$( 9 @:p @Axqk 2@  A(;C4 sD <<JEP<lH )Դd?(dc(Ƀ<@|8TH(䁣Ё!ƒ ԠӇʁ '  D@i/ۍ(lŃ٦oݜ@;$0>vn Pp`;|:pۼ{P,=f ]@I}Ν8# ͛g䇛 j87"ZTyF4*WT PWX@c>vXAл{h(&Z0 )>h*H@ ('thРs$'7AG}y@(_`pIw@)l YjB7(6g>a`0vMDlF*GE[9.00ɧ0ީ$$l 0TR`O"OwVA@ %Gy7:q8"1 ZE|QP2D6X`K@F a',&F|@wu`=(Jr.k0j@qb,}'{ ~G6x'u1fc&HuԱ'L53zCP'` fFotq"{du([!]CE_!0Grzzfh#PtnVqvp`pu?sb!@88puF  `_qzW+BQb}f8e=.pAoazΩy) JupKUٙ>)-AA1x9Tq p7R8cDМ@#L pyp8׉aC ͻ1v@ ;hk$< bJ _{C8d !^y@g 0G;  @̀q "c̀І]``"pv8YКisQ@(@fw zA ;FiAmqՌ_j<9 @9F?eJS)V D+W/Y*TC(7("k:eiFD@UjT#PA:3ԗKe*PCJun+*`H "@O&Y,7HpIe@@o5cG;% @i;"@+Le2s,Ұ7J.H|j {x|X.`$ ̀^nFLܛh0@pG2f1. DjqqvqatnJt4c@=s]xQJ^;(Y \ ot@^Gc:RzVN0[A[yc<,{BP \<ı,4)F0hdBP ̳H0S# \P"+6MHA*G>@e63;N`0 h,:yf ,0G7);:@A3!LP!r! nC nM+FI@ 2AB6TB! Mwd&$ fEY,fft?q! RzݒQ;^p@'\B8 ><d}DS;}+oZ vSE|o9}rSpsࣟj@L xG:Qn(Pich{uF6iܗ:֡A8\E!Ah~j-С:a@4me>ơaaFA6`0A@SENA<(*ArVpAt! @RMq`ZmʡJc AAujB! @!!ȁz6x¼MmЈƱ4i J*" !s dp ȡYd Ԥ&PA`)AJi pAh"a @!bbp%t @ 3 >arqiԡXNn" !N)$^K0A!*b qAPqA& R! 4BR7:AH@*p!1% ". !,ġ:ցfb A ZLl'L`1"Өئ! 6a !D4Pam A ) Aġ^ 3 4`<BA njp|7`*< .;8`aV0!ʁ2p>  !@1 @4N!6rB/`|F(@PnṴc2z0;D^ AA L>(P Bn7b! ANA22ɇ`JHhH{@m2  xt  QǑD'`*@9 @3RbRPQOC T u@ LWME>Wm+.m@ EFRU07Y[i&3@t X=S W Q 0T  z^`@)\!( 6.[-@!2[u$a^c[df8VBcGYMCb<6?T3UVeCVN7$fdS`"gc6cdgyvefOVhzn!VYVg`"6Eb3jspNjq6n""gSg6Nm6nvnmn6ovo%[=Vn-fvp p 73: 0A( B  YwrVp)r176s9s!45nsIt/`bZlLwr6vin-vqpo7tEvswN`ehaNogys-7zWztn}zs53C0a<mr|2|)3m(w~ r D|jx}ww{ ؀Xn=Vh@X]r/x6Xcp=Ed᥄XEvUxY]a8~7s5`sdvd S|o66T2Wn;^5P@bU{7s@rux7w%E!ƁWڶn5u^>!޳v8n4\ 0̷8n-T 02mRN `vCp8~= |^(`9< `44">a N-"N5@&'4p @ɕBG > \2pHaDA`B5CX$! @qY!~, basA1{GV(haA!A eb`"A8!ZځRvmU8`r3#!H47p& ^3(3!~,nV`&ȍ5e(Xd^~@HAA` i!6I&S=vz'N   qց.kjA /߾a0@/f$fayp1 @ ̤oԈ)$aށ/a<6A0~d(@!jR~>!4*A߻u맨7P;x{/ {.#=}-XOC|[ݼ{Ia?ԭ7/>h4 &4E2[(%;ĠXǒՈ6ڵlۺ} 7ܹtn4k-޽y) n&PSo([+ROѳG…fs 3u1[qmYDmt*:|l%R )z^H~+H3rAp]>uY"0ݼvkw{ ˖E4cE:#":FōN=|Ì&P8EP6!ASNbHWRL)E1AFН:H&5\K]"<t? +3z$H Aӎ 6:cte]~ h^nm? FXQ 8e94@?\?lO<`:@ ؃@D8CXN20gİF_%k!z?$P+ȣ ,M;L b5:S˳|x86jZ!P@\jN0:TOr8\ܔAh6<6;prK#!Dp+N>@?9)5c f@\>du83EL@g{ wr='VC9R*:CSBЄ:Fs LPDWq@$OD50:l`̳VQeیEmC8E!;`\D=ͣN |#>q J;\v+ 1'Gc9,,]Vi5@śPlz%@=}@x0@}C 0J6r`9 BBH@ :.-G4jp, 4mLlb>mo1Ied;BC$ixqC&G G=!oty XHv NP؇>1ˠX '| o}B޷&m8G׶Xja8ا,rHYB |P8 $< Px6c ! ?C .@EɟPCt!g֑p4UJ:1Ӊ mCP 0;Ca}h{CH}BA֡AN"3<3?E h@0i,v2IIj@hI0i;;xC7T |pe(Y F 1`Q%إ0cɖ>4 @G{|FcN <]8j6a60 `ҡr,HC \Bp=KE÷d  6ѐ 3#(JY\&Pnx%7LPy|# ٖ!K} Hb+EjUqբdպ@4q`h8C @YϚֵu|o=j_2K"-x:W7po-dc(dfX=Zx>NmhVC\h 6|(PE< NFNK 4p0ERX:ocn`6Mv{k@#IzDuQ"Z8Z<M-##_ZQnD"PhM*'ysZ:-$承zcmiqQ^\jD;q iHch1r yQu<ڼhG:`6Cu :9ބ/|CnadDo-b w<H8HשJ#@{C E98'Db<#5TdSy› P`(9v- ; woP I(l9cE2lag(d<0vҐ2>m5mM'DAB%CIt {T̓Y}fx%nUo cSgy6 3 3A;XD_ {T= 0X{IFr ^!}Jje}n]P K` FZp~~N PaYp `mFiwkO ՠ 0Ї :4bub` mpoX Rq%ݰ*pp8 0DN30MPbuEU0xI 08@:*P{ PxF10 \ x`.)QbP cqbRnPP G z <{lK NMPYsc0G -@OkoPR[cp b`Wʂ@l $f5P}"IMJP8 `M"[JEJ2@cMU9Rxk<>z8(Z9[*A@>0?Z3@EC8IăR1LNਏڣJ:E^E$0Np8b_E? )ik*m4P?>c >JMCQ\C0ClQ3 vBZٷ67sRAj6jusj!vk!edws6yhLFU'xh!j jhQP9Rdg3Xij׭:[0v(Lmފ]j!{p 1 $fx٪K˴MO p? * BL[˵]_ q3$` F#q+sKuیp P 9 :4jk;` "2p`Zĩ Vثo π 7o˻+( @ptېP`r*DEA296vL Q˘tPDʣ1^Kr%`N}2 `1ۤAԿu竴tM` `$)qR0 RKkD9P 0 '3D~ p  $MG`Lx"` %`S- [ ' ΰ*)0#Pł2` WؿuÅjP ![xDlHvj<F Z{Xl CPC5Ȫh1SJ+X`P,@'x^w mb5I ~G`@ՏF- = #@"pk"@؊M#EL l7"0 ؠ ؋Ȏ(GI#0"3ͿEA$QX\-ۉ]ۭ0 ~P΍ة$0 `P-t$ [ ۈذ=؝w!ے}x=ٗە|-Mt+؄ Ie Р`0Bu)0 ư҄lѱ|  ʦl0 Ͽ`̀` ci~ pCp ~ 5E!M @ ~D q[` K. }0̠l03>. e ˠ)p| ̰[. fp:0 z.=c{n6 Y|Ap  [M0[ENL &^ Mۿ&`}! Mg!Y 0p쇀r+ՠ!0p p p1 2l|8` /1 :@P2㙽 PѠ` fP1p D Ӡpc1j Ґ*/ ` 8׍.j `? h }oy Dp ,}/ 0 Jp@ 0P <' ^ `@o <H ʦW#/2> c0wRp+?0|>sOiX[ 6^2`nc@0<@ !8 #P#  %CP |0#pA ʟ06 ؿGP ПI OP % pFo*CR_PR ̅%N8CѢAR" Gf`aBS`)IYO>D!>*U$iͶDC!6McD#>LaiͰL2$6L%b<4 ZD)ORطb>Ai|M*UTfAtaf a"b)2TԩUKPZSPR%:B 4hN<$<|&tD'NE-ƪ}"JԖE)!Y4`-8Dd(ۖ4Q L:ˁ8$ jha00CONy 6 a@ k>"+jR;m~Q5p/,C#Cs"F"*ؠ,i& 8Ep%Ton:5ZD7fy Hf# k/;BOy& |ue#@ga8Q` 5,N t@Fa$E"dWg`Al Ԃ$h F〞 DMX@ ]bF}堅7E8"dhS_6&~iF 9\R: 8Z𨦔 di"AT% `-I>ނu]F-eN"bk\>t掉2Z> a[i%10p Ě78`|KBdЈl">N4!RHbj`ZG„41~`AP j>2T3PM3;P<G ",~hh""$,cIn< hF5lL? -`*J`4 (h*hADZ,#ЛI~ )[шĩ C(ЁQ7p B+HnP:jĎ#0XRDG֥ <`LIMOXֻD c4c 4#Q @bhke1Sla p@"dJԀ3! _#@p`ܑxȨxԁ",&R!"Xj@o` "fTaE@FI lXdUa#ċ1XZ Fڌ16R%h#|OEdj pF'h!!  Lf !a NntL%fRjD "`Pp3[5@<2 5Z)8CL 0 UD|L{z" X3 cK gB OO*",mD NĴj 0u@ 9q F ӂ#Phy7Q 2A d^Sj,!Mt1ӫ5#F_$#XVDHHq4#khm_!K&V:8&R@`HA fuu%^K6(y668-*\y^j4YTJ: B jidA X5 - _@́.[}&?i3](<eքX bW8DD8 Y w3 fHXPia `BXMeN+Y V ?RҀT5P?O`:i&rd(g0&q@5$U< > /=e#'R $&t6(ŖI.bA @B3޶`ӈDKOT(tp+X\}J h ))1cRH j|yR9:0I*5"\>"@TsUbi@J._`DGD=IWo[C*WD|tVyyxž_YS@c ]$;z70@pBd4&O } ̤:/_s?I}ـQ s1 L"s(3-|4tRCGs&bV.pQ>( ` ȗA*0S* lP ӂaےBe kX p`,?Ȇ g1m1ұoţ;h+`pUC>#V-z14HX`"(3=#Ex@ iʷ  8e-0a!yڣ q-UHрjT 7xiPшf8k)J`ZEhqJ 5%xP['/&x E8`..+IQ5qDɵp&8p!#@ c+Ae{ o„&с'XO+Eh 8hB6&B"B+Nj 聗8F%UBS21bg0*C&:h!Pj`iX1gÀp ah@sEF -?1`~uSg-?x'@!p>Ú2PU H?Ђp 3!pCsR ,u(@J/3;8hp'[-p;Ҁ)8% h)>0t,h)`Ζ71)7P hA] 8AXZ(Esg]%H}"'(@-#(ؾ p89P'Ҁ 5' T?5m_YX_}$puYRu,p_Ms"o 8`Mx_r `u_! 8`Gd%)!UB`Npxz;_N:Z_,D4z`g őb  *|_)!Οarr_9"c;c<:=6uš?(;cB:.dDNdE!>^ d䗉udKdLdMdNnNeQeR.eS7=eU^eVneW~eudXeZe[埫F\e^e_ed`fb.fcdY>fcb\^da<|f;NfeZf`[8hpd]v xHIgT.ct~[mg@fg}gdW)eprYl)ۭ1eFNeЂyy#dh`P ^ހ#pl^O_(\7dhUHFѫ韃k@)Fj ^؁(@Vp`8*ܼ'.燎hifnKvj-#@^k)jBjjzv߲%b``ndY hkͣ)k]ikf"_h0n0kh[d;R E{킩RmZUۦE J+Zl.hiOZ#S"@gg^{飈 `|Sn&A^mŠ n[jИ-[ oPn]6d^`ocmNW)P;PZ?x)N5j?H,81胺mAEȀ`?9( x^h-[8T18Ձ_)x7Eqp!],0]8 P]Ђg`Dq7C ,>`0-x>7HP1Y'x |p5pvUput^e;srюaڃ- lIFH4cHjzfP1-hhxXx`hғ h>P,mG 3.PxW{yGuf؆li&!p\#kQhIv?0EVY)`iH t* hlNqL0CRbnXa ^n;7~0y4.S$(LGZB(qj"BXM"!׆&&Dbа5 *Dp5ѭ"02 !Rs7J;)5Z؜M a ظA"7D7Єp/H@`㬁Ѳ"KҌ!H i@c  cc""u ΨF3tqS銶s60-AϘ 2B@yV l d~ P  XA#)1LEx S]Xk9&1um6i@is#l@18wr 1&@#2Q !43T"^f7/0OD#(}~ѹ'eT# J-"qNfҠX:8ڣBwʕ.Lǂp2!mCp[<(ZkhSi4 H!J@{8  SGЃ(}E-u+n(AN<`N$0@ARwy3ܰH!x -4A h n# `ATC8ssǿFun\9g|E6/ ? s QLB7G(qfhw X il"A*q{G2 ۻ"pC +0X#(2Lj%E=o %yλ W$Ӑ!+fE^ih?%u'r>$Wa{h `v{ @d]gyJ l@AgneGj8>(XY*j4A3l6d6B`T>$6w~ 4d*@Ԅ*i <L)@Xbg2[\!AC颅>W\B68(tOb5xt')}hc(V5\C6YTY&ipVd,4ڈbCr ' %"l D!ӚrUz `B$ 4W%4ԗ={R)|P86jc,x(G,T6d3h2k{̍E`@Y@3XŲ)#Ju<be:JNet̜546kFP(AfTQX$HF%TFdRcFU*JH`,dN)U ,e2[ZlVlVZhD̎Ɗ֣FZfܫmSZuĊ  <-΀ ؙB- Rr@ֺ@=zm `-  أʀ Xǎ - `ymԦ@ TXl \DmZ (.C l k (ERXߖErЪfAz H'<5@30 ($"#AHY54$<V` \Bo20rBJ`5A(44@o+l, 08g-ā T&!P5Q2BeHB=0](0FT4XHtp5\Tʅ&e(aY-A"6d4`0\d$`4Xg2җ ]-,Ҫ Z4h&FCS4PT4834D D@*.9Qdq5N@dWC(A383D5hͩ\`MT]-) A34GmT9ED6H/?C +IΈ l5JAor]r50w&N*œ\>++FZRV݄ @o\IC$@ᩞ1@Ctel6nL/M@D42؀9i d3,L5R8馜:4-$&*&+!ؠ XpÄ  d&P=4hcz1.N &CЌ ;`"!&&7(;J5ظx6pӍ7 x05N F3 Khv!,CR#j;rMo^c݌WÈk6YF"Q:Ґ8Q(hzF NoN0 0f8tD.Q4qg Sf@TQ lL= XV`^ chB9KV/ [L$=UЄ ,G CJ khBp1mBJ˂@-8ḓ@z 0l >虴h86 YB (] \m‚-l!. lb k %  ` 1, PAº %h DD\Zv `‘< ! B<  T?ACҀGF +' D"H VGl1!NfД0`p#;UH47Yf|^׀Ǵs@yd/ 6g( xA䢝I|2LS:$X B3А ׸Ώdׅ)r1a `z}\$> K]esdzByjۧO hX]ns>\gtY`@ a o7VVPoh@?pDOX)^q__&Qo d\|k YrC615GHߔ.A~b () -0t_YWC8@]ixlR~* y/J0Õـ 8 D~R! nM~|J g<כ5؄iHcO.Nь%0w^\_{ -dE/0hDbq-a7 ({__S 4@BwKx{Sf|o1 H$$R^K8cY"m޷ > `$@@A F~~B` &N$@ $/?8na+{,PODj D&PA ~h, b Lp$PtO+af Cpa%}O1pP0 OZ݈0 D/$@̦a$8^( rҏ!J Q m"@>J^pj P. dbP@"AϦ^Mrl:Ê#6  <.9W$@qSLʨ7BR8$DFBH` A$`b~J 4hT2(d$H`$G` 9@a DB B VD-HA9Gso_LD M@t &g5J* ` BZdD.u.h-N`>`LR 6!'L  *! ' | !m(! &Cu` `@~Nf ]#R" pU!@ \J N_@ rH ` 3Y.Z( !:# rTD@fʏ <B6?VK tguV $>K'UD@` !j 82hb  f`` !A%N Q,l5x4` ef Rp&k0@yrv;Tc FH(Mb6`Aj#@rft!j@  n] `"z$Um "˒ `dō6@AA >so0`]1 ;: ĵ`/ *`]n0Uз"Wb NP=  LVW@5ѣ!u\\#p!rpS@s >  G*@P$!m!f6A`7(tʧ0mlOO@ gM0$k:7a A6`bOS@5{%!yJAA@ rF! m~`UVU3t!(@! F 88M$( N !JC^ A`(V# Aj$ "U@P >ƢY+`@mO'!2g8 x  o d:x CmԖ0@ $AN&8` DxA RƬ &ʘb \Z bZD;G&Oe@nNր _gv$a>gH@ @ x@P%$6$jM#NqNZq!lx ^t }LIv:U @g`L'!P#PB^&G% 16zI(B03 @ ~_¦#5zj~A8a eAD`$!A1ͺ`  a3Sb~ T!aA !Ala J Q nvJ]\3{4c |@w@J;5\M mUN` a(O! @q`@aN)z,O ᐺ[":@MF` j!t2Ӈ1 pA"Ae:J@ ڴ+۔8 ȇu z۵]>a|F`Jpc  @\aa]j̹B!ܠY`A{P' "a`r 'e+7S0>Bb2S' A@@P%l?5"W" A'*&օA ͐ u"X@-x AA$0a(|b`6i*_o${`JBl"f) Ɂ! P >!|zV`ix8K$CcF 2>!D==8i'``A TlbUQ%Fܻ![we HmI߿ AӲÇ ~_CP D-`ᄢhBphɓ(S\ɲ˗0cʜI$)͢Ekd=H)ZC&Ќ-p6 {0v쿃p5I:8*L #T餦ȅ CJUf E5sq1)*i0Ě '} X@)j0`} ?"kҁk\z? 0k6פ3EtMj : a;a8,B4g2spGZ"d{, 5[Й9H^ȷPDUtQF1$@DlA5,bLH4TH48c? B'I@e TD PEB `# Mj 3ZlWZLC]CP"!D4X(:IDC!4V7RXC P:E?W:a1 Ch IEW &ċ! pnЀϐH53(H@"4qA{QnD "A%.(nCְk /%)lBWh#k0bhk C ):M38`"#Ep#U4 hC VXG Cd =d:tB āl$5 )t 0g2"`LI<`a@qP c0C-`3h8B$[JX&tAC)qSD dH̠ 9`Q  )(+" fcķ&pjyh ˈsP I88i3 `"`-0 wURbl%&\+'ˊY%=ul3]!>ӎ=4pB~|c)KX%)q'P5t:?~vIMB5_0 [ I[δ7-g@B2e50NۯҖ6WV PDLo^5p"*3[]czЎvtj/G̮n&i2j8NQn;&IMtswom{'8x&W]};=9w\Eϸ3]q/#IKp)9Kr~\/8u^ˆ@3|ݔ74߽xΥS}З~u]eT:׺u<\=6Կײ|'g#=t{wY<.pY|ET]Y|CN ͅ;~#y‹|7_znwU[ϲSz;yK7>ky;_=EO1Mzc?}ϑv>__sn_&;O{G=zS'yWypз||?wcG{X~kN7}z}^<'vǀ h+yw(zՅxM[(|ȁn%׃xDz~HgW xoׄT}8v((p2ȃ8v\zDŽSIh b8]xcxJX^Ȇfixnm8fvf?X7|׉x:׈u(QxtƂ[848U臊hrO~Lj?cB>xBr&yhE(8_xH؍shȌ}'hhtȂK؊ɨ`8G捖Ȏw÷ȏȍ,8~ؐ{7 )zň|LJ'zHO7h%(*ys7:a&Zx}zY-HL9zI9舺z|zhoږZbM).e'Yyx#I'hih&gxgBg/'ٌSIt)fyq_.2k̸9Y2יٚo9טyٛ9uf+O"ę9f" YԜ<Fb5Ӡ Y.ќ̐#9eJ"߉ Is074jZ $J#Z(pР):ICRk4ڣR ;e >zYL` '԰ 2RZG):A Q:\ ׀Ѡ[ڥfpl4 M* LppQ` ° P qFPE @BƧ: e:Zzکq  K$  jZ :g"Gg`w pZIOp9&:`w K@B0jZ1$ #:Z0 ׀ AzA.k f !`?-C`@` X@KꣴRppo'Y! ;A).D  n xP N ġ@t:` ` Y;,qq  6P ` o 4?~А :0# E\X`ZQ~ PY] ! = q?` C5X`'wp ,p00[J. x0YP +ȝ pe,lK A0_\OL@KV"p [{ Y@B!q7w Lp ̠:P_f ;NOPĎ7%u,X 4#2 LAj! 2` !Z@U3#S> ĠmP 0 QsqB0CaYy@B$D+5 YK2AH%MDRJ-]9N"aJ ;!aL@BO,091(>-shX` K3fP B,YKv+R^ >|8hڟ C|6DB 2Q JIb80pW3) f?rAAD /& `3N@x!KgEU"Bĉ&,c @NYIgpE͵RJF@J&H|@+ /0C 7AYs 6DiހQ8MTSNk9`)AjDvO郄jEO eAj@ UjlQg֤lFY(7qW|X]\Fܤ怆gqiw0y~)`5VVfI(Ҥ*w 2hJ6qmgf?yyО0>"g8%Kmtuꪯ^oFU!=[;0vw pM|cH-ҍ$"0f,A$`5U|I:ŒjT + c0b.]f4 GF$&Wh?`UvV23~QxN G<4Oe?4P;f/4*P[H! 8`.&>icN15<NuVhĬgJNxh1Z2ҥ$!\!7JVRɆ'vxh-@ \b%s&:6h4#i>҄ bTy'N&I3<`Z " ,ϋ{j ig@ۀ3D~*Ŵ=-R{S L`F3p!&#U3&ڔЬs@ҁ@\'ԕ7if h܁4@4A%te W 퇃a6%L3Ԡ^4kXMCI(f<`3Td0.Pk@;72ړz5 "V'K,4)z{*h`#iEԁDCjPTFF }*Tra؁5Q~& V2˘D0[d it! p#4[AB Mi |I4xj 3El.@ ҉6O-8n[HAA@aOvMԦi`0|z^aF)! jje=ā( F(:f0sa hF2"gtK4 ` vBQ gx"nIFgD@ h#YK5@6uӑ)f*'qu3A 9:/ %4UȒ*MNa88lsT7(bXF2N P$,5.j lKQ k {ESnBKB;HmBȄja{5@ '5(wl%B% BCq5pk !| :pH:bF0-Т%[&D#P"/hbF`Q$Q#E"j&>-]hF$p0Ah',g5C_+6oHfX W F51L VMpa ?|UDp Xj ``YE!&l!!B1 T8Xj" 1J1AA PYo,A\ %CA1T;I@`% X hJ""X [?؀!> xY" @"ڀ$l˹K( @ p7!( K h @-* d,@%@lp7|> 9* C " 9 C?90:9ĔCB,CDR  xDϲCID9a%DM\JN40CTœDLX|EZDLd1\|8f#38Dd Qf\ |FZ;Zh6eeTmԐ߂UH%g$r4sDGϚktd%AkyȀH)8 !gc A)0$Fgn{ȍȎH8f8HPMȼ-A ɴShEh jȂSɚɛ$G(V8lapHBThԅ5?tʧJ 8,x9x&J #ЂT&Ů4˳DKq X3LK Y˶\K `ś؈q P KoAL| 9TLCuUR#e%$MO3 &?'(t+͐t-*T)5P&XI$-0plT"F`#=MSrg`ih*jmFH%EeFMGuIe֑ L='$% dp(Ќ 1U AUUt0) X| HEȆ> V؀ ,ermVmĀ<p oTqtT "]Ypf*#UƤXWGXUxX1F[ @X,쀗]֘X蓈x7„؀IrVuLTYٜEQԖUxi Jpڏ?0hpo1ڄ]ؔ u[}d ZZqyHZ-WoWLܗ ]ۺܗ[%b+HUMוZe`MEEړZ)J]5Õ (hh`q( U,Z-Gm+[P;"[   dsphp_kK)@Q%OSaPԕ 1fM`(_ 8k}EK_ >]DWOgGHL'~fd-Gr#w.=W&PЂCf- 2V?H=MńQB,hpEH i\[3cYuMl0:ur6. R-0Q;,1$T$mQ_1``gVjixf:8]RԫCxa10`$Hj)-iyFW;YEWh2_S<_ exdh-CN0dhuW{7ʼ3{^-01&cfp Xz(:mF575YКF(Q97+S Tq4C HEfduvi&Pp7xiPP'hex7&xU [a  P#jth?H?(iQ,^3@$v`%8gXV<YHizFiI8 k'`tNb!jIP(MS8 ؐ(^ـRT7C88?xX܄PAxigȂC6̒"JFЏԉ hjxhkU{"XgeLk%p-sbc)rx `]+ЉGb ܀kg>ZOD~p0xUj#(tyh kjhpoH?HD8x+8o#0n8i !8g~H䘐Y3)D92qBjJDHքB9- d,hR p4DM< I6.4$ԀxA ."A3@QG%A" 00NA&W^19n"Zx+*JpEW[ BPI5\4È6ГeF3xh54$A90pmWqpDsgU3YTP"P?šN%pH6xpxV8| Ե5 GhED |2DrX81rL.qM!4RhpD0,̺/֨}9%طi `dq6FU+X[`#`)1衋~l g[Qy> cd} +AvcR65,B ,PsolH$ ^貟0lִ A :h21Z00$ Ą,GK $2! %P` _&p-<1H@$m/~כ hh! - d 47%] HCx4>@K0>7%2L!Ä<#uꞣ;QIPC[D@ @58LH3 ?C Z84QNq,"G%$b9 k< ´=$ Ia 5"x #C"/APG Z) jlb Y u4W4a?eVG3(%!e$ ?d ;M4Ѐl `5-܁ ą27!xC5s'@cJp0$N:fND `ոB) ͸5 '$M: `kdFEHAA-Bٸƚ`R+&mƘO\!X3 lTx;!e `iZ^M)xCZ`k@vZciЌg@a/Q4xhհ6 " BdD i L~!bic83({i,C2bC41\ . ?YAqnPDNԁ 0 Ʌ\XP. v8шF(qB N%MhbCa-oPXbD+`a9 Nǃ@"`qV?<Y]84"1I@>q1 D#` ?q$qiBV?A |%2F8pd3;p`ZD>#4 -@ "hs@ ~1(`>4{ُh@a|, .Y@´ ;C64eVt6pM#L6EJ[nʡ94$I0LB  `8Wl ЮA !~`pMaD4@K9؂.A ?t>PA PO"OEXN7vlӬ"k<#& !|J 5>kqwX? iE ۮmA@J.@$ ?1ǥ Vz8uL PE.& f"{p0hx9;'8@#|s`7ow+7p0c9a?> IHD|  hDlFc xLӯ3] 3"`{{Wo3" B̀44( צ_%=u9 oD"D@!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W!,W;sptlrx-1.2.3/go.mod000066400000000000000000000033231477325515100141720ustar00rootroot00000000000000module github.com/raitonoberu/sptlrx go 1.23.0 toolchain go1.24.1 require ( github.com/Pauloo27/go-mpris v1.4.0 github.com/charmbracelet/bubbletea v1.3.4 github.com/charmbracelet/lipgloss v1.1.0 github.com/coder/websocket v1.8.13 github.com/creasty/defaults v1.8.0 github.com/fhs/gompd v1.0.1 github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 github.com/muesli/reflow v0.3.0 github.com/raitonoberu/lyricsapi v0.0.0-20250321181912-2e8c45d10c8e github.com/spf13/cobra v1.9.1 golang.org/x/term v0.30.0 gopkg.in/yaml.v2 v2.4.0 ) require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/charmbracelet/colorprofile v0.3.0 // indirect github.com/charmbracelet/x/ansi v0.8.0 // indirect github.com/charmbracelet/x/cellbuf v0.0.13 // indirect github.com/charmbracelet/x/term v0.2.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/pquerna/otp v1.4.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect ) sptlrx-1.2.3/go.sum000066400000000000000000000177271477325515100142340ustar00rootroot00000000000000github.com/Pauloo27/go-mpris v1.4.0 h1:KWNTZuXeOdOdIVdzwG/JOOZHlveNiMjiSaK0AWi220c= github.com/Pauloo27/go-mpris v1.4.0/go.mod h1:+9otYxTLPRTVZ6i2k6VrG1Y0RzMbBXGuEUQM4ZSvjxU= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI= github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo= github.com/charmbracelet/colorprofile v0.3.0 h1:KtLh9uuu1RCt+Hml4s6Hz+kB1PfV3wi++1h5ia65yKQ= github.com/charmbracelet/colorprofile v0.3.0/go.mod h1:oHJ340RS2nmG1zRGPmhJKJ/jf4FPNNk0P39/wBPA1G0= github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/fhs/gompd v1.0.1 h1:kBcAhjnAPJQAylZXR0TeH+d2vpjawXlTtKYguqNlF4A= github.com/fhs/gompd v1.0.1/go.mod h1:b219/mNa9PvRqvkUip51b23hGL3iX4d4q3gNXdtrD04= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/raitonoberu/lyricsapi v0.0.0-20250321181912-2e8c45d10c8e h1:WtNsHhtfKScN1SKyAswd63VuZPyzkJP17f100puu0IY= github.com/raitonoberu/lyricsapi v0.0.0-20250321181912-2e8c45d10c8e/go.mod h1:ozDqx0WHdGtgBl4FdUcqOr+QoOcRu8WBh96RkgVSFcI= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= sptlrx-1.2.3/lyrics/000077500000000000000000000000001477325515100143705ustar00rootroot00000000000000sptlrx-1.2.3/lyrics/lyrics.go000066400000000000000000000003721477325515100162260ustar00rootroot00000000000000package lyrics type Provider interface { Lyrics(id, query string) ([]Line, error) } type Line struct { Time int `json:"time"` Words string `json:"words"` } func Timesynced(lines []Line) bool { return len(lines) > 1 && lines[1].Time != 0 } sptlrx-1.2.3/main.go000066400000000000000000000001311477325515100143310ustar00rootroot00000000000000package main import "github.com/raitonoberu/sptlrx/cmd" func main() { cmd.Execute() } sptlrx-1.2.3/man/000077500000000000000000000000001477325515100136365ustar00rootroot00000000000000sptlrx-1.2.3/man/sptlrx.5000066400000000000000000000042741477325515100152670ustar00rootroot00000000000000.\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 .TH "SPTLRX" "5" "October 2024" "" .SH "NAME" \fBsptlrx\fR \- Synchronized lyrics in your terminal .SH "LOCATION" The config file will be created at the first launch\. It is located in \fB~/\.config/sptlrx/config\.yaml\fR\. Run sptlrx \-h to see the full path\. .SH "SPOTIFY" .SS "FORMAT" .nf # config\.yaml cookie: [] player: spotify .fi .SS "NOTES" If you want to use Spotify as your player or lyrics source, you need to specify your cookie\. .IP "1." 4 Open your browser\. .IP "2." 4 Press F12, open the \fINetwork\fR tab and go to open\.spotify\.com\. .IP "3." 4 Click on the first request to \fIopen\.spotify\.com\fR\. .IP "4." 4 Scroll down to the \fIRequest Headers\fR, right click the cookie field and select Copy value\. .IP "5." 4 Paste it to your config\. .IP "" 0 .P You can also set the \fBSPOTIFY_COOKIE\fR environment variable or pass the \fB\-\-cookie\fR flag\. .P \fBTREAT YOUR COOKIE LIKE A PASSWORD AND NEVER SHARE IT!\fR .SH "MPD" .SS "FORMAT" .nf # config\.yaml player: mpd mpd: address: 127\.0\.0\.1:6600 password: "" .fi .SH "MOPIDY" .SS "FORMAT" .nf # config\.yaml player: mopidy mopidy: address: 127\.0\.0\.1:6680 .fi .SH "MPRIS" .SS "FORMAT" .nf # config\.yaml player: mpris mpris: players: [] .fi .SS "NOTES" System player that supports MPRIS protocol will be used\. You can also specify a whitelist of players to use, example: \fBplayers: [rhythmbox, spotifyd, ncspot]\fR\. Run \fBplayerctl \-l\fR to get the names\. .SH "BROWSER" .SS "FORMAT" .nf # config\.yaml player: browser browser: port: 8974 .fi .SS "NOTES" You need to install a browser extension \fIhttps://wnp\.keifufu\.dev/extension/getting\-started\fR\. If you don't change the default port, no further configuration is required\. Otherwise, create a custom adapter in the extension settings\. \fBYou can only run one instance on one port\.\fR .SH "LOCAL" .SS "FORMAT" .nf # config\.yaml local: folder: "" .fi .SS "NOTES" If you want to use your local collection of \fB\.lrc\fR files to display lyrics, specify the folder to scan\. The application will use files with the most similar name\. All other lyrics sources will be disabled\. sptlrx-1.2.3/man/sptlrx.5.ronn000066400000000000000000000036411477325515100162370ustar00rootroot00000000000000sptlrx(5) -- Synchronized lyrics in your terminal ==== ## LOCATION The config file will be created at the first launch. It is located in `~/.config/sptlrx/config.yaml`. Run sptlrx -h to see the full path. ## SPOTIFY ### FORMAT ``` # config.yaml cookie: [] player: spotify ``` ### NOTES If you want to use Spotify as your player or lyrics source, you need to specify your cookie. 1. Open your browser. 2. Press F12, open the *Network* tab and go to open.spotify.com. 3. Click on the first request to *open.spotify.com*. 4. Scroll down to the *Request Headers*, right click the cookie field and select Copy value. 5. Paste it to your config. You can also set the `SPOTIFY_COOKIE` environment variable or pass the `--cookie` flag. **TREAT YOUR COOKIE LIKE A PASSWORD AND NEVER SHARE IT!** ## MPD ### FORMAT ``` # config.yaml player: mpd mpd: address: 127.0.0.1:6600 password: "" ``` ## MOPIDY ### FORMAT ``` # config.yaml player: mopidy mopidy: address: 127.0.0.1:6680 ``` ## MPRIS ### FORMAT ``` # config.yaml player: mpris mpris: players: [] ``` ### NOTES System player that supports MPRIS protocol will be used. You can also specify a whitelist of players to use, example: `players: [rhythmbox, spotifyd, ncspot]`. Run `playerctl -l` to get the names. ## BROWSER ### FORMAT ``` # config.yaml player: browser browser: port: 8974 ``` ### NOTES You need to install a [browser extension](https://wnp.keifufu.dev/extension/getting-started). If you don't change the default port, no further configuration is required. Otherwise, create a custom adapter in the extension settings. **You can only run one instance on one port.** ## LOCAL ### FORMAT ``` # config.yaml local: folder: "" ``` ### NOTES If you want to use your local collection of `.lrc` files to display lyrics, specify the folder to scan. The application will use files with the most similar name. All other lyrics sources will be disabled. sptlrx-1.2.3/player/000077500000000000000000000000001477325515100143575ustar00rootroot00000000000000sptlrx-1.2.3/player/player.go000066400000000000000000000005121477325515100162000ustar00rootroot00000000000000package player type Player interface { State() (*State, error) } type State struct { // ID of the current track. ID string // Query is a string that can be used to find lyrics. Query string // Position of the current track in ms. Position int // Playing means whether the track is playing at the moment. Playing bool } sptlrx-1.2.3/pool/000077500000000000000000000000001477325515100140345ustar00rootroot00000000000000sptlrx-1.2.3/pool/pool.go000066400000000000000000000047401477325515100153410ustar00rootroot00000000000000package pool import ( "github.com/raitonoberu/sptlrx/config" "github.com/raitonoberu/sptlrx/lyrics" "github.com/raitonoberu/sptlrx/player" "time" ) // Update represents the state of the lyrics. type Update struct { Lines []lyrics.Line Index int Playing bool Err error } // Listen polls for lyrics updates and writes them to the channel. func Listen( player player.Player, provider lyrics.Provider, conf *config.Config, ch chan Update, ) { stateCh := make(chan playerState) go listenPlayer(player, stateCh, conf.UpdateInterval) ticker := time.NewTicker( time.Millisecond * time.Duration(conf.TimerInterval), ) var ( state playerState index int lines []lyrics.Line lastUpdate time.Time ) for { changed := false select { case newState := <-stateCh: lastUpdate = time.Now() if newState.ID != state.ID { changed = true if newState.ID != "" { newLines, err := provider.Lyrics(newState.ID, newState.Query) if err != nil { state.Err = err } lines = newLines } else { lines = nil } index = 0 } if newState.Playing != state.Playing { changed = true } state = newState case <-ticker.C: if !state.Playing || !lyrics.Timesynced(lines) { break } now := time.Now() state.Position += int(now.Sub(lastUpdate).Milliseconds()) lastUpdate = now } newIndex := getIndex(state.Position, index, lines) if newIndex != index { changed = true index = newIndex } if changed { ch <- Update{ Lines: lines, Index: index, Playing: state.Playing, Err: state.Err, } } } } type playerState struct { player.State Err error } func listenPlayer(player player.Player, ch chan playerState, interval int) { for { state, err := player.State() st := playerState{Err: err} if state != nil { st.ID = state.ID st.Query = state.Query st.Playing = state.Playing st.Position = state.Position } ch <- st time.Sleep(time.Millisecond * time.Duration(interval)) } } // getIndex is an effective algorithm to get current line's index func getIndex(position, curIndex int, lines []lyrics.Line) int { if len(lines) <= 1 { return 0 } if position >= lines[curIndex].Time { // search after for i := curIndex + 1; i < len(lines); i++ { if position < lines[i].Time { return i - 1 } } return len(lines) - 1 } // search before for i := curIndex; i > 0; i-- { if position > lines[i].Time { return i } } return 0 } sptlrx-1.2.3/pool/pool_test.go000066400000000000000000000015711477325515100163770ustar00rootroot00000000000000package pool import ( "github.com/raitonoberu/sptlrx/services/hosted" "math" "testing" ) func TestGetIndex(t *testing.T) { service := hosted.New("lyricsapi.vercel.app") lines, err := service.Lyrics("", "Death Grips No Love") if err != nil { t.Fatal(err) } test := func(pos, curIndex, expected int) { if index := getIndex(pos, curIndex, lines); index != expected { t.Errorf("failed getting index for pos %d with curIndex %d: expected %d got %d", pos, curIndex, expected, index) } } for i := 0; i < len(lines)-1; i++ { line := lines[i] dif := lines[i+1].Time - line.Time pos := line.Time + (dif / 2) for j := 0; j < len(lines); j++ { test(pos, j, i) } } // edge cases test(0, 0, 0) // 0 if pos == 0 test(lines[0].Time-1, 0, 0) // 0 if pos < first.Time test(math.MaxInt, 0, len(lines)-1) // last if pos > last.Time } sptlrx-1.2.3/services/000077500000000000000000000000001477325515100147065ustar00rootroot00000000000000sptlrx-1.2.3/services/browser/000077500000000000000000000000001477325515100163715ustar00rootroot00000000000000sptlrx-1.2.3/services/browser/browser.go000066400000000000000000000054431477325515100204110ustar00rootroot00000000000000package browser import ( "fmt" "github.com/raitonoberu/sptlrx/player" "io" "net" "net/http" "strconv" "strings" "sync" "time" "github.com/coder/websocket" ) const helloMessage = "ADAPTER_VERSION 1.0.0;WNPRLIB_REVISION 2" type state int const ( stopped state = iota paused playing ) func New(port int) (*Client, error) { c := &Client{} return c, c.start(port) } // Client implements player.Player type Client struct { state state position int title string artist string updateTime time.Time stateMu sync.Mutex connMu sync.Mutex } func (c *Client) handler(w http.ResponseWriter, r *http.Request) { // make sure we only have one connection c.connMu.Lock() defer c.connMu.Unlock() conn, err := websocket.Accept(w, r, &websocket.AcceptOptions{ InsecureSkipVerify: true, }) if err != nil { return } defer conn.Close(websocket.StatusInternalError, "internal error") writer, err := conn.Writer(r.Context(), websocket.MessageText) if err != nil { return } writer.Write([]byte(helloMessage)) writer.Close() for { t, reader, err := conn.Reader(r.Context()) if err != nil { return } msg, err := io.ReadAll(reader) if err != nil { return } if t != websocket.MessageText || len(msg) == 0 { continue } c.processMessage(string(msg)) } } func (c *Client) processMessage(msg string) { spaceIndex := strings.IndexByte(msg, ' ') if spaceIndex == -1 { return } msgType := strings.ToUpper(msg[:spaceIndex]) data := msg[spaceIndex+1:] // we are not doing global locking here because // we are not interested in most of the messages switch msgType { case "STATE": c.stateMu.Lock() switch data { case "PLAYING": c.state = playing case "PAUSED": c.state = paused case "STOPPED": c.state = stopped } c.stateMu.Unlock() case "TITLE": c.stateMu.Lock() c.title = data c.stateMu.Unlock() case "ARTIST": c.stateMu.Lock() c.artist = data c.stateMu.Unlock() case "POSITION_SECONDS": pos, _ := strconv.Atoi(data) c.stateMu.Lock() c.position = pos * 1000 c.updateTime = time.Now() c.stateMu.Unlock() } } func (c *Client) start(port int) error { l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) if err != nil { return err } server := &http.Server{ Handler: http.HandlerFunc(c.handler), } go server.Serve(l) return nil } func (c *Client) State() (*player.State, error) { c.stateMu.Lock() defer c.stateMu.Unlock() if c.state == stopped { return nil, nil } var query string if c.artist != "" { query = c.artist + " " + c.title } else { query = c.title } position := c.position if c.state != paused { position += int(time.Since(c.updateTime).Milliseconds()) } return &player.State{ ID: query, Query: query, Position: position, Playing: c.state == playing, }, nil } sptlrx-1.2.3/services/hosted/000077500000000000000000000000001477325515100161745ustar00rootroot00000000000000sptlrx-1.2.3/services/hosted/hosted.go000066400000000000000000000013201477325515100200050ustar00rootroot00000000000000package hosted import ( "encoding/json" "fmt" "github.com/raitonoberu/sptlrx/lyrics" "net/http" "net/url" ) // Host your own: https://github.com/raitonoberu/lyricsapi func New(host string) *Client { return &Client{ host: host, } } // Client implements lyrics.Provider type Client struct { host string } func (c *Client) Lyrics(id, query string) ([]lyrics.Line, error) { var url = fmt.Sprintf("https://%s/api/lyrics?name=%s", c.host, url.QueryEscape(query)) req, _ := http.NewRequest("GET", url, nil) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() var result []lyrics.Line err = json.NewDecoder(resp.Body).Decode(&result) return result, err } sptlrx-1.2.3/services/local/000077500000000000000000000000001477325515100160005ustar00rootroot00000000000000sptlrx-1.2.3/services/local/local.go000066400000000000000000000047531477325515100174320ustar00rootroot00000000000000package local import ( "bufio" "fmt" "github.com/raitonoberu/sptlrx/lyrics" "io" "io/fs" "os" "path/filepath" "strconv" "strings" ) var replacer = strings.NewReplacer( "_", " ", "-", " ", ",", "", ".", "", "!", "", "?", "", "(", "", ")", "", "[", "", "]", "", ) type file struct { Path string NameParts []string } func New(folder string) (*Client, error) { index, err := createIndex(folder) if err != nil { return nil, err } return &Client{index: index}, nil } // Client implements lyrics.Provider type Client struct { index []*file } func (c *Client) Lyrics(id, query string) ([]lyrics.Line, error) { f := c.findFile(query) if f == nil { return nil, nil } reader, err := os.Open(f.Path) if err != nil { return nil, err } defer reader.Close() return parseLrcFile(reader), nil } func (c *Client) findFile(query string) *file { parts := splitString(query) var best *file var maxScore int for _, f := range c.index { var score int for _, part := range parts { for _, namePart := range f.NameParts { if namePart == part { score++ break } } } if score > maxScore { maxScore = score best = f if score == len(parts) { break } } } return best } func createIndex(folder string) ([]*file, error) { if strings.HasPrefix(folder, "~/") { dirname, _ := os.UserHomeDir() folder = filepath.Join(dirname, folder[2:]) } index := []*file{} return index, filepath.WalkDir(folder, func(path string, d fs.DirEntry, err error) error { if d == nil { return fmt.Errorf("invalid path: %s", path) } if d.IsDir() || !strings.HasSuffix(d.Name(), ".lrc") { return nil } name := strings.TrimSuffix(d.Name(), ".lrc") parts := splitString(name) index = append(index, &file{ Path: path, NameParts: parts, }) return nil }) } func splitString(s string) []string { s = strings.ToLower(s) s = replacer.Replace(s) return strings.Fields(s) } func parseLrcFile(reader io.Reader) []lyrics.Line { result := []lyrics.Line{} scanner := bufio.NewScanner(reader) for scanner.Scan() { line := scanner.Text() if !strings.HasPrefix(line, "[") || len(line) < 10 { continue } result = append(result, parseLrcLine(line)) } return result } func parseLrcLine(line string) lyrics.Line { // [00:00.00]text -> {"time": 0, "words": "text"} h, _ := strconv.Atoi(line[1:3]) m, _ := strconv.Atoi(line[4:6]) s, _ := strconv.Atoi(line[7:9]) return lyrics.Line{ Time: h*60*1000 + m*1000 + s*10, Words: line[10:], } } sptlrx-1.2.3/services/mopidy/000077500000000000000000000000001477325515100162075ustar00rootroot00000000000000sptlrx-1.2.3/services/mopidy/mopidy.go000066400000000000000000000037361477325515100200500ustar00rootroot00000000000000package mopidy import ( "bytes" "encoding/json" "fmt" "github.com/raitonoberu/sptlrx/player" "net/http" ) func New(address string) *Client { return &Client{address: address} } // Client implements player.Player type Client struct { address string } func (c *Client) get(method string, out interface{}) error { body := requestBody{ JsonRPC: "2.0", ID: 1, Method: method, } bodyBytes, err := json.Marshal(body) if err != nil { return err } url := fmt.Sprintf("http://%s/mopidy/rpc", c.address) req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyBytes)) if err != nil { return err } req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() return json.NewDecoder(resp.Body).Decode(out) } func (c *Client) State() (*player.State, error) { var state stateResponse err := c.get("core.playback.get_state", &state) if err != nil { return nil, err } var current currentResponse err = c.get("core.playback.get_current_track", ¤t) if err != nil { return nil, err } var position positionResponse err = c.get("core.playback.get_time_position", &position) if err != nil { return nil, err } var artist string for i, a := range current.Result.Artists { if i != 0 { artist += " " } artist += a.Name } query := artist + " " + current.Result.Name return &player.State{ ID: current.Result.URI, Query: query, Position: position.Result, Playing: state.Result == "playing", }, err } type requestBody struct { JsonRPC string `json:"jsonrpc"` ID int `json:"id"` Method string `json:"method"` } type currentResponse struct { Result struct { URI string `json:"uri"` Name string `json:"name"` Artists []struct { Name string `json:"name"` } `json:"artists"` } `json:"result"` } type stateResponse struct { Result string `json:"result"` } type positionResponse struct { Result int `json:"result"` } sptlrx-1.2.3/services/mpd/000077500000000000000000000000001477325515100154665ustar00rootroot00000000000000sptlrx-1.2.3/services/mpd/mpd.go000066400000000000000000000026041477325515100165770ustar00rootroot00000000000000package mpd import ( "github.com/raitonoberu/sptlrx/player" "strconv" "github.com/fhs/gompd/mpd" ) func New(address, password string) *Client { return &Client{ address: address, password: password, } } // Client implements player.Player type Client struct { address string password string client *mpd.Client } func (c *Client) connect() error { if c.client != nil { c.client.Close() } client, err := mpd.DialAuthenticated("tcp", c.address, c.password) if err != nil { c.client = nil return err } c.client = client return nil } func (c *Client) checkConnection() error { if c.client == nil || c.client.Ping() != nil { return c.connect() } return nil } func (c *Client) State() (*player.State, error) { if err := c.checkConnection(); err != nil { return nil, err } status, err := c.client.Status() if err != nil { return nil, err } current, err := c.client.CurrentSong() if err != nil { return nil, err } elapsed, _ := strconv.ParseFloat(status["elapsed"], 32) var title string if t, ok := current["Title"]; ok { title = t } var artist string if a, ok := current["Artist"]; ok { artist = a } var query string if artist != "" { query = artist + " " + title } else { query = title } return &player.State{ ID: status["songid"], Query: query, Playing: status["state"] == "play", Position: int(elapsed) * 1000, }, nil } sptlrx-1.2.3/services/mpris/000077500000000000000000000000001477325515100160405ustar00rootroot00000000000000sptlrx-1.2.3/services/mpris/mpris_unix.go000066400000000000000000000043351477325515100205710ustar00rootroot00000000000000//go:build !(windows || darwin) package mpris import ( "github.com/raitonoberu/sptlrx/player" "net/url" "path/filepath" "strings" "github.com/Pauloo27/go-mpris" "github.com/godbus/dbus/v5" ) func New(players []string) (*Client, error) { return &Client{players}, nil } // Client implements player.Player type Client struct { players []string } func (c *Client) getPlayer() (*mpris.Player, error) { conn, err := dbus.SessionBus() if err != nil { return nil, err } players, err := mpris.List(conn) if err != nil { return nil, err } if len(players) == 0 { return nil, nil } if len(c.players) == 0 { return mpris.New(conn, players[0]), nil } // iterating over configured whitelisted players for _, p := range c.players { // adding the D-Bus bus name prefix p := "org.mpris.MediaPlayer2." + p for _, player := range players { // check for the name with and without the instance suffix if p == player || strings.HasPrefix(player, p+".instance") { return mpris.New(conn, player), nil } } } return nil, nil } func (c *Client) State() (*player.State, error) { p, err := c.getPlayer() if err != nil { return nil, err } if p == nil { return nil, nil } status, err := p.GetPlaybackStatus() if err != nil { return nil, err } position, err := p.GetPosition() if err != nil { // unsupported player return nil, nil } meta, err := p.GetMetadata() if err != nil { return nil, err } var title string if t, ok := meta["xesam:title"].Value().(string); ok { title = t } // In case the player uses the file name with extension as title if u, ok := meta["xesam:url"].Value().(string); ok { u, err := url.Parse(u) if err == nil { ext := filepath.Ext(u.Path) title = strings.TrimSuffix(title, ext) } } var artist string switch a := meta["xesam:artist"].Value(); a.(type) { case string: artist = a.(string) case []string: artist = strings.Join(a.([]string), " ") } var query string if artist != "" { query = artist + " " + title } else { query = title } return &player.State{ ID: query, // use query as id since mpris:trackid is broken Query: query, Position: int(position * 1000), // secs to ms Playing: status == mpris.PlaybackPlaying, }, err } sptlrx-1.2.3/services/mpris/mpris_unsupported.go000066400000000000000000000005151477325515100221720ustar00rootroot00000000000000//go:build windows || darwin package mpris import ( "errors" "github.com/raitonoberu/sptlrx/player" ) func New(players []string) (*Client, error) { return nil, errors.New("darwin is not supported") } // Client implements player.Player type Client struct{} func (p *Client) State() (*player.State, error) { return nil, nil } sptlrx-1.2.3/services/spotify/000077500000000000000000000000001477325515100164035ustar00rootroot00000000000000sptlrx-1.2.3/services/spotify/spotify.go000066400000000000000000000023271477325515100204330ustar00rootroot00000000000000package spotify import ( "strings" "github.com/raitonoberu/lyricsapi/spotify" "github.com/raitonoberu/sptlrx/lyrics" "github.com/raitonoberu/sptlrx/player" ) var ErrInvalidCookie = spotify.ErrInvalidCookie func New(cookie string) (*Client, error) { if cookie == "" { return nil, ErrInvalidCookie } return &Client{spotify.NewClient(cookie)}, nil } // Client implements both player.Player and lyrics.Provider type Client struct { api *spotify.Client } func (c *Client) State() (*player.State, error) { result, err := c.api.State() if err != nil { return nil, err } if result == nil || result.Item == nil { return nil, nil } return &player.State{ ID: "spotify:" + result.Item.ID, Position: result.Progress, Playing: result.Playing, }, nil } func (c *Client) Lyrics(id, query string) ([]lyrics.Line, error) { var ( result []spotify.LyricsLine err error ) if strings.HasPrefix(id, "spotify:") { result, err = c.api.GetByID(id[8:]) } else { result, err = c.api.GetByName(query) } if err != nil { return nil, err } if len(result) == 0 { return nil, nil } lines := make([]lyrics.Line, len(result)) for i, l := range result { lines[i] = lyrics.Line(l) } return lines, nil } sptlrx-1.2.3/sptlrx.tape000066400000000000000000000003141477325515100152700ustar00rootroot00000000000000Output demo.gif Require sptlrx Set TypingSpeed 100ms Set FontSize 27 Set Padding 40 Set FontFamily "mononoki" Set Theme "Rose Pine" Set Width 800 Set Height 600 Type "sptlrx" Sleep 1s Enter Sleep 15s sptlrx-1.2.3/ui/000077500000000000000000000000001477325515100135005ustar00rootroot00000000000000sptlrx-1.2.3/ui/ui.go000066400000000000000000000077241477325515100144560ustar00rootroot00000000000000package ui import ( "github.com/raitonoberu/sptlrx/config" "github.com/raitonoberu/sptlrx/lyrics" "github.com/raitonoberu/sptlrx/pool" "os" "runtime" "strings" tea "github.com/charmbracelet/bubbletea" gloss "github.com/charmbracelet/lipgloss" "golang.org/x/term" ) type Model struct { Config *config.Config Channel chan pool.Update state pool.Update w, h int styleBefore gloss.Style styleCurrent gloss.Style styleAfter gloss.Style hAlignment gloss.Position } func (m *Model) Init() tea.Cmd { m.styleBefore = m.Config.Style.Before.Parse() m.styleCurrent = m.Config.Style.Current.Parse() m.styleAfter = m.Config.Style.After.Parse() switch m.Config.Style.HAlignment { case "left": m.hAlignment = 0 case "right": m.hAlignment = 1 default: m.hAlignment = 0.5 } return tea.Batch(waitForUpdate(m.Channel), tea.HideCursor) } func (m *Model) Update(message tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd switch msg := message.(type) { case tea.WindowSizeMsg: // does not work on Windows! m.w, m.h = msg.Width, msg.Height case pool.Update: m.state = msg if runtime.GOOS == "windows" { w, h, err := term.GetSize(int(os.Stdout.Fd())) if err == nil { m.w, m.h = w, h } } cmd = waitForUpdate(m.Channel) case tea.KeyMsg: switch msg.String() { case "q", "esc", "ctrl+c": cmd = tea.Quit case "left": m.hAlignment -= 0.5 if m.hAlignment < 0 { m.hAlignment = 0 } case "right": m.hAlignment += 0.5 if m.hAlignment > 1 { m.hAlignment = 1 } case "up": if m.state.Playing && lyrics.Timesynced(m.state.Lines) { break } m.state.Index -= 1 if m.state.Index < 0 { m.state.Index = 0 } case "down": if m.state.Playing && lyrics.Timesynced(m.state.Lines) { break } m.state.Index += 1 if m.state.Index >= len(m.state.Lines) { m.state.Index = len(m.state.Lines) - 1 } } } return m, cmd } func (m *Model) View() string { if m.w < 1 || m.h < 1 { return "" } if m.state.Err != nil && !m.Config.IgnoreErrors { return gloss.PlaceVertical( m.h, gloss.Center, m.styleCurrent. Align(gloss.Center). Width(m.w). Render(m.state.Err.Error()), ) } if len(m.state.Lines) == 0 { return "" } curLine := m.styleCurrent. Width(m.w). Align(m.hAlignment). Render(m.state.Lines[m.state.Index].Words) curLines := strings.Split(curLine, "\n") curLen := len(curLines) beforeLen := (m.h - curLen) / 2 afterLen := m.h - beforeLen - curLen lines := make([]string, beforeLen+curLen+afterLen) // fill lines before current var filledBefore int var beforeIndex = m.state.Index - 1 for filledBefore < beforeLen { index := beforeLen - filledBefore - 1 if index < 0 || beforeIndex < 0 { filledBefore += 1 continue } line := m.styleBefore. Width(m.w). Align(m.hAlignment). Render(m.state.Lines[beforeIndex].Words) beforeIndex -= 1 beforeLines := strings.Split(line, "\n") for i := len(beforeLines) - 1; i >= 0; i-- { lineIndex := index - i if lineIndex >= 0 { lines[lineIndex] = beforeLines[len(beforeLines)-1-i] } filledBefore += 1 } } // fill current lines var curIndex = beforeLen for i, line := range curLines { index := curIndex + i if index >= 0 && index < len(lines) { lines[index] = line } } // fill lines after current var filledAfter int var afterIndex = m.state.Index + 1 for filledAfter < afterLen { index := beforeLen + curLen + filledAfter if index >= len(lines) || afterIndex >= len(m.state.Lines) { filledAfter += 1 continue } line := m.styleAfter. Width(m.w). Align(m.hAlignment). Render(m.state.Lines[afterIndex].Words) afterIndex += 1 afterLines := strings.Split(line, "\n") for i, line := range afterLines { lineIndex := index + i if lineIndex < len(lines) { lines[lineIndex] = line } filledAfter += 1 } } return gloss.JoinVertical(m.hAlignment, lines...) } func waitForUpdate(ch chan pool.Update) tea.Cmd { return func() tea.Msg { return <-ch } }