pax_global_header00006660000000000000000000000064140510017220014502gustar00rootroot0000000000000052 comment=57b39f5a8e2e3af005a6d5609f820467426c7389 cava-0.7.4/000077500000000000000000000000001405100172200124245ustar00rootroot00000000000000cava-0.7.4/.clang-format000066400000000000000000000001351405100172200147760ustar00rootroot00000000000000BasedOnStyle: LLVM --- Language: Cpp PointerAlignment: Right ColumnLimit: 100 IndentWidth: 4 cava-0.7.4/.github/000077500000000000000000000000001405100172200137645ustar00rootroot00000000000000cava-0.7.4/.github/ISSUE_TEMPLATE/000077500000000000000000000000001405100172200161475ustar00rootroot00000000000000cava-0.7.4/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000017521405100172200206460ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **When/where was the bug introduced?** - Are you using cava from a package repository, like AUR? - If so, check out the master branch here, is your issue already resolved? - Don't know how to clone, compile source code? File report to package maintainer instead. - try using git bisect to find out where the bug was introduced. **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Set config parameter to 2. run 3. do something 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. macOS, Ubuntu] - Version [e.g. 22] **Terminal emulator** - name - version **Additional context** Add any other context about the problem here. cava-0.7.4/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011231405100172200216710ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. cava-0.7.4/.github/workflows/000077500000000000000000000000001405100172200160215ustar00rootroot00000000000000cava-0.7.4/.github/workflows/build.yml000066400000000000000000000021761405100172200176510ustar00rootroot00000000000000name: build on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: DoozyX/clang-format-lint-action@v0.5 build-linux: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Install dependencies run: | sudo apt-get update sudo apt-get install libfftw3-dev libasound2-dev libncursesw5-dev libpulse-dev libtool automake libiniparser-dev portaudio19-dev libsndio-dev - name: Generate configure run: ./autogen.sh - name: Run ./configure run: CPPFLAGS=-I/usr/include/iniparser ./configure - name: Run make run: make build-macos: runs-on: macos-latest steps: - uses: actions/checkout@v1 - name: Install dependencies run: | brew install fftw ncurses libtool automake portaudio iniparser ln -s /usr/local/bin/glibtoolize /usr/local/bin/libtoolize - name: Generate configure run: ./autogen.sh - name: Run ./configure run: LDFLAGS="-L/usr/local/opt/ncurses/lib" CPPFLAGS="-I/usr/local/opt/ncurses/include" ./configure - name: Run make run: make cava-0.7.4/.gitignore000066400000000000000000000006221405100172200144140ustar00rootroot00000000000000cava *.so *.so.0 *.o *.a .deps/ .libs/ Makefile Makefile.in aclocal.m4 ar-lib autom4te.cache/ compile config.guess config.log config.status config.sub configure depcomp iniparser/.libs/ iniparser/Makefile iniparser/Makefile.in iniparser/libiniparser.la iniparser/src/.deps/ iniparser/src/.dirstamp iniparser/src/dictionary.lo iniparser/src/iniparser.lo install-sh libtool ltmain.sh m4/ missing version cava-0.7.4/CONTRIBUTING.md000066400000000000000000000014011405100172200146510ustar00rootroot00000000000000# How to contribute Thank you for wanting to contribute to this project. In order to get the development of this project to run as smooth as possible, we will encourage all contributions to follw this simple process: 1. Before any pull request is submitted a github issue must be created for the task. 2. The new github task is to be opened for suggestions from other contributors. 3. A pull request is published. 4. Contributors code review pull request and approve/reject pull request. 5. Pull request either gets approved or rejected. 5. Github task is updated and everyone is notified. # Coding conventions * 4 spaces for indents * curly braces on same line as if, while, for statements Generally please try to keep the style consistent with the code as it is. cava-0.7.4/LICENSE000066400000000000000000000020721405100172200134320ustar00rootroot00000000000000Copyright (c) 2015 Karl Stavestrand 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. cava-0.7.4/Makefile.am000066400000000000000000000023711405100172200144630ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign if !SYSTEM_LIBINIPARSER SUBDIRS = iniparser endif ACLOCAL_AMFLAGS = -I m4 M_CPPFLAGS = -DSYSTEM_LIBINIPARSER=@SYSTEM_LIBINIPARSER@ bin_PROGRAMS = cava cava_SOURCES = cava.c config.c input/common.c input/fifo.c input/shmem.c \ output/terminal_noncurses.c output/raw.c cava_LDFLAGS = -L/usr/local/lib -Wl,-rpath /usr/local/lib cava_CPPFLAGS = -DPACKAGE=\"$(PACKAGE)\" -DVERSION=\"$(VERSION)\" \ -D_POSIX_SOURCE -D _POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE_EXTENDED \ -DFONTDIR=\"@FONT_DIR@\" cava_CFLAGS = -std=c99 -Wall -Werror -Wextra -Wno-unused-result -Wno-unknown-warning-option -Wno-maybe-uninitialized -Wno-vla-parameter if OSX cava_CFLAGS += -DNORT else cava_LDFLAGS += -lrt cava_font_dir = @FONT_DIR@ cava_font__DATA = cava.psf endif if ALSA cava_SOURCES += input/alsa.c endif if PORTAUDIO cava_SOURCES += input/portaudio.c endif if PULSE cava_SOURCES += input/pulse.c endif if SNDIO cava_SOURCES += input/sndio.c endif if NCURSES cava_SOURCES += output/terminal_ncurses.c endif if !SYSTEM_LIBINIPARSER cava_LDADD = -liniparser cava_SOURCES += iniparser/libiniparser.la cava_LDADD += -Liniparser/.libs cava_CPPFLAGS += -Iiniparser/src endif cava-0.7.4/README.md000066400000000000000000000431351405100172200137110ustar00rootroot00000000000000C.A.V.A. [![Build Status](https://github.com/karlstav/cava/workflows/build/badge.svg)](https://github.com/karlstav/cava/actions) ==================== **C**onsole-based **A**udio **V**isualizer for **A**LSA also supports audio input from Pulseaudio, fifo (mpd), sndio, squeezelite and portaudio. Now also works on macOS! by [Karl Stavestrand](mailto:karl@stavestrand.no) ![spectrum](https://github.com/karlstav/cava/blob/master/example_files/cava.gif "spectrum") [Demo video](https://youtu.be/9PSp8VA6yjU) **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [What it is](#what-it-is) - [Installing](#installing) - [From Source](#from-source) - [Installing Build Requirements](#installing-build-requirements) - [Building](#building) - [Installing](#installing-1) - [Uninstalling](#uninstalling) - [Some distro specific pre-made binaries/recipes](#some-distro-specific-pre-made-binariesrecipes) - [openSUSE](#opensuse) - [Fedora](#fedora) - [Arch](#arch) - [Ubuntu/Debian](#ubuntudebian) - [Capturing audio](#capturing-audio) - [Pulseaudio monitor source (Easy, default if supported)](#pulseaudio-monitor-source-easy-default-if-supported) - [ALSA-loopback device (Tricky)](#alsa-loopback-device-tricky) - [mpd's fifo output](#mpds-fifo-output) - [sndio](#sndio) - [squeezelite](#squeezelite) - [macOS](#macos) - [Windows - winscap - WSL](#Windows---winscap---WSL) - [Running via ssh](#running-via-ssh) - [Raw Output](#raw-output) - [Font notes](#font-notes) - [In ttys](#in-ttys) - [In terminal emulators](#in-terminal-emulators) - [Latency notes](#latency-notes) - [Usage](#usage) - [Controls](#controls) - [Configuration](#configuration) - [Contribution](#contribution) What it is ---------- C.A.V.A. is a bar spectrum audio visualizer for the Linux terminal using ALSA, pulseaudio or fifo buffer for input. This program is not intended for scientific use. It's written to look responsive and aesthetic when used to visualize music. Installing ------------------ ### From Source #### Installing Build Requirements Required components: * [FFTW](http://www.fftw.org/) * libtool * automake * build-essentials * [iniparser](https://github.com/ndevilla/iniparser) Recomended components: * [ncursesw dev files](http://www.gnu.org/software/ncurses/) (bundled in ncurses in arch) * [ALSA dev files](http://alsa-project.org/), or * [Pulseaudio dev files](http://freedesktop.org/software/pulseaudio/doxygen/), or * Portaudio, or * Sndio Only FFTW and the other build tools are actually required for CAVA to compile, but this will only give you the ability to read from fifo files. To more easly grab audio from your system pulseaudio, alsa, sndio or portaudio dev files are recommended (depending on what audio system you are using). Not sure how to get the pulseaudio dev files for other distros than debian/ubuntu or if they are bundled in pulseaudio. For better a better visual experience ncurses is also recomended. Iniparser is also required, but if it is not already installed, a bundled version will be used. All the requirements can be installed easily in all major distros: Debian Buster or higher/Ubuntu 18.04 or higher : apt install libfftw3-dev libasound2-dev libncursesw5-dev libpulse-dev libtool automake libiniparser-dev export CPPFLAGS=-I/usr/include/iniparser older Debian/Ubuntu: apt install libfftw3-dev libasound2-dev libncursesw5-dev libpulse-dev libtool automake ArchLinux: pacman -S base-devel fftw ncurses alsa-lib iniparser pulseaudio openSUSE: zypper install alsa-devel ncurses-devel fftw3-devel libpulse-devel libtool Fedora: dnf install alsa-lib-devel ncurses-devel fftw3-devel pulseaudio-libs-devel libtool macOS: First install homebrew if you have't already: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" Then install prerequisites: brew install fftw ncurses libtool automake portaudio Then fix macOS not finding libtool and ncursesw: export LIBTOOL=`which glibtool` export LIBTOOLIZE=`which glibtoolize` ln -s `which glibtoolize` /usr/local/bin/libtoolize ln -s /usr/lib/libncurses.dylib /usr/local/lib/libncursesw.dylib Tested on macOS High Sierra. For M1 Mac I was able to build all prerequisites from source. It might work with homebrew rosetta emulation, but what's the fun in that. * build and install automake, autoconf and libtool following the instructions [here](https://superuser.com/questions/383580/how-to-install-autoconf-automake-and-related-tools-on-mac-os-x-from-source). * build and install fftw from the gz archive [here](http://www.fftw.org/download.html) * download ncurses source and configure with these options: ``` ./configure --prefix=/usr/local \ --without-cxx --without-cxx-binding --without-ada --without-progs --with-curses-h \ --with-shared --without-debug \ --enable-widec --enable-const --enable-ext-colors --enable-sigwinch --enable-wgetch-events \ ``` * just clone portaudio repo, build and install. * install [Backround Music](https://github.com/kyleneideck/BackgroundMusic) following option 1 in "Installing from Source Code". (requires xcode) * then build cava normally and follow the instructions in "capturing audio" #### Building First of all clone this repo and cd in to it, then run: ./autogen.sh ./configure make If you have a recommended component installed, but do not wish to use it (perhaps if building a binary on one machine to be used on another), then the corresponding feature can be disabled during configuration (see configure --help for details). #### Installing Install `cava` to default `/usr/local`: make install Or you can change `PREFIX`, for example: ./configure --prefix=PREFIX #### Uninstalling make uninstall ### Some distro specific pre-made binaries/recipes #### openSUSE Tumbleweed users have cava in their repo. They can just use: zypper in cava Leap users need to add the multimedia:apps repository first: zypper ar -f obs://multimedia:apps/openSUSE_Leap_42.2 multimedia If you use another version just replace *openSUSE_Leap_42.2* with *openSUSE_13.2*, adjust it to your version. #### Fedora Cava is available in Fedora 26 and later. You can install Cava by running: dnf install cava #### Arch Cava is in [AUR](https://aur.archlinux.org/packages/cava/). pacaur -S cava #### Ubuntu/Debian ##### Ubuntu 20.10 or more recent / Debian (unstable) apt install cava ##### Older Ubuntu Harshal Sheth has added CAVA to his PPA, it can be installed with: add-apt-repository ppa:hsheth2/ppa apt update apt install cava All distro specific instalation sources might be out of date. Capturing audio --------------- ### Pulseaudio monitor source (Easy, default if supported) Just make sure you have installed pulseaudio dev files and that cava has been built with pulseaudio support (it should be automatically if the dev files are found). If you're lucky all you have to do is to run cava. If nothing happens you might have to use a different source than the default. The default might also be your microphone. Look at the [config](#configuration) file for help. ### ALSA-loopback device (Tricky) Set method = alsa in the [config](#configuration) file. ALSA can be difficult because there is no native way to grab audio from an output. If you want to capture audio straight fom the output (not just mic or line-in), you must create an ALSA loopback interface, then output the audio simultaneously to both the loopback and your normal interface. To create a loopback interface simply run: `sudo modprobe snd_aloop` Hopefully your `aplay -l` should now contain a loopback interface. To make it persistent across boot add the line `snd-aloop` to "/etc/modules". To keep it from being loaded as the first soundcard add the line `options snd-aloop index=1` to "/etc/modprobe.d/alsa-base.conf", this will load it at '1'. You can replace '1' with whatever makes most sense in your audio setup. Playing the audio through your Loopback interface makes it possible for cava to capture it, but there will be no sound in your speakers. In order to play audio on the loopback interface and your actual interface you must make use of the ALSA multi channel. Look at the included example file `example_files/etc/asound.conf` on how to use the multi channel. I was able to make this work on my laptop (an Asus UX31 running Ubuntu), but I had no luck with the ALSA method on my Raspberry Pi (Rasbian) with an USB DAC. The PulseAudio method however works perfectly on my Pi. Read more about the ALSA method [here](http://stackoverflow.com/questions/12984089/capture-playback-on-play-only-sound-card-with-alsa). If you are having problems with the alsa method on Rasberry PI, try enabling `mmap` by adding the following line to `/boot/config.txt` and reboot: ``` dtoverlay=i2s-mmap ``` ### mpd's fifo output Add these lines in mpd: audio_output { type "fifo" name "my_fifo" path "/tmp/mpd.fifo" format "44100:16:2" } Uncomment and change input method to `fifo` in the [config](#configuration) file. The path of the fifo can be specified with the `source` parameter. I had some trouble with sync (the visualizer was ahead of the sound). Reducing the ALSA buffer in mpd fixed it: audio_output { type "alsa" name "My ALSA" buffer_time "50000" # (50ms); default is 500000 microseconds (0.5s) } ### sndio sndio is the audio framework used on OpenBSD, but it's also available on FreeBSD and Linux. So far this is only tested on FreeBSD. To test it ```bash # Start sndiod with a monitor sub-device $ sndiod -dd -s default -m mon -s monitor # Set the AUDIODEVICE environment variable to override the default # sndio device and run cava $ AUDIODEVICE=snd/0.monitor cava ``` ### squeezelite [squeezelite](https://en.wikipedia.org/wiki/Squeezelite) is one of several software clients available for the Logitech Media Server. Squeezelite can export its audio data as shared memory, which is what this input module uses. Just adapt your [config](#configuration): ``` method = shmem source = /squeezelite-AA:BB:CC:DD:EE:FF ``` where `AA:BB:CC:DD:EE:FF` is squeezelite's MAC address (check the LMS Web GUI (Settings>Information) if unsure). Note: squeezelite must be started with the `-v` flag to enable visualizer support. ### macOS Note: Cava doesn't render correctly within the default macOS terminal. In order to achieve an optimal display, install [Kitty](https://sw.kovidgoyal.net/kitty/index.html). Beware that you may run in to the issue presented in #109; however, it can be resolved with [this](https://stackoverflow.com/questions/7165108/in-os-x-lion-lang-is-not-set-to-utf-8-how-to-fix-it). **Background Music** Install [Background Music](https://github.com/kyleneideck/BackgroundMusic) which provides a loopback interface automatically. Once installed and running just edit your [config](#configuration) to use this interface with portaudio: ``` method = portaudio source = "Background Music" ``` **Sound Flower** [Soundflower](https://github.com/mattingalls/Soundflower) also works to create a loopback interface. Use Audio MIDI Setup to configure a virtual interface that outputs audio to both your speakers and the loopback interface, following [this](https://github.com/RogueAmoeba/Soundflower-Original/issues/44#issuecomment-151586106) recipe. By creating a multi-output device you lose the ability to control the volume on your keyboard. Because of this, we recommend the Background Music app which still gives you keyboard controls. Then edit your [config](#configuration) to use this interface with portaudio: ``` method = portaudio source = "Soundflower (2ch)" ``` ### Windows - winscap - WSL @quantum5 has written a handy tool called [winscap](https://github.com/quantum5/winscap) to capture audio from Windows and output it to stdout. Just follow the instructions in the readme on how to set it up with cava. Running via ssh --------------- To run via ssh to an external monitor, redirect output to `/dev/console`: ~# ./cava <> /dev/console >&0 2>&1 exit with ctrl+z then run 'bg' to keep it running after you log out. (You must be root to redirect to console. Simple sudo is not enough: Run `sudo su` first.) ### Raw Output You can also use Cava's output for other programs by using raw output mode, which will write bar data to `STDOUT` that can be piped into other processes. More information on this option is documented in [the example config file](/example_files/config). A useful starting point example script written in python that consumes raw data can be found [here](https://github.com/karlstav/cava/issues/123#issuecomment-307891020). Font notes ---------- Since the graphics are simply based on characters, performance is dependent on the terminal font. ### In ttys If you run this in a TTY the program will change the font to the included `cava.psf` (actually a slightly modified "unifont"). In console fonts it seems that only 256 Unicode characters are supported, probably because they are bitmap fonts. I could not find a font with Unicode characters 2581-2587 (the 1/8 - 7/8 blocks used on the top of each bar to increase resolution). So in `cava.psf`, the characters 1-7 are actually replaced by Unicode characters 2581-2587. When cava exits, it changes the font back. If cava exits abnormally and you notice that 1-7 are replaced by partial blocks, just change the font with `setfont`. Actually, `setfont` is supposed to return the default font, but this usually isn't set. I haven't found another way to get the current font. So cava sets the font to "Lat2-Fixed16" when interrupted. All major distros should have it. It will revert to your default font at reboot. ### In terminal emulators In terminal emulators like `xterm`, the font settings is chosen in the software and cannot be changed by an application. So find your terminal settings and try out different fonts and settings. Also character spacing affects the look of the bar spectrum. Performance is also different, urxvt is the best I found so far, while Gnome-terminal is quite slow. Cava also disables the terminal cursor, and turns it back on on exit, but in case it terminates unexpectedly, run `setterm -cursor on` to get it back. Tip: Cava will look much nicer in small font sizes. Use a second terminal emulator for cava and set the font size to 1. Warning, can cause high CPU usage and latency if the terminal window is too large! Latency notes ------------- If you see latency issues (sound before image) in a terminal emulator, try increasing the font size. This will reduce the number of characters that have to be shown. If your audio device has a huge buffer, you might experience that cava is actually faster than the audio you hear. This reduces the experience of the visualization. To fix this, try decreasing the buffer settings in your audio playing software. Usage ----- Usage : cava [options] Visualize audio input in terminal. Options: -p path to config file -v print version Exit with ctrl+c or q. If cava quits unexpectedly or is force killed, echo must be turned on manually with `stty -echo`. ### Controls NOTE: only works in ncurses output mode. | Key | Description | | --- | ----------- | | up / down| increase/decrease sensitivity | | left / right| increase/decrease bar width | | f / b| change foreground/background color | | r | Reload configuration | | c | Reload colors only | | q or CTRL-C| Quit C.A.V.A. | Configuration ------------- As of version 0.4.0 all options are done in the config file, no more command-line arguments! By default a configuration file is located in `$XDG_CONFIG_HOME/cava/config` or `$HOME/.config/cava/config`, but cava can also be made to use a different file with the `-p` option. If for some reason the config file is not in the config dir, copy the [bundled configuration file](/example_files/config) to the config dir manually. Sending cava a SIGUSR1 signal, will force cava to reload its configuration file. Thus, it behaves as if the user pressed r in the terminal. One might send a SIGUSR1 signal using `pkill` or `killall`. For example: ``` $ pkill -USR1 cava ``` Similarly, sending cava a SIGUSR2 signal will only reload the colors from the configuration file, which is the same as pressing c in the terminal. This is slightly faster than reloading the entire config as the audio processing does not need to reinitialize. ``` $ pkill -USR2 cava ``` **Examples on how the equalizer works:** [eq] 1=0 2=1 3=0 4=1 5=0 ![3_138](https://cloud.githubusercontent.com/assets/6376571/8670183/a54a851e-29e8-11e5-9eff-346bf6ed91e0.png) [eq] 1=2 2=2 3=1 4=1 5=0.5 ![3_139](https://cloud.githubusercontent.com/assets/6376571/8670181/9db0ef50-29e8-11e5-81bc-3e2bb9892da0.png) Contribution ------ Please read CONTRIBUTING.md before opening a pull request. Thanks to: * [CelestialWalrus](https://github.com/CelestialWalrus) * [anko](https://github.com/anko) * [livibetter](https://github.com/livibetter) for major contributions in the early development of this project. Also thanks to [dpayne](https://github.com/dpayne/) for figuring out how to find the pulseaudio default sink name. cava-0.7.4/autogen.sh000077500000000000000000000006301405100172200144240ustar00rootroot00000000000000#!/bin/sh if [ -d .git ]; then git describe --always --tags --dirty > version # get version from git else echo 0.7.4 > version # hard coded versions fi libtoolize aclocal autoconf automake --add-missing CONFIGDIR=$XDG_CONFIG_HOME/cava if [ -z "$XDG_CONFIG_HOME" ]; then CONFIGDIR=$HOME/.config/cava; fi mkdir -p "$CONFIGDIR" [ -f "$CONFIGDIR"/config ] || cp example_files/config "$CONFIGDIR"/config cava-0.7.4/cava.c000066400000000000000000001303331405100172200135050ustar00rootroot00000000000000#include #ifdef HAVE_ALLOCA_H #include #else #include #endif #include #include #ifndef M_PI #define M_PI 3.1415926535897932385 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "util.h" #ifdef NCURSES #include "output/terminal_bcircle.h" #include "output/terminal_ncurses.h" #include #endif #include "output/raw.h" #include "output/terminal_noncurses.h" #include "input/alsa.h" #include "input/common.h" #include "input/fifo.h" #include "input/portaudio.h" #include "input/pulse.h" #include "input/shmem.h" #include "input/sndio.h" #include "config.h" #ifdef __GNUC__ // curses.h or other sources may already define #undef GCC_UNUSED #define GCC_UNUSED __attribute__((unused)) #else #define GCC_UNUSED /* nothing */ #endif pthread_mutex_t lock; // used by sig handler // needs to know output mode in order to clean up terminal int output_mode; // whether we should reload the config or not int should_reload = 0; // whether we should only reload colors or not int reload_colors = 0; // whether we should quit int should_quit = 0; // these variables are used only in main, but making them global // will allow us to not free them on exit without ASan complaining struct config_params p; fftw_complex *out_bass_l, *out_bass_r; fftw_plan p_bass_l, p_bass_r; fftw_complex *out_mid_l, *out_mid_r; fftw_plan p_mid_l, p_mid_r; fftw_complex *out_treble_l, *out_treble_r; fftw_plan p_treble_l, p_treble_r; // general: cleanup void cleanup(void) { if (output_mode == OUTPUT_NCURSES) { #ifdef NCURSES cleanup_terminal_ncurses(); #else ; #endif } else if (output_mode == OUTPUT_NONCURSES) { cleanup_terminal_noncurses(); } } // general: handle signals void sig_handler(int sig_no) { if (sig_no == SIGUSR1) { should_reload = 1; return; } if (sig_no == SIGUSR2) { reload_colors = 1; return; } cleanup(); if (sig_no == SIGINT) { printf("CTRL-C pressed -- goodbye\n"); } signal(sig_no, SIG_DFL); raise(sig_no); } #ifdef ALSA static bool is_loop_device_for_sure(const char *text) { const char *const LOOPBACK_DEVICE_PREFIX = "hw:Loopback,"; return strncmp(text, LOOPBACK_DEVICE_PREFIX, strlen(LOOPBACK_DEVICE_PREFIX)) == 0; } static bool directory_exists(const char *path) { DIR *const dir = opendir(path); if (dir == NULL) return false; closedir(dir); return true; } #endif int *monstercat_filter(int *bars, int number_of_bars, int waves, double monstercat) { int z; // process [smoothing]: monstercat-style "average" int m_y, de; if (waves > 0) { for (z = 0; z < number_of_bars; z++) { // waves bars[z] = bars[z] / 1.25; // if (bars[z] < 1) bars[z] = 1; for (m_y = z - 1; m_y >= 0; m_y--) { de = z - m_y; bars[m_y] = max(bars[z] - pow(de, 2), bars[m_y]); } for (m_y = z + 1; m_y < number_of_bars; m_y++) { de = m_y - z; bars[m_y] = max(bars[z] - pow(de, 2), bars[m_y]); } } } else if (monstercat > 0) { for (z = 0; z < number_of_bars; z++) { // if (bars[z] < 1)bars[z] = 1; for (m_y = z - 1; m_y >= 0; m_y--) { de = z - m_y; bars[m_y] = max(bars[z] / pow(monstercat, de), bars[m_y]); } for (m_y = z + 1; m_y < number_of_bars; m_y++) { de = m_y - z; bars[m_y] = max(bars[z] / pow(monstercat, de), bars[m_y]); } } } return bars; } // general: entry point int main(int argc, char **argv) { // general: console title printf("%c]0;%s%c", '\033', PACKAGE, '\007'); // general: handle command-line arguments char configPath[PATH_MAX]; configPath[0] = '\0'; // general: handle Ctrl+C struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_handler = &sig_handler; sigaction(SIGINT, &action, NULL); sigaction(SIGTERM, &action, NULL); sigaction(SIGUSR1, &action, NULL); sigaction(SIGUSR2, &action, NULL); char *usage = "\n\ Usage : " PACKAGE " [options]\n\ Visualize audio input in terminal. \n\ \n\ Options:\n\ -p path to config file\n\ -v print version\n\ \n\ Keys:\n\ Up Increase sensitivity\n\ Down Decrease sensitivity\n\ Left Decrease number of bars\n\ Right Increase number of bars\n\ r Reload config\n\ c Reload colors only\n\ f Cycle foreground color\n\ b Cycle background color\n\ q Quit\n\ \n\ as of 0.4.0 all options are specified in config file, see in '/home/username/.config/cava/' \n"; int c; while ((c = getopt(argc, argv, "p:vh")) != -1) { switch (c) { case 'p': // argument: fifo path snprintf(configPath, sizeof(configPath), "%s", optarg); break; case 'h': // argument: print usage printf("%s", usage); return 1; case '?': // argument: print usage printf("%s", usage); return 1; case 'v': // argument: print version printf(PACKAGE " " VERSION "\n"); return 0; default: // argument: no arguments; exit abort(); } } // general: main loop while (1) { debug("loading config\n"); // config: load struct error_s error; error.length = 0; if (!load_config(configPath, &p, 0, &error)) { fprintf(stderr, "Error loading config. %s", error.message); exit(EXIT_FAILURE); } bool first = true; int inAtty; output_mode = p.output; if (output_mode != OUTPUT_RAW) { // Check if we're running in a tty inAtty = 0; if (strncmp(ttyname(0), "/dev/tty", 8) == 0 || strcmp(ttyname(0), "/dev/console") == 0) inAtty = 1; // in macos vitual terminals are called ttys(xyz) and there are no ttys if (strncmp(ttyname(0), "/dev/ttys", 9) == 0) inAtty = 0; if (inAtty) { // checking if cava psf font is installed in FONTDIR FILE *font_file; font_file = fopen(FONTDIR "/cava.psf", "r"); if (font_file) { fclose(font_file); system("setfont " FONTDIR "/cava.psf >/dev/null 2>&1"); } else { // if not it might still be available, we dont know, must try system("setfont cava.psf >/dev/null 2>&1"); } system("setterm -blank 0"); } // We use unicode block characters to draw the bars and // the locale var LANG must be set to use unicode chars. // For some reason this var can't be retrieved with // setlocale(LANG, NULL), so we get it with getenv. // Also we can't set it with setlocale(LANG "") so we // must set LC_ALL instead. // Attempting to set to en_US if not set, if that lang // is not installed and LANG is not set there will be // no output, for more info see #109 #344 if (!getenv("LANG")) setlocale(LC_ALL, "en_US.utf8"); else setlocale(LC_ALL, ""); } // input: init int *bars_left, *bars_right; double *temp_l, *temp_r; int bass_cut_off = 150; int treble_cut_off = 2500; struct audio_data audio; memset(&audio, 0, sizeof(audio)); audio.source = malloc(1 + strlen(p.audio_source)); strcpy(audio.source, p.audio_source); audio.format = -1; audio.rate = 0; audio.FFTbassbufferSize = 4096; audio.FFTmidbufferSize = 2048; audio.FFTtreblebufferSize = 1024; audio.terminate = 0; if (p.stereo) audio.channels = 2; if (!p.stereo) audio.channels = 1; audio.average = false; audio.left = false; audio.right = false; if (strcmp(p.mono_option, "average") == 0) audio.average = true; if (strcmp(p.mono_option, "left") == 0) audio.left = true; if (strcmp(p.mono_option, "right") == 0) audio.right = true; audio.bass_index = 0; audio.mid_index = 0; audio.treble_index = 0; audio.bass_multiplier = (double *)malloc(audio.FFTbassbufferSize * sizeof(double)); audio.mid_multiplier = (double *)malloc(audio.FFTmidbufferSize * sizeof(double)); audio.treble_multiplier = (double *)malloc(audio.FFTtreblebufferSize * sizeof(double)); temp_l = (double *)malloc((audio.FFTbassbufferSize / 2 + 1) * sizeof(double)); temp_r = (double *)malloc((audio.FFTbassbufferSize / 2 + 1) * sizeof(double)); bars_left = (int *)malloc(256 * sizeof(int)); bars_right = (int *)malloc(256 * sizeof(int)); for (int i = 0; i < audio.FFTbassbufferSize; i++) { audio.bass_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (audio.FFTbassbufferSize - 1))); } for (int i = 0; i < audio.FFTmidbufferSize; i++) { audio.mid_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (audio.FFTmidbufferSize - 1))); } for (int i = 0; i < audio.FFTtreblebufferSize; i++) { audio.treble_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (audio.FFTtreblebufferSize - 1))); } // BASS // audio.FFTbassbufferSize = audio.rate / 20; // audio.FFTbassbufferSize; audio.in_bass_r = fftw_alloc_real(audio.FFTbassbufferSize); audio.in_bass_l = fftw_alloc_real(audio.FFTbassbufferSize); audio.in_bass_r_raw = fftw_alloc_real(audio.FFTbassbufferSize); audio.in_bass_l_raw = fftw_alloc_real(audio.FFTbassbufferSize); out_bass_l = fftw_alloc_complex(audio.FFTbassbufferSize / 2 + 1); out_bass_r = fftw_alloc_complex(audio.FFTbassbufferSize / 2 + 1); memset(out_bass_l, 0, (audio.FFTbassbufferSize / 2 + 1) * sizeof(fftw_complex)); memset(out_bass_r, 0, (audio.FFTbassbufferSize / 2 + 1) * sizeof(fftw_complex)); p_bass_l = fftw_plan_dft_r2c_1d(audio.FFTbassbufferSize, audio.in_bass_l, out_bass_l, FFTW_MEASURE); p_bass_r = fftw_plan_dft_r2c_1d(audio.FFTbassbufferSize, audio.in_bass_r, out_bass_r, FFTW_MEASURE); // MID // audio.FFTmidbufferSize = audio.rate / bass_cut_off; // audio.FFTbassbufferSize; audio.in_mid_r = fftw_alloc_real(audio.FFTmidbufferSize); audio.in_mid_l = fftw_alloc_real(audio.FFTmidbufferSize); audio.in_mid_r_raw = fftw_alloc_real(audio.FFTmidbufferSize); audio.in_mid_l_raw = fftw_alloc_real(audio.FFTmidbufferSize); out_mid_l = fftw_alloc_complex(audio.FFTmidbufferSize / 2 + 1); out_mid_r = fftw_alloc_complex(audio.FFTmidbufferSize / 2 + 1); memset(out_mid_l, 0, (audio.FFTmidbufferSize / 2 + 1) * sizeof(fftw_complex)); memset(out_mid_r, 0, (audio.FFTmidbufferSize / 2 + 1) * sizeof(fftw_complex)); p_mid_l = fftw_plan_dft_r2c_1d(audio.FFTmidbufferSize, audio.in_mid_l, out_mid_l, FFTW_MEASURE); p_mid_r = fftw_plan_dft_r2c_1d(audio.FFTmidbufferSize, audio.in_mid_r, out_mid_r, FFTW_MEASURE); // TRIEBLE // audio.FFTtreblebufferSize = audio.rate / treble_cut_off; // audio.FFTbassbufferSize; audio.in_treble_r = fftw_alloc_real(audio.FFTtreblebufferSize); audio.in_treble_l = fftw_alloc_real(audio.FFTtreblebufferSize); audio.in_treble_r_raw = fftw_alloc_real(audio.FFTtreblebufferSize); audio.in_treble_l_raw = fftw_alloc_real(audio.FFTtreblebufferSize); out_treble_l = fftw_alloc_complex(audio.FFTtreblebufferSize / 2 + 1); out_treble_r = fftw_alloc_complex(audio.FFTtreblebufferSize / 2 + 1); memset(out_treble_l, 0, (audio.FFTtreblebufferSize / 2 + 1) * sizeof(fftw_complex)); memset(out_treble_r, 0, (audio.FFTtreblebufferSize / 2 + 1) * sizeof(fftw_complex)); p_treble_l = fftw_plan_dft_r2c_1d(audio.FFTtreblebufferSize, audio.in_treble_l, out_treble_l, FFTW_MEASURE); p_treble_r = fftw_plan_dft_r2c_1d(audio.FFTtreblebufferSize, audio.in_treble_r, out_treble_r, FFTW_MEASURE); debug("got buffer size: %d, %d, %d", audio.FFTbassbufferSize, audio.FFTmidbufferSize, audio.FFTtreblebufferSize); reset_output_buffers(&audio); debug("starting audio thread\n"); pthread_t p_thread; int timeout_counter = 0; struct timespec timeout_timer = {.tv_sec = 0, .tv_nsec = 1000000}; int thr_id GCC_UNUSED; switch (p.input) { #ifdef ALSA case INPUT_ALSA: // input_alsa: wait for the input to be ready if (is_loop_device_for_sure(audio.source)) { if (directory_exists("/sys/")) { if (!directory_exists("/sys/module/snd_aloop/")) { cleanup(); fprintf(stderr, "Linux kernel module \"snd_aloop\" does not seem to be loaded.\n" "Maybe run \"sudo modprobe snd_aloop\".\n"); exit(EXIT_FAILURE); } } } thr_id = pthread_create(&p_thread, NULL, input_alsa, (void *)&audio); // starting alsamusic listener timeout_counter = 0; while (audio.format == -1 || audio.rate == 0) { nanosleep(&timeout_timer, NULL); timeout_counter++; if (timeout_counter > 2000) { cleanup(); fprintf(stderr, "could not get rate and/or format, problems with audio thread? " "quiting...\n"); exit(EXIT_FAILURE); } } debug("got format: %d and rate %d\n", audio.format, audio.rate); break; #endif case INPUT_FIFO: // starting fifomusic listener thr_id = pthread_create(&p_thread, NULL, input_fifo, (void *)&audio); audio.rate = p.fifoSample; audio.format = p.fifoSampleBits; break; #ifdef PULSE case INPUT_PULSE: if (strcmp(audio.source, "auto") == 0) { getPulseDefaultSink((void *)&audio); } // starting pulsemusic listener thr_id = pthread_create(&p_thread, NULL, input_pulse, (void *)&audio); audio.rate = 44100; break; #endif #ifdef SNDIO case INPUT_SNDIO: thr_id = pthread_create(&p_thread, NULL, input_sndio, (void *)&audio); audio.rate = 44100; break; #endif case INPUT_SHMEM: thr_id = pthread_create(&p_thread, NULL, input_shmem, (void *)&audio); timeout_counter = 0; while (audio.rate == 0) { nanosleep(&timeout_timer, NULL); timeout_counter++; if (timeout_counter > 2000) { cleanup(); fprintf(stderr, "could not get rate and/or format, problems with audio thread? " "quiting...\n"); exit(EXIT_FAILURE); } } debug("got format: %d and rate %d\n", audio.format, audio.rate); // audio.rate = 44100; break; #ifdef PORTAUDIO case INPUT_PORTAUDIO: thr_id = pthread_create(&p_thread, NULL, input_portaudio, (void *)&audio); audio.rate = 44100; break; #endif default: exit(EXIT_FAILURE); // Can't happen. } if (p.upper_cut_off > audio.rate / 2) { cleanup(); fprintf(stderr, "higher cuttoff frequency can't be higher than sample rate / 2"); exit(EXIT_FAILURE); } int bars[256]; int bars_mem[256]; int bars_last[256]; int previous_frame[256]; int fall[256]; float bars_peak[256]; int height, lines, width, remainder, fp; bool reloadConf = false; while (!reloadConf) { // jumping back to this loop means that you resized the screen for (int n = 0; n < 256; n++) { bars_last[n] = 0; previous_frame[n] = 0; fall[n] = 0; bars_peak[n] = 0; bars_mem[n] = 0; bars[n] = 0; } // frequencies on x axis require a bar width of four or more if (p.xaxis == FREQUENCY && p.bar_width < 4) p.bar_width = 4; switch (output_mode) { #ifdef NCURSES // output: start ncurses mode case OUTPUT_NCURSES: init_terminal_ncurses(p.color, p.bcolor, p.col, p.bgcol, p.gradient, p.gradient_count, p.gradient_colors, &width, &lines); if (p.xaxis != NONE) lines--; // we have 8 times as much height due to using 1/8 block characters height = lines * 8; break; #endif case OUTPUT_NONCURSES: get_terminal_dim_noncurses(&width, &lines); if (p.xaxis != NONE) lines--; init_terminal_noncurses(inAtty, p.col, p.bgcol, width, lines, p.bar_width); height = lines * 8; break; case OUTPUT_RAW: if (strcmp(p.raw_target, "/dev/stdout") != 0) { int fptest; // checking if file exists if (access(p.raw_target, F_OK) != -1) { // testopening in case it's a fifo fptest = open(p.raw_target, O_RDONLY | O_NONBLOCK, 0644); if (fptest == -1) { printf("could not open file %s for writing\n", p.raw_target); exit(1); } } else { printf("creating fifo %s\n", p.raw_target); if (mkfifo(p.raw_target, 0664) == -1) { printf("could not create fifo %s\n", p.raw_target); exit(1); } // fifo needs to be open for reading in order to write to it fptest = open(p.raw_target, O_RDONLY | O_NONBLOCK, 0644); } } fp = open(p.raw_target, O_WRONLY | O_NONBLOCK | O_CREAT, 0644); if (fp == -1) { printf("could not open file %s for writing\n", p.raw_target); exit(1); } printf("open file %s for writing raw output\n", p.raw_target); // width must be hardcoded for raw output. width = 256; if (strcmp(p.data_format, "binary") == 0) { height = pow(2, p.bit_format) - 1; } else { height = p.ascii_range; } break; default: exit(EXIT_FAILURE); // Can't happen. } // handle for user setting too many bars if (p.fixedbars) { p.autobars = 0; if (p.fixedbars * p.bar_width + p.fixedbars * p.bar_spacing - p.bar_spacing > width) p.autobars = 1; } // getting numbers of bars int number_of_bars = p.fixedbars; if (p.autobars == 1) number_of_bars = (width + p.bar_spacing) / (p.bar_width + p.bar_spacing); if (number_of_bars < 1) number_of_bars = 1; // must have at least 1 bars if (number_of_bars > 256) number_of_bars = 256; // cant have more than 256 bars if (p.stereo) { // stereo must have even numbers of bars if (number_of_bars % 2 != 0) number_of_bars--; } // checks if there is stil extra room, will use this to center remainder = (width - number_of_bars * p.bar_width - number_of_bars * p.bar_spacing + p.bar_spacing) / 2; if (remainder < 0) remainder = 0; // process [smoothing]: calculate gravity float g = p.gravity * ((float)height / 2160) * pow((60 / (float)p.framerate), 2.5); // calculate integral value, must be reduced with height double integral = p.integral; if (height > 320) integral = p.integral * 1 / sqrt((log10((float)height / 10))); #ifndef NDEBUG debug("height: %d width: %d bars:%d bar width: %d remainder: %d\n", height, width, number_of_bars, p.bar_width, remainder); #endif // process: calculate cutoff frequencies and eq if (p.stereo) number_of_bars = number_of_bars / 2; // in stereo only half number of number_of_bars per channel // for cutoff frequencies and eq calculation double userEQ_keys_to_bars_ratio; if (p.userEQ_enabled && (number_of_bars > 0)) { userEQ_keys_to_bars_ratio = (double)(((double)p.userEQ_keys) / ((double)number_of_bars)); } // calculate frequency constant (used to distribute bars across the frequency band) double frequency_constant = log10((float)p.lower_cut_off / (float)p.upper_cut_off) / (1 / ((float)number_of_bars + 1) - 1); float cut_off_frequency[256]; float upper_cut_off_frequency[256]; float relative_cut_off[256]; double center_frequencies[256]; int FFTbuffer_lower_cut_off[256]; int FFTbuffer_upper_cut_off[256]; double eq[256]; int bass_cut_off_bar = -1; int treble_cut_off_bar = -1; bool first_bar = true; int first_treble_bar = 0; int bar_buffer[number_of_bars + 1]; for (int n = 0; n < number_of_bars + 1; n++) { double bar_distribution_coefficient = frequency_constant * (-1); bar_distribution_coefficient += ((float)n + 1) / ((float)number_of_bars + 1) * frequency_constant; cut_off_frequency[n] = p.upper_cut_off * pow(10, bar_distribution_coefficient); if (n > 0) { if (cut_off_frequency[n - 1] >= cut_off_frequency[n] && cut_off_frequency[n - 1] > bass_cut_off) cut_off_frequency[n] = cut_off_frequency[n - 1] + (cut_off_frequency[n - 1] - cut_off_frequency[n - 2]); } relative_cut_off[n] = cut_off_frequency[n] / (audio.rate / 2); // remember nyquist!, per my calculations this should be rate/2 // and nyquist freq in M/2 but testing shows it is not... // or maybe the nq freq is in M/4 eq[n] = pow(cut_off_frequency[n], 1); // the numbers that come out of the FFT are verry high // the EQ is used to "normalize" them by dividing with this verry huge number eq[n] *= (float)height / pow(2, 28); if (p.userEQ_enabled) eq[n] *= p.userEQ[(int)floor(((double)n) * userEQ_keys_to_bars_ratio)]; eq[n] /= log2(audio.FFTbassbufferSize); if (cut_off_frequency[n] < bass_cut_off) { // BASS bar_buffer[n] = 1; FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (audio.FFTbassbufferSize / 2); bass_cut_off_bar++; treble_cut_off_bar++; if (bass_cut_off_bar > 0) first_bar = false; eq[n] *= log2(audio.FFTbassbufferSize); } else if (cut_off_frequency[n] > bass_cut_off && cut_off_frequency[n] < treble_cut_off) { // MID bar_buffer[n] = 2; FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (audio.FFTmidbufferSize / 2); treble_cut_off_bar++; if ((treble_cut_off_bar - bass_cut_off_bar) == 1) { first_bar = true; FFTbuffer_upper_cut_off[n - 1] = relative_cut_off[n] * (audio.FFTbassbufferSize / 2); } else { first_bar = false; } eq[n] *= log2(audio.FFTmidbufferSize); } else { // TREBLE bar_buffer[n] = 3; FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (audio.FFTtreblebufferSize / 2); first_treble_bar++; if (first_treble_bar == 1) { first_bar = true; FFTbuffer_upper_cut_off[n - 1] = relative_cut_off[n] * (audio.FFTmidbufferSize / 2); } else { first_bar = false; } eq[n] *= log2(audio.FFTtreblebufferSize); } if (n > 0) { if (!first_bar) { FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1; // pushing the spectrum up if the exponential function gets "clumped" in the // bass and caluclating new cut off frequencies if (FFTbuffer_lower_cut_off[n] <= FFTbuffer_lower_cut_off[n - 1]) { FFTbuffer_lower_cut_off[n] = FFTbuffer_lower_cut_off[n - 1] + 1; FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1; if (bar_buffer[n] == 1) relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) / ((float)audio.FFTbassbufferSize / 2); else if (bar_buffer[n] == 2) relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) / ((float)audio.FFTmidbufferSize / 2); else if (bar_buffer[n] == 3) relative_cut_off[n] = (float)(FFTbuffer_lower_cut_off[n]) / ((float)audio.FFTtreblebufferSize / 2); cut_off_frequency[n] = relative_cut_off[n] * ((float)audio.rate / 2); } } else { if (FFTbuffer_upper_cut_off[n - 1] <= FFTbuffer_lower_cut_off[n - 1]) FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n - 1] + 1; } upper_cut_off_frequency[n - 1] = cut_off_frequency[n]; // high_relative_cut_off * ((float)audio.rate / 2); center_frequencies[n - 1] = pow((cut_off_frequency[n - 1] * upper_cut_off_frequency[n - 1]), 0.5); } #ifndef NDEBUG initscr(); curs_set(0); timeout(0); if (n != 0) { mvprintw(n, 0, "%d: %f -> %f (%d -> %d) bass: %d, treble:%d \n", n, cut_off_frequency[n - 1], cut_off_frequency[n], FFTbuffer_lower_cut_off[n - 1], FFTbuffer_upper_cut_off[n - 1], bass_cut_off_bar, treble_cut_off_bar); } #endif } if (p.stereo) number_of_bars = number_of_bars * 2; // process: calculate x axis values int x_axis_info = 0; if (p.xaxis != NONE) { x_axis_info = 1; double center_frequency; if (output_mode == OUTPUT_NONCURSES) { printf("\r\033[%dB", lines + 1); if (remainder) printf("\033[%dC", remainder); } for (int n = 0; n < number_of_bars; n++) { if (p.stereo) { if (n < number_of_bars / 2) center_frequency = center_frequencies[number_of_bars / 2 - 1 - n]; else center_frequency = center_frequencies[n - number_of_bars / 2]; } else { center_frequency = center_frequencies[n]; } float freq_kilohz = center_frequency / 1000; int freq_floor = center_frequency; if (output_mode == OUTPUT_NCURSES) { #ifdef NCURSES if (center_frequency < 1000) mvprintw(lines, n * (p.bar_width + p.bar_spacing) + remainder, "%-4d", freq_floor); else if (center_frequency > 1000 && center_frequency < 10000) mvprintw(lines, n * (p.bar_width + p.bar_spacing) + remainder, "%.2f", freq_kilohz); else mvprintw(lines, n * (p.bar_width + p.bar_spacing) + remainder, "%.1f", freq_kilohz); #endif } else if (output_mode == OUTPUT_NONCURSES) { if (center_frequency < 1000) printf("%-4d", freq_floor); else if (center_frequency > 1000 && center_frequency < 10000) printf("%.2f", freq_kilohz); else printf("%.1f", freq_kilohz); if (n < number_of_bars - 1) printf("\033[%dC", p.bar_width + p.bar_spacing - 4); } } printf("\r\033[%dA", lines + 1); } bool resizeTerminal = false; struct timespec framerate_timer = {.tv_sec = 0, .tv_nsec = 0}; if (p.framerate <= 1) { framerate_timer.tv_sec = 1 / (float)p.framerate; } else { framerate_timer.tv_sec = 0; framerate_timer.tv_nsec = (1 / (float)p.framerate) * 1e9; } int sleep_counter = 0; bool silence = false; char ch = '\0'; #ifndef NDEBUG int maxvalue = 0; int minvalue = 0; #endif struct timespec sleep_mode_timer = {.tv_sec = 1, .tv_nsec = 0}; while (!resizeTerminal) { // general: keyboard controls #ifdef NCURSES if (output_mode == OUTPUT_NCURSES) ch = getch(); #endif /* // disabled key controls in non-curses mode, caused garbage on screen if (output_mode == OUTPUT_NONCURSES) ch = fgetc(stdin); */ switch (ch) { case 65: // key up p.sens = p.sens * 1.05; break; case 66: // key down p.sens = p.sens * 0.95; break; case 68: // key right p.bar_width++; resizeTerminal = true; break; case 67: // key left if (p.bar_width > 1) p.bar_width--; resizeTerminal = true; break; case 'r': // reload config should_reload = 1; break; case 'c': // reload colors reload_colors = 1; break; case 'f': // change forground color if (p.col < 7) p.col++; else p.col = 0; resizeTerminal = true; break; case 'b': // change backround color if (p.bgcol < 7) p.bgcol++; else p.bgcol = 0; resizeTerminal = true; break; case 'q': should_reload = 1; should_quit = 1; } if (should_reload) { reloadConf = true; resizeTerminal = true; should_reload = 0; } if (reload_colors) { struct error_s error; error.length = 0; if (!load_config(configPath, (void *)&p, 1, &error)) { cleanup(); fprintf(stderr, "Error loading config. %s", error.message); exit(EXIT_FAILURE); } resizeTerminal = true; reload_colors = 0; } #ifndef NDEBUG // clear(); refresh(); #endif // process: check if input is present silence = true; for (int n = 0; n < audio.FFTbassbufferSize; n++) { if (audio.in_bass_l[n] || audio.in_bass_r[n]) { silence = false; break; } } if (p.sleep_timer) { if (silence && sleep_counter <= p.framerate * p.sleep_timer) sleep_counter++; else if (!silence) sleep_counter = 0; if (sleep_counter > p.framerate * p.sleep_timer) { #ifndef NDEBUG printw("no sound detected for 30 sec, going to sleep mode\n"); #endif nanosleep(&sleep_mode_timer, NULL); continue; } } // process: execute FFT and sort frequency bands pthread_mutex_lock(&lock); fftw_execute(p_bass_l); fftw_execute(p_mid_l); fftw_execute(p_treble_l); if (p.stereo) { fftw_execute(p_bass_r); fftw_execute(p_mid_r); fftw_execute(p_treble_r); number_of_bars /= 2; } pthread_mutex_unlock(&lock); // process: separate frequency bands for (int n = 0; n < number_of_bars; n++) { temp_l[n] = 0; if (p.stereo) temp_r[n] = 0; // process: add upp FFT values within bands for (int i = FFTbuffer_lower_cut_off[n]; i <= FFTbuffer_upper_cut_off[n]; i++) { if (n <= bass_cut_off_bar) { temp_l[n] += hypot(out_bass_l[i][0], out_bass_l[i][1]); if (p.stereo) temp_r[n] += hypot(out_bass_r[i][0], out_bass_r[i][1]); } else if (n > bass_cut_off_bar && n <= treble_cut_off_bar) { temp_l[n] += hypot(out_mid_l[i][0], out_mid_l[i][1]); if (p.stereo) temp_r[n] += hypot(out_mid_r[i][0], out_mid_r[i][1]); } else if (n > treble_cut_off_bar) { temp_l[n] += hypot(out_treble_l[i][0], out_treble_l[i][1]); if (p.stereo) temp_r[n] += hypot(out_treble_r[i][0], out_treble_r[i][1]); } } // getting average multiply with sens and eq temp_l[n] /= FFTbuffer_upper_cut_off[n] - FFTbuffer_lower_cut_off[n] + 1; temp_l[n] *= p.sens * eq[n]; if (temp_l[n] <= p.ignore) temp_l[n] = 0; bars_left[n] = temp_l[n]; if (p.stereo) { temp_r[n] /= FFTbuffer_upper_cut_off[n] - FFTbuffer_lower_cut_off[n] + 1; temp_r[n] *= p.sens * eq[n]; if (temp_r[n] <= p.ignore) temp_r[n] = 0; bars_right[n] = temp_r[n]; } } if (p.stereo) number_of_bars *= 2; // process [filter] if (p.monstercat) { if (p.stereo) { bars_left = monstercat_filter(bars_left, number_of_bars / 2, p.waves, p.monstercat); bars_right = monstercat_filter(bars_right, number_of_bars / 2, p.waves, p.monstercat); } else { bars_left = monstercat_filter(bars_left, number_of_bars, p.waves, p.monstercat); } } // processing signal bool senselow = true; for (int n = 0; n < number_of_bars; n++) { // mirroring stereo channels if (p.stereo) { if (n < number_of_bars / 2) { bars[n] = bars_left[number_of_bars / 2 - n - 1]; } else { bars[n] = bars_right[n - number_of_bars / 2]; } } else { bars[n] = bars_left[n]; } // process [smoothing]: falloff if (g > 0) { if (bars[n] < bars_last[n]) { bars[n] = bars_peak[n] - (g * fall[n] * fall[n]); if (bars[n] < 0) bars[n] = 0; fall[n]++; } else { bars_peak[n] = bars[n]; fall[n] = 0; } bars_last[n] = bars[n]; } // process [smoothing]: integral if (p.integral > 0) { bars[n] = bars_mem[n] * integral + bars[n]; bars_mem[n] = bars[n]; int diff = height - bars[n]; if (diff < 0) diff = 0; double div = 1 / (diff + 1); // bars[n] = bars[n] - pow(div, 10) * (height + 1); bars_mem[n] = bars_mem[n] * (1 - div / 20); } #ifndef NDEBUG mvprintw(n, 0, "%d: f:%f->%f (%d->%d), eq:\ %15e, peak:%d \n", n, cut_off_frequency[n], cut_off_frequency[n + 1], FFTbuffer_lower_cut_off[n], FFTbuffer_upper_cut_off[n], eq[n], bars[n]); if (bars[n] < minvalue) { minvalue = bars[n]; debug("min value: %d\n", minvalue); // checking maxvalue 10000 } if (bars[n] > maxvalue) { maxvalue = bars[n]; } if (bars[n] < 0) { debug("negative bar value!! %d\n", bars[n]); // exit(EXIT_FAILURE); // Can't happen. } #endif // zero values causes divided by zero segfault (if not raw) if (output_mode != OUTPUT_RAW && bars[n] < 1) bars[n] = 1; // automatic sense adjustment if (p.autosens && !silence) { if (bars[n] > height && senselow) { p.sens = p.sens * 0.98; senselow = false; first = false; } } } if (p.autosens && !silence && senselow) { p.sens = p.sens * 1.001; if (first) p.sens = p.sens * 1.1; } #ifndef NDEBUG mvprintw(number_of_bars + 1, 0, "sensitivity %.10e", p.sens); mvprintw(number_of_bars + 2, 0, "min value: %d\n", minvalue); // checking maxvalue 10000 mvprintw(number_of_bars + 3, 0, "max value: %d\n", maxvalue); // checking maxvalue 10000 (void)x_axis_info; #endif // output: draw processed input #ifdef NDEBUG int rc; switch (output_mode) { case OUTPUT_NCURSES: #ifdef NCURSES rc = draw_terminal_ncurses(inAtty, lines, width, number_of_bars, p.bar_width, p.bar_spacing, remainder, bars, previous_frame, p.gradient, x_axis_info); break; #endif case OUTPUT_NONCURSES: rc = draw_terminal_noncurses(inAtty, lines, width, number_of_bars, p.bar_width, p.bar_spacing, remainder, bars, previous_frame, x_axis_info); break; case OUTPUT_RAW: rc = print_raw_out(number_of_bars, fp, p.is_bin, p.bit_format, p.ascii_range, p.bar_delim, p.frame_delim, bars); break; default: exit(EXIT_FAILURE); // Can't happen. } // terminal has been resized breaking to recalibrating values if (rc == -1) resizeTerminal = true; #endif memcpy(previous_frame, bars, 256 * sizeof(int)); // checking if audio thread has exited unexpectedly if (audio.terminate == 1) { cleanup(); fprintf(stderr, "Audio thread exited unexpectedly. %s\n", audio.error_message); exit(EXIT_FAILURE); } nanosleep(&framerate_timer, NULL); } // resize terminal } // reloading config //**telling audio thread to terminate**// audio.terminate = 1; pthread_join(p_thread, NULL); if (p.userEQ_enabled) free(p.userEQ); free(audio.source); fftw_free(audio.in_bass_r); fftw_free(audio.in_bass_l); fftw_free(out_bass_r); fftw_free(out_bass_l); fftw_destroy_plan(p_bass_l); fftw_destroy_plan(p_bass_r); fftw_free(audio.in_mid_r); fftw_free(audio.in_mid_l); fftw_free(out_mid_r); fftw_free(out_mid_l); fftw_destroy_plan(p_mid_l); fftw_destroy_plan(p_mid_r); fftw_free(audio.in_treble_r); fftw_free(audio.in_treble_l); fftw_free(out_treble_r); fftw_free(out_treble_l); fftw_destroy_plan(p_treble_l); fftw_destroy_plan(p_treble_r); cleanup(); if (should_quit) return EXIT_SUCCESS; // fclose(fp); } } cava-0.7.4/cava.psf000066400000000000000000000113461405100172200140550ustar00rootroot00000000000000rµJ† ~BBBBBBBB~ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$$ÿÿÿÿÿÿçÛÛçÿÿÿÿÿÿ 8DDDD88DDDD8|>"> À~B~BBBBBBD€’T8î8T’ÀðüÿüðÀ?ÿ?8TT8$$$$$$$$$~’’’’r8D@0HDD$D8~~~~8TT8|8TT8þ @þ@ @@@@@~$BÿB$88||þþþþ||88$$$$$$~$$~$$$|’|’|d”h ,RL$$0JDDD:   $~$| ~ @@8  @ ~~@  @BBB>@@@|BBBBB|BBBBB>BBBBB><@@@|BBBBBB08 DD8@@@BDHpHDB08ü’’’’’’|BBBBBBBBBBB>^`@@@@@>@@<||BBBBBB>BBB$$‚‚’’’’|BB$$BBBBBBBB><~ @~   00b’Œ(D‚‚‚‚þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿDDD$ 2L2L >  |`$$$<|(((((((((((((((($$BBB><@@|BBBBB|BBBBBB?>BBBBB><$BBBBBB>BDHpHDB"""""B‚ƪ’‚‚‚BBB~BBBBB>"B|BBBBB|@@@<’’T8T’’8DDH|BBBB|@@xDDDx‚‚òŠŠŠò` <"""<ÿÿÿÿ(((((((/((((((((((((((/ ?? /(((((((((((((ïÿÿï(((((((((((((/ /(((((((ÿÿ((((((ïï(((((((ÿÿ(((((((ÿ88DD88(((((((?BBBB> "B|BBBB|@@@@<’’’T8T’’’’|BBB|BBBB|@@@|BBBBB|‚‚‚òŠŠŠŠŠòÀ@@|BBBBB|�ÿÿÿÿÿÿÿÿÿâ—‹ÿâ—™ÿ♂ÿ♀ÿ♪ÿ♫♬ÿ☼ÿâ–¶â–ºÿ◀◄ÿ↕ÿ‼ÿ¶ÿ§ÿâ–¬ÿ↨ÿ↑ÿ↓ÿ→ÿâ†ÿ∟ÿ↔ÿâ–²ÿâ–¼ÿ ÿ!ÿ"ÿ#ÿ$ÿ%ÿ&ÿ'ÿ(ÿ)ÿ*ÿ+ÿ,ÿ-ÿ.ÿ/ÿ0ÿ1ÿ2ÿ3ÿ4ÿ5ÿ6ÿ7ÿ8ÿ9ÿ:ÿ;ÿ<ÿ=ÿ>ÿ?ÿ@ÿÿÿÿÿÿÿÿÿIÿJÿKÿLÿMÿNÿOÿPÿQÿRÿSÿTÿUÿVÿWÿXÿYÿZÿ[ÿ\ÿ]ÿ^ÿ_ÿ`ÿaÿbÿcÿdÿeÿfÿgÿhÿiÿjÿkÿlÿmÿnÿoÿpÿqÿrÿsÿtÿuÿvÿwÿxÿyÿzÿ{ÿ|ÿ}ÿ~ÿ⌂ÿ│ÿÿÿÿÿÿÿÿÿ√ÿ≈ÿ≤ÿ≥ÿ ÿ⌡ÿ°ÿ²ÿ·ÿ÷ÿâ•‘ÿÑ‘ÿÑ–ÿÑ—ÿâ•—ÿâ•›ÿÒ‘ÿâ•ÿâ•¡ÿÐÿЄÿâ•£ÿ©ÿÑŽÿаÿбÿцÿдÿеÿÑ„ÿгÿÑ…ÿиÿйÿкÿлÿмÿнÿоÿпπÿÑÿÑ€ÿÑÿÑ‚ÿуÿжÿвÿÑŒÿÑ‹ÿзÿшÿÑÿщÿчÿÑŠÿâ””ÿâ”´ÿ┬ÿ├ÿ─ÿ┼ÿ╞ÿ╟ÿ╚ÿâ•”ÿâ•©ÿ╦ÿâ• ÿâ•ÿ╬ÿâ•§ÿ╨ÿІÿЇÿâ•™ÿ╘ÿâ•’ÿÑ”ÿÒÿ╪ÿ┘ÿ┌ÿâ–ˆÿâ–„ÿâ–Œÿâ–ÿâ–€ÿЮÿÐÿБÿЦÿДÿЕÿФÿГÿÐ¥ÿИÿЙÿКÿЛÿМÿÐÿОÿПÿЯÿРÿСÿТÿУÿЖÿÐ’ÿЬÿЫÿЗÿШÿЭÿЩÿЧÿЪÿcava-0.7.4/config.c000066400000000000000000000444611405100172200140460ustar00rootroot00000000000000#include "config.h" #include "util.h" #include #include #include #ifdef SNDIO #include #endif #include #include #include double smoothDef[5] = {1, 1, 1, 1, 1}; enum input_method default_methods[] = { INPUT_FIFO, INPUT_PORTAUDIO, INPUT_ALSA, INPUT_PULSE, }; char *outputMethod, *channels, *xaxisScale; const char *input_method_names[] = { "fifo", "portaudio", "alsa", "pulse", "sndio", "shmem", }; const bool has_input_method[] = { true, /** Always have at least FIFO and shmem input. */ HAS_PORTAUDIO, HAS_ALSA, HAS_PULSE, HAS_SNDIO, true, }; enum input_method input_method_by_name(const char *str) { for (int i = 0; i < INPUT_MAX; i++) { if (!strcmp(str, input_method_names[i])) { return (enum input_method)i; } } return INPUT_MAX; } void write_errorf(void *err, const char *fmt, ...) { struct error_s *error = (struct error_s *)err; va_list args; va_start(args, fmt); error->length += vsnprintf((char *)error->message + error->length, MAX_ERROR_LEN - error->length, fmt, args); va_end(args); } int validate_color(char *checkColor, void *params, void *err) { struct config_params *p = (struct config_params *)params; struct error_s *error = (struct error_s *)err; int validColor = 0; if (checkColor[0] == '#' && strlen(checkColor) == 7) { // If the output mode is not ncurses, tell the user to use a named colour instead of hex // colours. if (p->output != OUTPUT_NCURSES) { #ifdef NCURSES write_errorf(error, "hex color configured, but ncurses not set. Forcing ncurses mode.\n"); p->output = OUTPUT_NCURSES; #else write_errorf(error, "Only 'ncurses' output method supports HTML colors " "(required by gradient). " "Cava was built without ncurses support, install ncurses(w) dev files " "and rebuild.\n"); return 0; #endif } // 0 to 9 and a to f for (int i = 1; checkColor[i]; ++i) { if (!isdigit(checkColor[i])) { if (tolower(checkColor[i]) >= 'a' && tolower(checkColor[i]) <= 'f') { validColor = 1; } else { validColor = 0; break; } } else { validColor = 1; } } } else { if ((strcmp(checkColor, "black") == 0) || (strcmp(checkColor, "red") == 0) || (strcmp(checkColor, "green") == 0) || (strcmp(checkColor, "yellow") == 0) || (strcmp(checkColor, "blue") == 0) || (strcmp(checkColor, "magenta") == 0) || (strcmp(checkColor, "cyan") == 0) || (strcmp(checkColor, "white") == 0) || (strcmp(checkColor, "default") == 0)) validColor = 1; } return validColor; } bool validate_colors(void *params, void *err) { struct config_params *p = (struct config_params *)params; struct error_s *error = (struct error_s *)err; // validate: color if (!validate_color(p->color, p, error)) { write_errorf(error, "The value for 'foreground' is invalid. It can be either one of the 7 " "named colors or a HTML color of the form '#xxxxxx'.\n"); return false; } // validate: background color if (!validate_color(p->bcolor, p, error)) { write_errorf(error, "The value for 'background' is invalid. It can be either one of the 7 " "named colors or a HTML color of the form '#xxxxxx'.\n"); return false; } if (p->gradient) { for (int i = 0; i < p->gradient_count; i++) { if (!validate_color(p->gradient_colors[i], p, error)) { write_errorf( error, "Gradient color %d is invalid. It must be HTML color of the form '#xxxxxx'.\n", i + 1); return false; } } } // In case color is not html format set bgcol and col to predefinedint values p->col = -1; if (strcmp(p->color, "black") == 0) p->col = 0; if (strcmp(p->color, "red") == 0) p->col = 1; if (strcmp(p->color, "green") == 0) p->col = 2; if (strcmp(p->color, "yellow") == 0) p->col = 3; if (strcmp(p->color, "blue") == 0) p->col = 4; if (strcmp(p->color, "magenta") == 0) p->col = 5; if (strcmp(p->color, "cyan") == 0) p->col = 6; if (strcmp(p->color, "white") == 0) p->col = 7; // default if invalid // validate: background color if (strcmp(p->bcolor, "black") == 0) p->bgcol = 0; if (strcmp(p->bcolor, "red") == 0) p->bgcol = 1; if (strcmp(p->bcolor, "green") == 0) p->bgcol = 2; if (strcmp(p->bcolor, "yellow") == 0) p->bgcol = 3; if (strcmp(p->bcolor, "blue") == 0) p->bgcol = 4; if (strcmp(p->bcolor, "magenta") == 0) p->bgcol = 5; if (strcmp(p->bcolor, "cyan") == 0) p->bgcol = 6; if (strcmp(p->bcolor, "white") == 0) p->bgcol = 7; // default if invalid return true; } bool validate_config(struct config_params *p, struct error_s *error) { // validate: output method p->output = OUTPUT_NOT_SUPORTED; if (strcmp(outputMethod, "ncurses") == 0) { p->output = OUTPUT_NCURSES; p->bgcol = -1; #ifndef NCURSES write_errorf(error, "cava was built without ncurses support, install ncursesw dev files " "and run make clean && ./configure && make again\n"); return false; #endif } if (strcmp(outputMethod, "noncurses") == 0) { p->output = OUTPUT_NONCURSES; p->bgcol = 0; } if (strcmp(outputMethod, "raw") == 0) { // raw: p->output = OUTPUT_RAW; p->bar_spacing = 0; p->bar_width = 1; // checking data format p->is_bin = -1; if (strcmp(p->data_format, "binary") == 0) { p->is_bin = 1; // checking bit format: if (p->bit_format != 8 && p->bit_format != 16) { write_errorf( error, "bit format %d is not supported, supported data formats are: '8' and '16'\n", p->bit_format); return false; } } else if (strcmp(p->data_format, "ascii") == 0) { p->is_bin = 0; if (p->ascii_range < 1) { write_errorf(error, "ascii max value must be a positive integer\n"); return false; } } else { write_errorf(error, "data format %s is not supported, supported data formats are: 'binary' " "and 'ascii'\n", p->data_format); return false; } } if (p->output == OUTPUT_NOT_SUPORTED) { #ifndef NCURSES write_errorf( error, "output method %s is not supported, supported methods are: 'noncurses' and 'raw'\n", outputMethod); return false; #endif #ifdef NCURSES write_errorf(error, "output method %s is not supported, supported methods are: 'ncurses', " "'noncurses' and 'raw'\n", outputMethod); return false; #endif } p->xaxis = NONE; if (strcmp(xaxisScale, "none") == 0) { p->xaxis = NONE; } if (strcmp(xaxisScale, "frequency") == 0) { p->xaxis = FREQUENCY; } if (strcmp(xaxisScale, "note") == 0) { p->xaxis = NOTE; } // validate: output channels p->stereo = -1; if (strcmp(channels, "mono") == 0) { p->stereo = 0; if (strcmp(p->mono_option, "average") != 0 && strcmp(p->mono_option, "left") != 0 && strcmp(p->mono_option, "right") != 0) { write_errorf(error, "mono option %s is not supported, supported options are: 'average', " "'left' or 'right'\n", p->mono_option); return false; } } if (strcmp(channels, "stereo") == 0) p->stereo = 1; if (p->stereo == -1) { write_errorf( error, "output channels %s is not supported, supported channelss are: 'mono' and 'stereo'\n", channels); return false; } // validate: bars p->autobars = 1; if (p->fixedbars > 0) p->autobars = 0; if (p->fixedbars > 256) p->fixedbars = 256; if (p->bar_width > 256) p->bar_width = 256; if (p->bar_width < 1) p->bar_width = 1; // validate: framerate if (p->framerate < 0) { write_errorf(error, "framerate can't be negative!\n"); return false; } // validate: colors if (!validate_colors(p, error)) { return false; } // validate: gravity p->gravity = p->gravity / 100; if (p->gravity < 0) { p->gravity = 0; } // validate: integral p->integral = p->integral / 100; if (p->integral < 0) { p->integral = 0; } else if (p->integral > 1) { p->integral = 1; } // validate: cutoff if (p->lower_cut_off == 0) p->lower_cut_off++; if (p->lower_cut_off > p->upper_cut_off) { write_errorf(error, "lower cutoff frequency can't be higher than higher cutoff frequency\n"); return false; } // setting sens p->sens = p->sens / 100; return true; } bool load_colors(struct config_params *p, dictionary *ini, void *err) { struct error_s *error = (struct error_s *)err; free(p->color); free(p->bcolor); p->color = strdup(iniparser_getstring(ini, "color:foreground", "default")); p->bcolor = strdup(iniparser_getstring(ini, "color:background", "default")); p->gradient = iniparser_getint(ini, "color:gradient", 0); if (p->gradient) { for (int i = 0; i < p->gradient_count; ++i) { free(p->gradient_colors[i]); } p->gradient_count = iniparser_getint(ini, "color:gradient_count", 8); if (p->gradient_count < 2) { write_errorf(error, "\nAtleast two colors must be given as gradient!\n"); return false; } if (p->gradient_count > 8) { write_errorf(error, "\nMaximum 8 colors can be specified as gradient!\n"); return false; } p->gradient_colors = (char **)malloc(sizeof(char *) * p->gradient_count * 9); p->gradient_colors[0] = strdup(iniparser_getstring(ini, "color:gradient_color_1", "#59cc33")); p->gradient_colors[1] = strdup(iniparser_getstring(ini, "color:gradient_color_2", "#80cc33")); p->gradient_colors[2] = strdup(iniparser_getstring(ini, "color:gradient_color_3", "#a6cc33")); p->gradient_colors[3] = strdup(iniparser_getstring(ini, "color:gradient_color_4", "#cccc33")); p->gradient_colors[4] = strdup(iniparser_getstring(ini, "color:gradient_color_5", "#cca633")); p->gradient_colors[5] = strdup(iniparser_getstring(ini, "color:gradient_color_6", "#cc8033")); p->gradient_colors[6] = strdup(iniparser_getstring(ini, "color:gradient_color_7", "#cc5933")); p->gradient_colors[7] = strdup(iniparser_getstring(ini, "color:gradient_color_8", "#cc3333")); } return true; } bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colorsOnly, struct error_s *error) { FILE *fp; // config: creating path to default config file if (configPath[0] == '\0') { char *configFile = "config"; char *configHome = getenv("XDG_CONFIG_HOME"); if (configHome != NULL) { sprintf(configPath, "%s/%s/", configHome, PACKAGE); } else { configHome = getenv("HOME"); if (configHome != NULL) { sprintf(configPath, "%s/%s/", configHome, ".config"); mkdir(configPath, 0777); sprintf(configPath, "%s/%s/%s/", configHome, ".config", PACKAGE); } else { write_errorf(error, "No HOME found (ERR_HOMELESS), exiting..."); return false; } } // config: create directory mkdir(configPath, 0777); // config: adding default filename file strcat(configPath, configFile); // open file or create file if it does not exist fp = fopen(configPath, "ab+"); if (fp) { fclose(fp); } else { // try to open file read only fp = fopen(configPath, "rb"); if (fp) { fclose(fp); } else { write_errorf(error, "Unable to open or create file '%s', exiting...\n", configPath); return false; } } } else { // opening specified file fp = fopen(configPath, "rb"); if (fp) { fclose(fp); } else { write_errorf(error, "Unable to open file '%s', exiting...\n", configPath); return false; } } // config: parse ini dictionary *ini; ini = iniparser_load(configPath); if (colorsOnly) { if (!load_colors(p, ini, error)) { return false; } return validate_colors(p, error); } #ifdef NCURSES outputMethod = (char *)iniparser_getstring(ini, "output:method", "ncurses"); #endif #ifndef NCURSES outputMethod = (char *)iniparser_getstring(ini, "output:method", "noncurses"); #endif xaxisScale = (char *)iniparser_getstring(ini, "output:xaxis", "none"); p->monstercat = 1.5 * iniparser_getdouble(ini, "smoothing:monstercat", 0); p->waves = iniparser_getint(ini, "smoothing:waves", 0); p->integral = iniparser_getdouble(ini, "smoothing:integral", 77); p->gravity = iniparser_getdouble(ini, "smoothing:gravity", 100); p->ignore = iniparser_getdouble(ini, "smoothing:ignore", 0); if (!load_colors(p, ini, error)) { return false; } p->fixedbars = iniparser_getint(ini, "general:bars", 0); p->bar_width = iniparser_getint(ini, "general:bar_width", 2); p->bar_spacing = iniparser_getint(ini, "general:bar_spacing", 1); p->framerate = iniparser_getint(ini, "general:framerate", 60); p->sens = iniparser_getint(ini, "general:sensitivity", 100); p->autosens = iniparser_getint(ini, "general:autosens", 1); p->overshoot = iniparser_getint(ini, "general:overshoot", 20); p->lower_cut_off = iniparser_getint(ini, "general:lower_cutoff_freq", 50); p->upper_cut_off = iniparser_getint(ini, "general:higher_cutoff_freq", 10000); p->sleep_timer = iniparser_getint(ini, "general:sleep_timer", 0); // config: output free(channels); free(p->mono_option); free(p->raw_target); free(p->data_format); channels = strdup(iniparser_getstring(ini, "output:channels", "stereo")); p->mono_option = strdup(iniparser_getstring(ini, "output:mono_option", "average")); p->raw_target = strdup(iniparser_getstring(ini, "output:raw_target", "/dev/stdout")); p->data_format = strdup(iniparser_getstring(ini, "output:data_format", "binary")); p->bar_delim = (char)iniparser_getint(ini, "output:bar_delimiter", 59); p->frame_delim = (char)iniparser_getint(ini, "output:frame_delimiter", 10); p->ascii_range = iniparser_getint(ini, "output:ascii_max_range", 1000); p->bit_format = iniparser_getint(ini, "output:bit_format", 16); // read & validate: eq p->userEQ_keys = iniparser_getsecnkeys(ini, "eq"); if (p->userEQ_keys > 0) { p->userEQ_enabled = 1; p->userEQ = (double *)calloc(p->userEQ_keys + 1, sizeof(double)); #ifndef LEGACYINIPARSER const char *keys[p->userEQ_keys]; iniparser_getseckeys(ini, "eq", keys); #endif #ifdef LEGACYINIPARSER char **keys = iniparser_getseckeys(ini, "eq"); #endif for (int sk = 0; sk < p->userEQ_keys; sk++) { p->userEQ[sk] = iniparser_getdouble(ini, keys[sk], 1); } } else { p->userEQ_enabled = 0; } free(p->audio_source); char *input_method_name; for (size_t i = 0; i < ARRAY_SIZE(default_methods); i++) { enum input_method method = default_methods[i]; if (has_input_method[method]) { input_method_name = (char *)iniparser_getstring(ini, "input:method", input_method_names[method]); } } p->input = input_method_by_name(input_method_name); switch (p->input) { #ifdef ALSA case INPUT_ALSA: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "hw:Loopback,1")); break; #endif case INPUT_FIFO: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "/tmp/mpd.fifo")); p->fifoSample = iniparser_getint(ini, "input:sample_rate", 44100); p->fifoSampleBits = iniparser_getint(ini, "input:sample_bits", 16); break; #ifdef PULSE case INPUT_PULSE: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "auto")); break; #endif #ifdef SNDIO case INPUT_SNDIO: p->audio_source = strdup(iniparser_getstring(ini, "input:source", SIO_DEVANY)); break; #endif case INPUT_SHMEM: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "/squeezelite-00:00:00:00:00:00")); break; #ifdef PORTAUDIO case INPUT_PORTAUDIO: p->audio_source = strdup(iniparser_getstring(ini, "input:source", "auto")); break; #endif case INPUT_MAX: { char supported_methods[255] = ""; for (int i = 0; i < INPUT_MAX; i++) { if (has_input_method[i]) { strcat(supported_methods, "'"); strcat(supported_methods, input_method_names[i]); strcat(supported_methods, "' "); } } write_errorf(error, "input method '%s' is not supported, supported methods are: %s\n", input_method_name, supported_methods); return false; } default: write_errorf(error, "cava was built without '%s' input support\n", input_method_names[p->input]); return false; } bool result = validate_config(p, error); iniparser_freedict(ini); return result; } cava-0.7.4/config.h000066400000000000000000000032461405100172200140470ustar00rootroot00000000000000#pragma once #include #include #include #include #define MAX_ERROR_LEN 1024 #ifdef PORTAUDIO #define HAS_PORTAUDIO true #else #define HAS_PORTAUDIO false #endif #ifdef ALSA #define HAS_ALSA true #else #define HAS_ALSA false #endif #ifdef PULSE #define HAS_PULSE true #else #define HAS_PULSE false #endif #ifdef SNDIO #define HAS_SNDIO true #else #define HAS_SNDIO false #endif // These are in order of least-favourable to most-favourable choices, in case // multiple are supported and configured. enum input_method { INPUT_FIFO, INPUT_PORTAUDIO, INPUT_ALSA, INPUT_PULSE, INPUT_SNDIO, INPUT_SHMEM, INPUT_MAX }; enum output_method { OUTPUT_NCURSES, OUTPUT_NONCURSES, OUTPUT_RAW, OUTPUT_NOT_SUPORTED }; enum xaxis_scale { NONE, FREQUENCY, NOTE }; struct config_params { char *color, *bcolor, *raw_target, *audio_source, /**gradient_color_1, *gradient_color_2,*/ **gradient_colors, *data_format, *mono_option; char bar_delim, frame_delim; double monstercat, integral, gravity, ignore, sens; unsigned int lower_cut_off, upper_cut_off; double *userEQ; enum input_method input; enum output_method output; enum xaxis_scale xaxis; int userEQ_keys, userEQ_enabled, col, bgcol, autobars, stereo, is_bin, ascii_range, bit_format, gradient, gradient_count, fixedbars, framerate, bar_width, bar_spacing, autosens, overshoot, waves, fifoSample, fifoSampleBits, sleep_timer; }; struct error_s { char message[MAX_ERROR_LEN]; int length; }; bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colorsOnly, struct error_s *error); cava-0.7.4/configure.ac000066400000000000000000000175201405100172200147170ustar00rootroot00000000000000AC_INIT([cava], [m4_esyscmd_s([cat version])], [karl@stavestrand.no]) AM_INIT_AUTOMAKE([subdir-objects -Wall -Werror foreign]) dnl AC_CONFIG_MACRO_DIRS([m4]) AM_PROG_AR LT_INIT AC_PROG_CC AC_PROG_CC_STDC AM_PROG_LIBTOOL dnl ############################ dnl checking if debug is enabled dnl ############################ AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [enable debug messages and frequency table output]) ) AS_IF([test "x$enable_debug" != "xyes"], [ dnl enabling debug mode CPPFLAGS="$CPPFLAGS -DNDEBUG" ]) AC_ARG_ENABLE([asan], AS_HELP_STRING([--enable-asan], [build with AddressSanitizer]) ) AS_IF([test "x$enable_asan" = "xyes"], [ dnl enabling asan CPPFLAGS="$CPPFLAGS -fsanitize=address" LDFLAGS="$LDFLAGS -fsanitize=address" ]) AC_ARG_ENABLE([tsan], AS_HELP_STRING([--enable-tsan], [build with ThreadSanitizer]) ) AS_IF([test "x$enable_tsan" = "xyes"], [ dnl enabling tsan CPPFLAGS="$CPPFLAGS -fsanitize=thread" LDFLAGS="$LDFLAGS -fsanitize=thread" ]) AC_ARG_ENABLE([ubsan], AS_HELP_STRING([--enable-ubsan], [build with UndefinedBehaviorSanitizer]) ) AS_IF([test "x$enable_ubsan" = "xyes"], [ dnl enabling ubsan CPPFLAGS="$CPPFLAGS -fsanitize=undefined" LDFLAGS="$LDFLAGS -fsanitize=undefined" ]) dnl ###################### dnl checking for pthread dnl ###################### AC_CHECK_HEADERS([pthread.h], AC_CHECK_LIB(pthread, pthread_create, LIBS="$LIBS -lpthread", AC_MSG_ERROR([pthread.h found but there is no pthread library to make use of]) ), AC_MSG_ERROR([no pthread.h header header file found]) ) dnl ###################### dnl checking for alloca.h dnl ###################### AC_CHECK_HEADER([alloca.h], [CPPFLAGS="$CPPFLAGS -DHAVE_ALLOCA_H"]) dnl ###################### dnl checking for alsa dev dnl ###################### AC_ARG_ENABLE([input_alsa], AS_HELP_STRING([--disable-input-alsa], [do not include support for input from alsa streams]) ) AS_IF([test "x$enable_input_alsa" != "xno"], [ AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no) if [[ $have_alsa = "yes" ]] ; then LIBS="$LIBS -lasound" CPPFLAGS="$CPPFLAGS -DALSA" fi if [[ $have_alsa = "no" ]] ; then AC_MSG_NOTICE([WARNING: No alsa dev files found building without alsa support]) fi], [have_alsa=no] ) AM_CONDITIONAL([ALSA], [test "x$have_alsa" = "xyes"]) dnl ###################### dnl checking for pulse dev dnl ###################### AC_ARG_ENABLE([input_pulse], AS_HELP_STRING([--disable-input-pulse], [do not include support for input from pulseaudio]) ) AS_IF([test "x$enable_input_pulse" != "xno"], [ AC_CHECK_LIB(pulse-simple, pa_simple_new, have_pulse=yes, have_pulse=no) if [[ $have_pulse = "yes" ]] ; then LIBS="$LIBS -lpulse-simple -lpulse" CPPFLAGS="$CPPFLAGS -DPULSE" fi if [[ $have_pulse = "no" ]] ; then AC_MSG_NOTICE([WARNING: No pusleaudio dev files found building without pulseaudio support]) fi], [have_pulse=no] ) AM_CONDITIONAL([PULSE], [test "x$have_pulse" = "xyes"]) dnl ###################### dnl checking for portaudio dev dnl ###################### AC_ARG_ENABLE([input_portaudio], AS_HELP_STRING([--disable-input-portaudio], [do not include support for input from portaudio]) ) AS_IF([test "x$enable_input_portaudio" != "xno"], [ AC_CHECK_LIB(portaudio, Pa_Initialize, have_portaudio=yes, have_portaudio=no) if [[ $have_portaudio = "yes" ]] ; then LIBS="$LIBS -lportaudio" CPPFLAGS="$CPPFLAGS -DPORTAUDIO" fi if [[ $have_portaudio = "no" ]] ; then AC_MSG_NOTICE([WARNING: No portaudio dev files found building without portaudio support]) fi], [have_portaudio=no] ) AM_CONDITIONAL([PORTAUDIO], [test "x$have_portaudio" = "xyes"]) dnl ###################### dnl checking for sndio dev dnl ###################### AC_ARG_ENABLE([input_sndio], AS_HELP_STRING([--disable-input-sndio], [do not include support for input from sndio]) ) AS_IF([test "x$enable_input_sndio" != "xno"], [ AC_CHECK_LIB(sndio, sio_open, have_sndio=yes, have_sndio=no) if [[ $have_sndio = "yes" ]] ; then LIBS="$LIBS -lsndio" CPPFLAGS="$CPPFLAGS -DSNDIO" fi if [[ $have_sndio = "no" ]] ; then AC_MSG_NOTICE([WARNING: No sndio dev files found building without sndio support]) fi], [have_portaudio=no] ) AM_CONDITIONAL([SNDIO], [test "x$have_sndio" = "xyes"]) dnl ###################### dnl checking for math lib dnl ###################### AC_CHECK_LIB(m, sqrt, have_m=yes, have_m=no) if [[ $have_m = "yes" ]] ; then LIBS="$LIBS -lm" fi if [[ $have_m = "no" ]] ; then AC_MSG_ERROR([math library is required!]) fi dnl ###################### dnl checking for fftw3 dnl ###################### AC_CHECK_LIB(fftw3,fftw_execute, have_fftw=yes, have_fftw=no) if [[ $have_fftw = "yes" ]] ; then LIBS="$LIBS -lfftw3" fi if [[ $have_fftw = "no" ]] ; then AC_MSG_ERROR([fftw library is required!]) fi dnl ###################### dnl checking for ncursesw dnl ###################### AC_ARG_ENABLE([output_ncurses], AS_HELP_STRING([--disable-output-ncurses], [do not include support for output with ncurses]) ) AS_IF([test "x$enable_output_ncurses" != "xno"], [ curses_config_bin="ncursesw6-config ncursesw5-config" AC_PATH_PROGS(CURSES_CONFIG, $curses_config_bin) AC_CHECK_LIB(ncursesw, initscr, curses_lib=ncursesw ) AC_CHECK_LIB($curses_lib, initscr, if test "$CURSES_CONFIG" = "" ; then LIBS="$LIBS -l$curses_lib" CPPFLAGS="$CPPFLAGS -DNCURSES" fi if test "$CURSES_CONFIG" != "" ; then CPPFLAGS="$CPPFLAGS `$CURSES_CONFIG --cflags` -DNCURSES" LIBS="$LIBS `$CURSES_CONFIG --libs`" fi AC_CHECK_HEADERS([curses.h], , AC_MSG_ERROR([missing curses.h header])) have_ncurses=yes, AC_MSG_NOTICE([WARNING: building without ncursesw support ncursesw is recomended!]) have_ncurses=no )], [have_ncurses=no] ) AM_CONDITIONAL([NCURSES], [test "x$have_ncurses" = "xyes"]) dnl ###################### dnl checking for system iniparser dnl ###################### AC_ARG_ENABLE([system_iniparser], AS_HELP_STRING([--disable-system-iniparser], [do not use system iniparser library (use bundled iniparser library)]) ) AS_IF([test "x$enable_system_iniparser" != "xno"], [ AC_SEARCH_LIBS([iniparser_load], [iniparser], [ AC_CHECK_HEADERS([iniparser.h], [have_system_iniparser=yes]) ]) ], [have_system_iniparser=no] ) AM_CONDITIONAL([SYSTEM_LIBINIPARSER], [test "x$have_system_iniparser" = "xyes"]) if test "x$have_system_iniparser" = "xyes"; then AC_SUBST(SYSTEM_LIBINIPARSER, 1) AC_MSG_NOTICE([Using installed iniparser]) LIBS="$LIBS -liniparser" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[dictionary* ini; const char *keys[3]; iniparser_getseckeys(ini, "eq", keys);]])], [AC_MSG_RESULT(iniparser > 3.2 test OK)], [AC_MSG_RESULT(iniparser > 3.2 test failed falling back to legacy iniparser mode) CPPFLAGS="$CPPFLAGS -DLEGACYINIPARSER"]) else AC_SUBST(SYSTEM_LIBINIPARSER, 0) AC_CONFIG_FILES(iniparser/Makefile) AC_MSG_NOTICE([Building iniparser]) fi dnl ############################ dnl Set font directory dnl ############################ DEFAULT_FONT_DIR="${datarootdir}/consolefonts" AC_ARG_VAR(FONT_DIR, [Directory where the font will be installed.]) if test -z "$FONT_DIR" ; then FONT_DIR="$DEFAULT_FONT_DIR" fi AC_CANONICAL_HOST build_linux=no build_windows=no build_mac=no AC_MSG_NOTICE([Checking OS]) # Detect the target system case "${host_os}" in linux*) AC_MSG_NOTICE([Linux detected]) build_linux=yes ;; darwin*) AC_MSG_NOTICE([OSX detected]) build_mac=yes ;; *) AC_MSG_ERROR(["OS $host_os is not supported"]) ;; esac # Pass the conditionals to automake AM_CONDITIONAL([LINUX], [test "$build_linux" = "yes"]) AM_CONDITIONAL([OSX], [test "$build_mac" = "yes"]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT cava-0.7.4/debug.h000066400000000000000000000004711405100172200136650ustar00rootroot00000000000000#include #ifdef NDEBUG #define debug(...) \ do { \ } while (0) #else #define debug(...) fprintf(stderr, __VA_ARGS__) #endif cava-0.7.4/example_files/000077500000000000000000000000001405100172200152415ustar00rootroot00000000000000cava-0.7.4/example_files/cava.gif000066400000000000000000002107421405100172200166500ustar00rootroot00000000000000GIF89a˜—ó ?ÿÿêêêòòòôôôûûûýýýþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù!ÿ NETSCAPE2.0,˜—þ0ÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïh-`Ín»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹Œ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²£³·¸¹º»¼½¾¿ÀÁÂÃÄ”µÅÊËÌÍÎÏÐÑÒÓ°ÇÉÔÙÚÛÜÝÞßàÌÖØáæçèéêëìÅãåíòóôõö÷æïñøýþÿ ,¥Ï¿*\È0\Á JœH±¢ÅX)D¼È±£Çþ3Nز¤É“(牔@2¥Ë—0c6[™ ¥Ì›8sêdEÓæÎŸ@ƒ •Ôs¨Ñ£HuMÊ´©Ó¶žJJ5àÒªX³jEwu«×¯`Ÿu K¶¬Y]cϪ]ËÖTÚ¶pãÊ­ôv®Ý»gëâÝË7«Þ¾€'ý+¸°a¥Q+^œ“0ãÇ/:ŽL¹rÂÉ–3k¾‡y³çÏé:ƒMz›èÒ¨SÏL¬ºµëh§_Ëž=+6í½rëÞÍ»·€Û»l·ë»¸ïṄ#k¼¹îå·”CgëÜùtYÒ¯Ÿ­Þ\{5ÖÞs7ÞUöò`ÇGÏ<{¼ê¿Ou~~Öø½í£ª¯Ÿ*~Þý¹þå^€mý·¤ð‡`S>·`( >ˆTƒ¹IJ„Eáov‚a‡@m"'ލ“ˆ&fRbŠ7¡È¢%+¾“‹2Nc)шc7îh’Ž8öè#H@Ö(ä)ã‘HÒƒ¢’/2Ù¤•ùãâ÷j?­úÊû^päç7úáË~RÑ_ý È!í1P`²»Õ‰¾sMoTà#¸ ò‹ÁkŸë˜¸ rP-„ ÿ¤'ÂP¤ŠÃ gBÂå…/ ÷Ø7<Þ­°\ñsÜÒjØB¹àˆ=tß-hÃV]Ðs3ŒÅ›8!$‡W\Ÿþ³ÈEÐAm‰·ƒ¢•ˆÅnÑŒ]$ߌ¬ˆÆ6ö¯ŒoW»È¯rS;Þ׆׻ÛÅ.n£;¨évW½é}¯|¿‹ÞóÂ×¾ó/}ï[Þãö7¹o5ïÅàÏòH·†í«^¼Ü7–¼ðaaOØ¿®ï€5œaþvx¹-¬hü` _X †ð‰-œb·Ã+æpŒ=<ãüâw¿6Þð}Ñ*]?VÇ9þ0އ¬ß"ߨÈ@&ò‘—œd$ ÙÉ5Vr“™üä%ó¸½>v¯”«<å.sùËQ†ò‹Q\b™Åe&óÁ|æú^ùQZsšÑ¼æ0SÙÎ^Æ3›ç,ã6ÓØÏAÖ³ ½…åAóyÇt)Â}E3úÑÁ¤'-GSúÒ*±4¦7­IsúÓ#L(¨GmO“úÔ25ªWšG4âհ޵¬gMëZÛúָε®wÍë7¤á×À¶°‡MìbûØÈN¶²—Íìf;ûÙÐŽ¶´§Míj[ûÚØÎ¶¶·Íín{ûÛà·¸_!ù,*‚RþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÈÉÊËÌ*HÐ/ÆÓÔWÍ×ÍØÛÉÑÑÕáâNÜÜÚåØÞßHãíîAèéñ×êëIïùú7ôÙóýËìÝ‹±¯ ÁþKˆì Ã‡>v[Ȣŋ5$6¤˜£Çþ$4:ã¤É“Dž“ˆ²¥Ë•Iö{IÓ¤J™ôjêÄxóæÎŸ{jJ”¨Ï¢H_U2_Ò§™–i*ªU“T ^Ýz1+ ®`ÊK¶¬Ù“RϪ –v­[^mßʽwn ¯Ò쪫W^} ñ¥ù—FŠÂ N̸ÔMÄM„²lLÅâ-ů²ç—9dF¸9ôçÓ0;þ«BrLG¦QŠ]ŵjØ›eC¢M…w%ߺû2\RñiÇ-%Oa»ä©åÄ ó,Ûqõ‹Ò±SŸÌäv˜ìl¯[OÄ{ðˆâ¡’bþ<õáÃsî=÷­ò´¯ÏŸô}1ûõŽ' ùýà€“Þ&è Ú—ÓƒáD؃…4W….è†)m7¡$£qx ˆhhÎ*%š(œ‡óý·K‹.ƒâ%Ñ8„Ž5‚q£%9²Ö=~£-Aâåd?yA“”$é•P:IA•$ ÙÝ‘`i%‡^~)¦‚“…9¦DÂ%bƒg¶Y„™n!ù,,‚PþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl:ŸÐ¨tJõ ¯¯ªvËíz¿à°¸‚ÅŽÏè´zÍn»ßð¸|N¯›ø¼~ÏØÿ€‚ƒ„"}‡}…Š‹ŒŽaˆ‘y”•–—˜5’’™žŸ —›‘¡¥¦§¨n£ˆ©­®¯°N«‡±µ¶·¸)³‰¹½¾¿¿»|ÀÄÅÆ§Â{ÇËÌÍÉzÎÒÓÔqГÕÙÚÛ]×xÜàáâwÞÞ~ãéêëçæåìñòóîô÷øùúûüýþÿ H° Áƒ]•¹’°¡ÃJ ‘<œH‘PÄ#3jœs1ÉÆþ Ót”²¤I/#cœ\Ér½–0c y)³¦M4oêÜIîÏŸ@Cä J´è„¡F“þDª´©M¦N£‚K CT©X«QÍ¢ ^Ö¯Û¶ºKÖ¤XeÓªuu­ÛmßÊõw®Ý|öêvÒ{—l^¯žóùàlßï ?°§ñ±Æ'øþRÌX°ãÇ–QHVWyëeŠ›Bþ¼Ž2`Ò¨{™&œº5®ÕÐÚ$sM;ÝìÚ¸¹ÝÎÍ»·ïßÀƒ N¼¸q¡+g”|¹óAÍEžpº/ëÔ bϵ=»÷ïàËïi4ó䉣³>½{7íßËŸO¿¾ýûs:SÅ/?>ÿü¡¦l»`€Ÿ ˜‚u÷ˆ‚ž1(!N˜Q!ù,,‚TþðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WU¸|N¯Øø¼~Ïïû1vv„…†‡ˆ‰8‚ŒrŠ‘’“{”˜™š›œA–Œ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øxnFùýþNûŠüH0HÀ#û$H¡Ã‡p‚H±"‰-jÜhcŽÜ Az¤²¤Å‘sLª\ɲ¥Ë—0cÊœI³¦Í›8sê|tÆÎŸ#P:JT›Ð8E“^;zG©SiLŸJ}uªÕ«&z¾Àʵ«×¯%«‚õ&¶^Ù±ÛÎÎSK‚-ÚSn]iÍ÷-©º9ñÚÍ¥bß½¶þ: xáˆ5NÌXÒâÆ?hu¹²å˘sM¾’¹³çÏ C‹Mº´éÓ¨S«^ͺµéÇ®cËžM»¶íÛ¸së†{÷«Í,bööM\Ãðâ@ÏPŽüäQ ÌSDoî÷ùƒé'°S§©}{îîÞkE!ù,5‚EþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl:ŸÐ¨tJõ ¯¯ªvËíz¿à°¸‚ÅŽÏè´zÍnSËW·|N¯Ûïm8Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”!zG•™š›œi—I¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉʸŸ2ËÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíÞÍ1îòóQð0ôøùDöYúþÿ:ø¹H°  4 *\!7‡ #’€(±¢EŠ3jÜȱ£G2ªGaüH²ÉÈ’(­„Tt2¥Ë*-_Ê|·r¦Ío1oꬖs§Oh=ÕÁcô'£¢FG Mšm)8§L­A¥É/*¹©.±ZÝjK+ׯ±¼‚…%–^Ù±­ÎÊS‹V[“5;½m{j.Ý»šìâÝË·¯ß¿€ L¸°a?+^̸±€Ã)9žì8²å‚z/s¤ÌY±æÏŠ:wÖ—ô&ÑœIÇ5} 5eÖ°c«¬*;Z!ù,;\þðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pH4ÍŽ³¢rÉl:ŸÐ¨tJe!¯¯ªvËíz¿à°x„ÅŽÏè´zÍn»ßð¸|N¯«ÊW»~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®—xH¯³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéJ±Gêîïðñ¡ìIòö÷<ô2øüýVú0üÝP ‚Y *\Ø ¡ †#JœH±¢Å‹3jÜȱ#&€Âã8¤qhdÈ“àL¢\¹M%Ë!._>йÎ!?š2¯á„·3ç<›)zúJ´¨Ñ£H“>ú‰©Ò§¶œBU%•bÕ©§®JÔŠ•Wˆ_»þD(¶¬Ù³hÓª]KH€Û·pãÊÀ¶.Ô°ŽðÚµ t¯ß¿€ L¸°á%z+^̸±ãÇ#K,¹²åËv(cÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“ÿ!ù, ,jUþðÉI«½8ëÍ»ÿ`(Ždiž(¬lë¾A*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨¬HeI¯Ø¬vËíz¿›jL.›Ïè´+¦®ßð¸|NW·‹õ¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ¬wDÂÆÇ¯ÄFÈÌÍPÊ/NÐ.ÎÕÖHÓ-ÒÙ+×ÞßCÜ1Mâãàçè(åÛÜéîï!ëäâðõöòLù÷üõûJÿú <½ Ô·0¡Ã‡ì²Eœ±"³‚G0ZܨKcþCÒùƒ¤È“(=˜Lɲ%…•.cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*µs©ÓXMŸJÖpªÕ‘U¯jMv0j¯[E€å7vMÙ°*³Ö:ûR­¶høWB]3wã^È ê._0õNÜÉï\>„'Þd¸¡Å‚:6 ád”+f.Y9òŒÍž?v­î0i2OŸÝ…µj™®·ÄŽ9ûõ•Úø ØÍ»·ïßÖš¶Ý÷^ÝÀ“ÿ~™ø ãL‘+ŸkóÔ©;O½‚¼ìÓá¿ ^ùvƒ×ÑK|P>¹øá8È·_~^H÷¶ŽçÓ§œ¾‡|ý¼Õ“g|þI`uü­7`" €™|ç ‚vhÃ}OLH!„3Ƀ¡r(Õ‡M„(≃˜ˆâŠ~¨Èâ‹y¸˜‰0æ"¡ƒȘ„‰4ÖxËæ8áèãi&êHFZ’C¦À¤~N>%]Ie•‘A‰£”ZÎÇe—WFÉ„’cŠˆ¦k¦)`›nÆ™¡™r&!ù,2‚KþðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WÙð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕ&nFÖÚÛØEÜàávÞGâæçiä0èìí^ê/Nð.îõÑóWMø,öýþKûdèÛ÷¯à±€ò\( á@| #þrÈ„¢Ä‹¸,*ш±£,ŽèCŠ”r¤É‹%Oª\ɲ¥Ë—0cÊœI³¦Í›8sê”r§Ob= ¨p¨ÑaA*]Ê´©Ó§X’Š“ ÕUpWe­ºmk¯ˆÀr¥&ÖVÙ±÷Šª×F¡€·pãÊ+m³³PØ®uK·ï\hxVápðCom!>ðË.`µvËè%Ô¸qä˘3kÞ̹jeÆCgúìW´éJ¤ûÎ4|ºõÖ'`§ƒìz™ìY·=ä®Í›‚ØÂ w÷v*|Gq ©é~üGò¿lžË]n›6õë{š{”vìàËO¾¼ùó7¸;Fo*!ù,7`þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ p؉cĤrÉl:ŸÐ¨t ÅË×ÌY_z£ŽsÛîo_d†©%>\l±4ÇŒF¹MåÈ¿.cf¸)$Í›ûvÞúth¼£—ž^Â4šÔ‚YÓsM‚¶زñÙ±; î{ƒ®‘øJã=~B.‰yî-Ê 9ÿ<ù¹õ늫Ÿ›Ž}w_ß»‹O¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ+(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†M!ù,<[þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ p؉cĤrÉl:ŸÐ¨t º‘§Ñ‚1gEÙd)Ó£å|*uêÄ)F¨æ¤²ê‘ ל:±ÚÒªuÐW¯VÁÞ˶ËÙ5g‰æyÛ¶®º‰ðÚETV–ÞC÷ê+p!ÂÓ@l6­âÇ8 ’œ0di”;d>eù2´Í@{ÍJ4éÓ§â:F}Æ4ëÐŽ]¿nºz6 ÕTm÷.Þ¾ƒ—¬-œðâ°so’\"sDÏ›K7}Æñ騷\Ïν»÷ïàËO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vh! !ù, ‚_þðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùº÷úýþªüþ ¨) ÁƒLȰaŸ…#J„q¢Å‹c*bÜÈÑŠÆŽþ C"ù(²G€“(Sª\ d?’.u°œÉ2f>˜6oÐ܉2g=œ>iðätТ1†îDúî(SJi>]çtꊨ3­¦«ªµkI®^Ãr+¶ìD²fÓ2D«¶í@¶nãêƒ+·®Ñvvób¤«·/9¾~w,¸°5†7C¬¸1¨dŒKFÖ.òäË ãÅÌù—fVCûúLJ´é[¤9^-¬òfÖ°E¥ž»¶l× Xv‡µ¦ÍÝ”sÏV”³÷ÊœdWH‚òtÆU"Ý‚ùj¸Kë¦2zJ\Þ{6Iž]µëlœsþ$øöNÈ _Ï=õ¹c¶oyk?Eúæäþ·Jy´m'`IþõßòiW†}aØ• -ÊòÜ ¶aÛ+ºp!v²Dˆ‚lèJ‡ÕHˆy€Hœ‰ª èƒŠƒ°˜‰‹À¨cf.6·ã.4þxc× iÒ‚FÖðáK"%c’/4Y”PšHåWVÙŽ”Œ¤–,<Ù—"2‘%kbè =d–âå|¹¥y™œ@O›­¸‘ ’ñY™™ƒ_†â'U…Šƒg-„ÚÉ!’þšÊ¢½Ôu(˜|Pš×¥{Hº‘¦BªP¢[ z¦tx O‚ ¢*‡ª®&Bjœk¬Ì°:+®¼>¡«£½Ûé®Âkì± †‡ì²sÔÊl*!ù,‚wþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊëîÙ³hÌ¢];F-Û·[ÜR @·®Ý»xÀ½"wjÞ¿y÷Zé+°áº‚«ŽzøpbIíº66üX[d®“Wv²jæ¿››tÖ0ÚãçÀ¡—”ưšãi¼©U_vÑzãë»ÿjËÒýe¶ÊÛvsû¶7|oŒÀû;þŠùç“ÓÎ*"tŠÒõBºN»xBî³GïÃ;BòÅo7Oý:÷±³Ÿ5ßüO÷ã£Èo¿~ þ™þ¨É8g ¿8 iíX] Zႈ 2ø …ÌLÈZƒ nø‚…zÈaZæ@")8È"„)žÈˆ‰ì”â‹vÄ(£44V°"'-êX#Ž;¦óã$AÚ¨ä‹.Y¤:G*’$“7:Ùã“eU‰äsZJÉå’N>&–|DÈ”Vvyæ—D62&™¨Ç„™w ¹%läså {â"§l`Þ©fl¾ OŸ0Š¸ÏŸ€ šg¡‚êe=ˆæ¨¨>Œ¶€'vzÙä–” ©˜¨ßdŠÄ¦a@:鈤ZS)«—æcꨶ¡êš–¶yh«GÍjD­xÜJh®†¾óêJ¾®â(§‰êj,¯F%ÛÖ²© *œâH+°‚4[,¶Ùhë·‹€Ë!¹”˜{.µ¶ªë„¸"ë® ð†$ï¼,Ô Ò½øª ¿ýöô/´ÏH°,Çj†¾ùm4 ;»°t ‡GñÉ0\1…o<`ÇrÈZe|1É{™œÊ‚© Ë^D!ù,8CR<þPÈI«/ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘j”’—˜™š›œžŸ ¡¢"•¥£¨©ª-¦¦y­¥«²³´°•µ¹ºˆ·”½–»ÂÃ~À¿ÆÄË6ÎÏÐÑÒ‘ÉÊHÖ§ÌÛIÓÞÓÕÙâã/åÜéFßìϺè0ðêó@ííïâ1òôü;öìø²éËׯ`Žß’ì3¸¡7†¹‚ÃFbC‰Ñ,Ò˜‘¢@r¡5Š\ÅšB‚ -&ù¨¤;–wVÂdäÒÙL;2oêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*mVs©S§5©=JµªÕ«X³jÝʵ«×¯`ÊK¶,”¨fÓîB«¶-«uغ‹"å¹tóް+¯Þ¿€ L¸°áÈÏâ›Â¯âǯ` ¹rÊ–3ÃÁìC²æÏo<ƒ­ƒs ѤS×0­ZR!ù,8CR<þ0ÈI« /ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰ŒŠ‘’“”•O˜–›œžŸ ¡¢£¤¥¦¢©ª«¬­§°±²³´µ¶1®¹®·¼½¾¿ÀÁÂÃÄÅ`ºÈªÆËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâP™™É»ãêëìíîïðñòó9å˜ôøòöùýîûŒü TÐÑÀƒß Z@Ȱ¡Ã‡#Jœ¦°ÂÄ‹3jÜȱ£ÇL C®C‡L¤É“(Sª\ɲ¥Ë—0cÊœI³ME 5sò¹©I§Ï;<%üÔIR×УH“+š+LP J£JJµªÕLÓ]Ýʵ«Ã§^ÉD!ù,D‚:þðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ï{臼 pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’S?•“˜™š›œžd––Ÿ£¤¥†¡•¦ª«¬*¨?­±²³f¯>f¹º»¼½´ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎ¥¶@Ñ ÏÖרÙÚÛÜÝÞßàáâãäåæÔçëì~éíñò²ï—ãéóùúXõûÿÇô° Á,*\%!Ç#ŽðEÑ—Ä‹«bÜȱ£Çp Íi I²¤„‘&SzD©²åE‡,]Ê ³ßÌ›÷lNÓ‰Ó`ÅŸºÈլ׳h·˜F“¶Cª´i9¦N£‚ƒ*µê6ªV³jÝʵ«×¯`Ia K¶¬Ì±fÓª]˶­[khßʽèIžsójŠ«·ï)¼~E!ù, Fj9þðÉI«!ëÍ{¸`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡#ŠˆŽ2‹“‘–—˜™š›œX””’Ÿ‹¤¥¦B¢£©Š¬Œ§±²m¯Jµ³º»¸¼ÀÁ·¾ÃÇÈÉÊËÌÍzÅÆ«ÐÎÔÕ¦ÐÒÅÖÜÝ—ØÞáâãäåæÄÛçêëˆàìïðgîñôõuó/øñ¸öý-úÿ¦ùHð@ *\Ȱá #JœHQ€Ã‹{bÜÈ•ÀŽk CþИè£È“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜI†$ÏŸ@ú JôÜТHÅMÊ´©Ó§P£JirªUeK¯j=•u«WN]¿~ ›†¬Ø³hÓ>«ª¶­Û·pñ˜K·®Ý»xó›«7N!ù,‚yþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£)AÊÔ‰RM£.yBªÕ#TA\Ýʵ«×¯`ÊK¶¬Ù³hÓªe”uÊÚ·_Ú’€KWî\º¦ìJЋ&ß¾jÿ¦(ÜÁ #&«x±ØÆ+ ;ÞÉWò䜖/oͬ¹ çÎQ?ƒf*ÕÑeO£ÞRÊájªEµv8;Cí«·æîðzµïßÀóö.²;8¾â.¯§|yÍæ·HŸN½ºuÎ¥^ß~={Tîà§{o>üøóÑʃGT=wöFÝo‡ß :}•öïëßÏ¿¿ÿÿ.”_€v!_w1 ˜„‚.r uÂµÕ N Nhá…Tˆá†vè¡+~HÛpÀE!ù, jrþðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬v;F¹à°xL.›Ï,/Ín»ßð¸¥þÍïø¼~ÏçÕ}}‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sê|øÈΟTz‚J´‰ÐE“*]Ê´©Ó§P£JªI€Õ«X³j@µk‹­`·z›"¬Ù«z »äìY8j¥<‰+âݺlY¸5+aoX¸t%Ü58¯^¿b Nì¦paÃÈkí+«“ÇíU¶¬x³ÕË3ßóü¹³gÐqE& 8µêz¤¹Æˆ-óël´Mo–‘û¶Âܽ}ãÎZxNâ§³ ®¼+óæSŸC;JJúKëΨ/*Œ½Ÿmè-¸'øü ñÉɇ6¯¤;¿òár¿O>ûûäìã/ª?ÐþþíW`€9 HàM¨à‚ 6è aë=8Rn JX…Z}^7^‡ †¸T…"šD"–˜Ï‰¤H‹*ÆãbÆxz»Å£î —#0ÍdHB!ù,‚lþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±â83jÜÈQ€„Žþ ;Z.¤ÉŒOš$ɲ›Ê•^†lI3›L)on¬É³šNŽ9b *´§Ñ\B5ý¹Tçѧ²’¢Œ)Õ#U©P³ºªj•kÓ›ZÞòz5éW™bÓ‚"˶ªÚ·™Úb-[®ÝHrÍÒez·o£¼uÉú\0_Á„÷1ìtocÄŠ#_a ÖqeÈ’3;¡ŒÖrgÌšC'áüòliϧE«íµJÓ¯]ŸÔG‹Äj?¤c瞯ömÜ­wÃ=Ï÷o>ÂgÊÞŸñãz’ã\®œ¸¼çÐ'ß>†õxسW‘.’útïÍï…ÿ„ô¨¡Sú g„ЦÁ(?†f7©†‘NT飜vêé§ †úÎ¥¢–jꩨΰiª¬¶êê«°šCj¬´~‘é+«þ6+2»¦k­7ôjŒ°'ü ,MÄ«ì²Ìr‘l³¦>ËÁŒÐ¶$mµ ^‹­§ÚnËi·Þf!ù,#‚_þðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–E™š›œ— Y“!¡¥¦2ž©ž§¬­®¯yª²š°µ¶·¸W³³¹½¾¿À6»²ÁÅÆÇÈêÉÍÎϯ˩ÐÔÕÖÒ«×ÛÜÝsÙÞâãäBàœç›åìíî.ê´ñ™ïö÷øôŸóôùÿÙíKç/ ÁƒÖö‹‡°¡Cd #|H±¢!‰ ª³È±#5…þCŠr¤É“Ñ&¢\ÉòRÉ–0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê4ØË¦P£>JÕÔÔªX‹^ÍÊèÖ®`w~ KÖæØ²hcžMËåÚ¶pC¾K·âܺxóêÝË·¯ß¿ìFL8 à)…ß;ìA±cwŒI<ž<.2å˘3kÞÌYƒåΠCŸú,Ú&銧KÏüœz[kÕ0Y3®<6MÙ‡iç¶½ºökÞÀ-ýN¼¸ñãÈ“+_μùãáÎ[Þ…=úÊéϪ[ß^F;÷ï]¼‡Ÿ^µx.£Ê—>¿%ý öZà«G$‹{õ¯äŸŸó~‹ýUQÈŸiä hà&X„€ 6èàƒF(á„Â`…f¨á†c\(vŠáa;‚¢yµÁ`≢•¨~¾¥È"Q#ªQãŒ8æ˜×Š:RÈcqD!ù, jdþðÉI«½8ëÍ»ÿ`(Ždižhª®¬$¼p,ÏBkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍ[Ùð¸|N¯ƒÝH»~ÏïûÿxG€„…†‡ˆ[‚I‰Ž‘&‹3’–—˜™‡”2šžŸ ¡eœ1¢¦§¨©A¤Xª®¯°±¬5²¶·¸¹º»¼½¾¿ ÂÃÄÅÆÀÉÊËiÇÎÇÌÑÒÓRÏÖÃÔÙÚÛ>××Üàáâ&ÞÖãçèéåÏêî´µïŸìÎó÷ñøžõÐûÿuõ3° ÁW‹\È0XBl #J„ôâÄ‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨QuúŽ*-˜t©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xIV–·/š½Èü x°ÄÂÙ^œE1ãÇPCžL¹²åËW%cv§™YçŸ7KBÚaE¥E?"½aë©U7b}Z¶íu¯cßîÓ´¥îÝÀ9üN¼¸ñãÈ“+_Î|­æÐôŽN½ºu\÷d¿¾pB8Û¹ü.^9ynáÅÑw°á …+¶x±ã&?D~œtrË”Û`î´YCçÌM®\!öCiÐUD#QqPkÔ{T¯æx•ì#°ïÜNB{#«Ý3rÛ.ƒumUÄc/õÚRr,ËG5¯ôüEtéÇSU¯q]ñvßÓ„ïkü ófГ/2]z2ï× i(¾|TôÙ¿o*?¤ý*gX€ FàIþX êÅ`ƒt=!\Nhá…f¨á ûmèU‡ö!ù,4‚LþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯°ªvËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~OÁbù€‚ƒ„Q~W…‰Š‹Œ!‡HŽ’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿EGÀÄÅÆÂIǯÉ3ËÄÍ2Ï®Ñ1jÕYÓ†Ø5ÚÞbÜÝßMáãæ]åçKéêíî¡ìïòó—ñô÷øŠöùüýzûþ „p Áƒf "\ȋ†#:y(±¢Å‹3jÜȱ£Çþ CŠI²¤É“(SŠÀ²¥Ë—0¨œÉ1¦Í˜4sb¼É³¥ÎŸ{öJ”¡PžE“¥Eqꃨ8­Æª:+L­[¹ÍàõåXfbÏZ(ëR­[ml}¾+‡k¸,éÃ+ó*ÞNvyð%˜Õ`¿q§erX¯ã5…u4~L9áâ%‡#WÞÌB3Ï@s]BtÓ}.“^õ„t“YË6»LíÙ¸Oܳ;·ï½ÃÿÝÂ5ñã{ÒGÎÜ‹rÕÍ£»Y.½zêÖ³£Á®½ûî?À[ï½ùò諜OϾ½û÷ðg–]¿~‰²ö; ÏÏŸ ôþ?í ,!ù,‚eþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚ¡HÝ0ÛàáDÞÞâæç;äÝèìíîïðñòóôõöÀêH÷ûïùGüÑùK° ¸3 *\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ Cf@(C¤ÉS$cœ\9*å·2._°œù)f š85ÙÌÉóÒΞ@ƒ J´¨Ñ£H“*]šç'Ó§wœž@µªÕ«X@ÝDª‰¬`³rÛÃk‰°h«’]›Ã,‰´iÙÊmáv\´s󦨫·o¾~S,¸ð†+A¬¸qטŽ#7a,¹2Ê–Ý ‹ sæB›Á6-öóWÒWG£¶jºèjÖM^«m=T6U'¶µÒš·íݼÇNÌ3p"½‡Ë6fü¸äL ;Ç)]Iõé,¯#'Ž] äÚO…ï¾§9yìæÏ;O¯8ûö´ßÃ7-¾»úã¾Ûwˆäþþ-(à€hàjˆàF«¡ à‚s=Éx]P¡?I‰…VÆa‡þ}"!ù,‚bþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞHá0ßäå8ââæêë'èáìðñòóôõö÷øùúûüýîHü ¼ðÈÀƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ ëL²$§‘3Lª\ɲe#”2\Ê|3ÆÌ›‹jŽÃɳ§ÏŸ2J´¨Q@“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯MŠ= ¶l“±h‡š]["mZ nѲ$îXlvÅ:ÉK–®¾Fá&ŠJç Áƒ…ú•”XíƒÆŠO®ñòâH‘Vn\ØðeT™'î¬ó³é“O«N‘zµ´Ð4=»ŽÛQëÙÏjãÞÍA7ïß|OÜñâÀ#ç »9àåNsÞœzXËÔ‹¶k©ôÑÙãv_ú]{x·ã•–~þí’Ûé³­ç»]ü{ÙñåcGa^ üüõ( sì H }&èru0¨`7náƒÚL˜……—µö_0^Ñ¡_!ù, j`þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâããcVäèéæHêîïìGðôîòIõùå÷2úþÿ lÁ¯ßÀƒÓ Æ@ÈšB, #.{øB¢Edk\Ü8,#Çþ CŠI²¤É“(Sª\Ér¤Ç–0C½ŒI“ÓÌš8/ÝÌÉ3àΞ@ýL94¨ž¢F“Bª´é¦N£JJµˆ€«X³jÝ* ªW=\ÃrýJv‡Ø³XU E[¶íµgÕ ë¶îйtà«w¯V»€OøýÛwðU †Ó^,$ñá†/9îÊXÙdÄŽ%gnr¹r Î+…^2ÚsЛM«žRzµk&­I ~M»Bì³kë¾-"·nÚ¼Cøþí:8ˆáÄ“ÿ@®¼¹Ô{K:^&Ô«fÿg}®ôïºÃÝ´ýNyðįÍy=õlÝËŸOŸ‘ñúø1'ÎÏ?|jÀ÷õAsnØŸS!˜Ÿ‚Q1XŸƒMA( +ðydž„ Sáxþ—a4®×á~Òƒa‰vœøQ{(¦ça‹ó©£j!ù,#‚\þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯°ªvËíz¿à°¸‚ÅŽÏè´zÍnSËW·|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíÉpHîòó!ðGôøùöIúþúüfüH/  ‚ÛŒ‘°aº…YJœhâ Š¿Y¬‘±£¶þC^)²¤4’&S6C©²¥Ë—0cÊœI³¦0–6sΩ³§+žÊJ´¨QÊ€ÒTŠì¨Ó£>Ã1=ö´êШংÑúŪU¬`{p KvÓØ^«–];ç,Û·‘ÜîHû®Ý"rïê=”w¯ß¿€ ¶ÑwðŽÂ†ËAL‡.QÅ 9¾¹²å˘3kÆ4ÙèæÏl: Sôã@¦)“n™Z¨ ÖHWË{¶í.µoëÞÝ…1ï ¹Oð-<¸ðÄ'—ÜIóÝËÇ=?NuëêØƒDÏν»÷ïàËO>Oîíå=¡·>ý öÞà»$þüú.ñÛG{²þýü`xø]!ù,(‚VþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯°ªvËíz¿à°¸‚ÅŽÏè´zÍnSËW·|N¯Ûïm8Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö±zG÷ûûùIüçù›° ¼2 *d‡0ÆÂ‡èfHqœÄ..VÜîb ŽÒ ·y IÛÈ’(§LÉÒÙÊ–0“½Œéd&M:6o*É©³ç.ž=úÌ$ôfÑ¡HñiLÊôÖÑWO›\*µ*¬¨V³>Ä ’«VG^¿Š½6’€³hÓªE­ìØnßþˆ+wÄIºuóªÁ«·ï ¾åÖ ,À¯áÈ+Ö x±ãÇ#KžL¹rJ˜ÙZÞÌ¹óæÆžC‹Mz èÒO金ZªêÖ°Y¼ŽM»v­Ì™më^‚óîßCzþ¹t6ðãÈ“+_Î|¬ðÁ’7?.}úïêÓ#!ù,8.RMþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pH™gĤrÉl:ŸÐ¨4w¬¾¦Ø¬vËíz¿A«L.›Ïè´'®®ßð¸|N_¶õ¼~ÏïóïF~‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôX€HõùÔ÷2úþÑübüØ, ‚“¼Òk¡‹„ïÒ€HQ˜ÄŠ]L±1£ÇDÈO„üHrÖÈ$'•¥,Yh¥—Ç`²ô#sf…š6õàÌù`'Ï9> åTGÑ¡Hmeã°âÒ¤#žÊ ÈD*TVáQµÓôꎬ^%µ6öMYˆg§¥M³vS["oŸÅ}Ùu®>»aQlÄ›·¯¾~“Ü…°àn†+¶×u±ã–k%~Ìj2åËp#cÞÌ™åΠ©hMºÌçÒ¨ŸNÍ:êèÖW× ;í·k“}m&·î}¼ w½PBYßÃÑùFž¼6óÖ!ù,85RIþðÉI«½8ëÍ»ÿ`(Ždižhª®Và¾p,lmßx®ï|ïÿÀ pH™gĤrÉl:ŸÐ¨4w¬¾¦Ø¬vËíz¿A«L.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòDbUó÷¾õGøüºúF…þ!éGP…@Æ(XP! †h^H±•D3ªºHC# Žž?€ ég$É“žLÊRÈD%JH._ÊœI³¦Í˜6£àÌYbgŸÜ€îŠ’h6£xò„§ÔNS-O—JJµªÕ«¡¢bÝʵ+­^Ãz+¶l²fÓBAÛð¢Ú·ÝÂK·®Ý»xóê­Ëv¯¦‘}UL¸°áÃüR ü`$âLjç,²eÂ’3‡p|ٲƚévöº´ŽÑM{‰!ù,9‚FþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯°ªvËíz¿à°¸‚ÅŽÏè´zÍnSËW·|N¯Ûïm8Ïïûÿ€)zG‚†‡ˆ‰Šj„I‹‘’“:3”˜™š››–2œ ¡¢£vž1¤¨©ª«S¦Y¬°±²³-®/´¸¹º»d¶¼¿ÀÁ£¶5ÂÆÇȉÄÉÌÍÎtËÏÒÓÔ]ÑÕØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýî HP€¿ƒÛ\X0¯„Ç1œС«ˆQ¤(aãD‹þ¦2ŠÌå‘aÇ’ Ù\É’Ê”/ ‚ôԲ檘Oâ8Ó’ÍŸ¤vV| ”§Ê‡@“n*jhQH•J•ÃÔIU§B¡^|°rª×%W»–¸Jö)ׇb¿ª 6ª‰²Y±î”-íÚ»<ÚnEw®\œtѺÅKX‡Þ)úþ3ðV»ý NlV2Å¿tŒØ²>Ï“ÇVLófÍ(9Ó<ÚèQ]Ò¡)ÇÝÃtjH«½Þ›ÅáÜ`Í^uísÑnĽ}æ­ÄvÉHÀžœïräÁã7^<Íôâ´«{øÝ=»ßíºËŸùÞú,óáù¡GãÜcFö„T«‡{Ý|DÿâŸøé¡_{( (N€†0(ˆ‚=µW Za÷Žƒ`„¬YÈß{$pø†臈KLXF…Ô…ØŸ:&ö#(*¡¢ƒ¼BÜ̈‡wðH„¶(M}EäOëöj|Ïïûÿ€'sbxy9†‡7‚ŒŽ‘H„P‰Š–‡’š›œž”O˜y£vŸ§¨©ª«I¡QŠ<¥g¬µ¶·¸¹®3³f¾TºÂÃÄż2ÀwÆÌÍÎ϶±zÐÔÕÖ×}Ò:ØÜÝÞßàáâãäåæçèéêëìíî(Úˆïóôõšñ8öúûü{ø‹¹þ¡Á‚,F¿ƒÉ ÔRL‡#iøB¢Å‹3jÜȱ£Çá CŠI²¤É“(=P¬‘²¥ª…WJ鲿'˜ iÒ´ÉóÞ?ˆ:)ö '  ‰*mdôàÎ¥PY5-ñÔVU?È¢j½ru«…¬^ÃN*زhƒtM‹m-ÛZnßR‹+·®]!tïêÝ‹´àL²{¿É+©/X‚œÊ0¯¿I[NU̱Ǯ\0þ3™OgÊi,wÁJsä@Ÿã¤“¬h ¯Ó¬~3›u¿Ø@pc¬m»›îË›kñ&2¼·qÈ~%ÿ<Μøò„Å›K}ºõëØ³kßÎ}Åo‹Õ»‹'~|Ú!ù,8nGþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,ÖŽµ¢rÉl:ŸÐ¨têDZcÔ¬vËíz¿`îõ.›Ïè´z [Ùð¸|N¯ŸÝH»~Ïïûÿ#xG€„…†‡ˆ_‚I‰Ž‘*‹4’–—˜™Ž”3šžŸ ¡iœ2¢¦§¨©F¤0ª®¯°±$¬­²¶·¸°´6¹½¾¿—»ÀÃÄÅÂÆÉÊËhÈÌÏÐÑm´ÒÕÖ×>ÎØÛÜÝÞßàáâãäå|Úæéêëìíîïðñòóôõö÷øùúûüýþÿ ø ]‰*\È0Á‡ ’hH±!Ä‹%ލÈ1!Æçþ4‚IÒ„È’(Sª\ɲ¥Ë—0cÊœI³¦Í›8sÂéØQ§O<9þª/hE¢Hí¥˜”ÞɇK-6JµªÕ«X³jÝʵ«WqQ~ -ìB²WŸ2«P[h«ªýó¡ÛºqÁÍí±·O]‡yñõÝ1xÏßÀ‚©)Å‹Ø^ar‡o{Ü/2bÊ0»ˆ¬Yr…ÎÝ@Oíi5–—œ.}m5šÔ¬c‹‚-»¶È´më~’{#ãÝÀWàþ}¢wðã!†¿U¡œíÝåȵ67ëdzØèØÍXš½ûãA\›ï½¼y|äÏ«/!ù,0‚QþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€)zH‚†‡ˆ‰Šj„J‹‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîï^òóôõöðùúûüî4ý <ñoÆÀƒ=”‘°¡Ã µ<œ˜0" ŠZ´‘±£GKþ?Š4²IÉ‘(A\²2¥Kq-_Êìs¦Ml5o꜖s§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JªÑb°{XïQEØWÖ¯ó¶ìz ,X±U#^5›­@²¶Ø¶uÛn-¹XéêuVp¯»nû2²êW ^­ºަ˜Xc+“!̘ò`µ¨"Ó|ƒóÏQ@K~cÙˆh4§S¥]mõ©Õ‡í±îåš`iÔ·IÄ®7›Wm¿‹ïݬäêáCWf<÷åA /ßì\„ôé3WqûKí˜Qt÷žr<óäÝí¦ }zvëþŸß&¾¼”öñÑßÏ[þþ†ñ_€r!ù,/nTþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíV5ð5îóÃñö1ôùw÷÷úþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢ÅNüì]Üx(c<ާ y„²äŸ‘òLªT…’ÆÊ—0cÊœI³¦M9-gÜÜY&§ ž@ÃøÄÔËPÚÈ ©Ó§P£À£´(¶ª¤j•jµk¬[Ã:õJ¶¬Y^XM¥ý²ÖˆX±goµí27îÀºvó Á«×*ß¾€uüÅõ6làÈG NÌØÄâÆ#KžL¹²e}/kά¹s)Ξ“Þº´éÓ¨SŸ­UuhÖ\]wŽ!ù,Nn5þðÉI«½8ëÍ»ÿ`(Ždižhª®lë~A,Ït¼x®ï|ïÿÀ pH,ºlH›qÉl:ŸÐ¨tJý%¯²ªvËíz¿à°xL.›Ïè´z,h»ßð¸`M¯Ûïø¼~Ïïûÿ€‚ƒ„…xrˆrjXX†Ž‘(‰”n’—˜™šK••*”›¢£¤¥& ‰Ÿ¨Š¦­®¯¦«¬“²p°·¸¹†µ¶)¼oºÁÂÃv¿–¾ÆsÄËÌÍ]ÉÊ´ÆÐÎÖר§ÉªÓÕÙàáâßÒ¿ÔÛãêëÎå'îìñòñßõéóøùàöÝðúÿƒñ;çí^Àƒø#2ºn #J|±pHÃZ NÜÈQDNøé.ÊêH²ä‡ŠBD®ÊèФ˗ä Q‰ ¦Í›%P¡ §Ï:_URæÏ£H ~œYtiÒ"CŸnˆÚƒ*ž¤jduGWX=mëç+Цß¡mIV £+IÍâ Y?£m»¼M"a/’¼@ä^ ›JiZÀzýÖ@ìE°ˆÿQ¼X2)ȳ,ë¡Lc˜ãvk1jÞÃyÆhQ˜ãœÞ\:ÆjM©{½ÞúùRí·gëΖÛîáÝÀö6Ç6¸q}ÃÕ:=ÎüKr¿âmN]ËóœÓSf¯Î½Ùuß»‹—~¼ùóèñ•OϾ½û÷ðãËŸO¿¾¤õöó‹!ù,/‚SþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖdÙÚÛÜÝ×àáDÞäÞâçè;åëÚéîï*ììðôõ!òëb5û5öþøÊÅ h.¿ƒ1þ)LD° ІÝ$!D¸°bˆÜbÌ&q"? þ?Z·±]Š’#…Ür%‘$QjÜØÑ¥ ˜8+ ü–³'¸5mÂðI´šÐ›E“*]ÊÔЦP=J5ØÔªX¹\õ²5«W+]µÊüJìX0a˪e’VKÛµpžKÕÛºx;ÝÍË·¯ß¿€ œa/,ĉ!¦‚íÜÄÌž.VÑqIÈÏ$?.Òø×d)Ÿ©j¾œ¤³¯ÐPPCU—u×KaOMsšl%·‹æ¦m:ZnG>øyïÊÅ]OŽáxCæÐÛ,¿2=ºÒêUvoKÚº쌷/ï«x6äá¤/¿e}êó ᳟O¿¾&÷ö󳕯¿¿üþ$(à€X €&¨ 6øƒF(á„Vhá…„!ˆá†D!ù,0‚QþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌcÏÐÑÒÓÍÖׂÔÚÔØÝÞyÛáÐßäåpââæêëìíîïðñòóôõö÷øùèáúþÿ ,”%ËÀƒ¯L’°aÀ… Jœ¨"Š“YT’±ã»þ4<Š Áo›,3FªìPR› ”2TÀÔ²²&¨™0dâ´É³N)~öJ´¨Ñk-¹]ê+é4¦Pw9•¦bj´¨XY÷`ë3 ^«e›Í+X³]Ñ’]Û'ìÙ­o­Vuʶî·iáæ•›b*¼vÍ „·°Ú~ÏV|ã`@†õ.6‘ØÌä2—GŠÌEåb™5?âü9ah1§Eó M×]j0¯Uç`T¶íB´[ÞÞMml\y ñ{¸qBÅ+ÿ“|WðåÇšëz¢ôêØ³kßν»÷ïàËO¾¼ùóèÓ«_O¼1û÷R®ÃŸO¿¾ýûøóëßÏ¿¿"òý' !ù,3‚MþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàÇeXáåæçèéêëìíîïðñòóoãIôøøöH…ûJùëø£Ño Œ€/<Ød¡Ba$œ˜.¢ Š3jÜ8O€ÇÈ CŠÀ±$‹*P¦Ér¤Š–0?šÔ¦’IÍ7ÄŒ)a'Ì™Ùrz$¢Ÿ-{"u ôÑ!OED ²”iÓ«bÝʵNU]ÊK¶ì—¯!ͪ]˶­[8S‡¡ùÖ[\aseÖåvw¯ß¿€ L^^°…'쫸ñ!ÆŽ# ‚,¹²Ã$SP¶Ì¹ æ‚;·ýœ5´èµ¤O«ö“zµë<­_˦{¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+ÿT{¹ó!ù,7VHþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH|ÕŽ´¢rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§@Hª1¨­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍs««ÎÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèétЪNìHêñÔïG~ô5òùÍ÷IMÿ (@ŸÁ>üf|“PÆÂ‡#JœH±¢E Y5Éã¢Ç2m äø±d«&S–ByŒ¥Ê—0cÊœI³¦Í›8͸Ìɳ§ˆ>ƒ*´¨Ñ£H“ !È” Ò§ušJµj–©S%`•jµk›­M½ŠJr¬YJDϪ]”v­[+mßÊK·®Ý»xóêÝË·¯ß¿€ L¸ð °L +ØéâÇ"!ù,9‚DþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²‹zH³·¸¹dµ4º¾¿ÀF¼½ÁÅÆÇ-Ã3ÈÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâWÊZãçè‡åæéíî}ë0ïóôõö÷øùúûüýþÿ H° ˆx6 *\x0ž„£ ¦ÈÅ%+jÜø £!ÁGr”òVÉA'GrJ‹% —*1Át5žÈ˜8MÕܱ²œÆzæ ´($¢7¥ôXS’7U>}2uéè#«Zý¥uM×­`y|M36¬YeÏ6K‹­Z§XßÊ5! ®Ý»xó ˜ Ä-_¿ ô ÖË÷`¹‡ 牫¸1´ÄŽ#KžL¹²å˘WAÎÌÙ‘ÖÍC3-º4!ÒC›^5׬cÛ-»¶í؃s۽ͻ·ïßÀƒ ®R·nâÈE!ù, <j<þðÉI«½8OÁ»ÿ  dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬v;F¹à°xL ˜Ïè´:@n»M^è{N¯ÛIëüúÎ'Ç}‚ƒXz†g„‰U>ŠŽ8‡‡‘•EŒ@–š›œ“†¡5˜ ¢¦§‰Ÿz¨¬+¤­±²dªy³·¯¸¼½¾¿uºRÀÄÅÆÇIÂÈÌÍÎÏ-Ê"ÐÔÕÖÏÒ×ÚÛÜ·ÙÝàáâ‘ßãaµ{æêÎåëZèjîòÆíóVðiöú½õûþÿG) H° Aý*\h0!Çç9ŒH±b·‰áC“±c ŒþïlD²¤&çŒ4“²e”.i­Œ&ÍŽ6oZÉ©“"ÏžN~e(t¨’¢F93ÆJ6&…ñ´•Ô*U÷]Ú"+ª­}¼"ËU…XSd™Žd·´ì³¢ÒºÅ!÷\w]µ»s/´¼úô›D°&|0¾Õ5eX^c8„‘<ó ñ Å‘›MV·yKå¦vŸÀ,Œo¥¬µ|^{G4äÒO2·I5è`Kicq]‚÷ìÛ1uòíGöâc„3T.¹¸´ÎM0W8½OtpЛžR}û ì° v÷>¼.òèçš•¾½ûãÚßËŸOß1ðúøóg¯¿¿ÿÿ)(à€8 æw0&Xß‚¿4èà|¾sß„vßiº!a†ûD!ù,‚tþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùº÷úýþªüþ ¨) ÁƒLȰaŸ…#J„q¢Å‹c*bÜÈÑŠÆŽþ C"ù(²¤IpíNª\9+%Ë—0kŒI³&;V6sê41s§O•= t¨QŒE*˜t©S„MŸJýuªU|U¯j}—u«Wt]¿Šçr¬YaϪ•–v­[{eßÊM×v®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇQÕì(€å˘3k°t2eF›Coî÷s,Ѩ/“ÆiWêÔ«IµvýZtlN³oÕ¶­ÔsîA»Cßžô»¸³ÒÆ“SD~4øhå¡|ot®ztææXÿ£žÙ:¨¬Ò™qÇŒ+|MðØçW}˽Yø²½·Œ??nýB¸þ“Ä؃€0¨ÈUóqf Göñ¡O >!- Q…J2!:Äa‡N(ƒó¡¸"&ÞA"1#¾Àaˆk|…/¢£ 3â¨И#Yq¸c†@6Ñ"+9M‘)>àä BÚ‘äMù4e4UV°evY¦Òå7_63¦HgvS¦…Ü=’fk.ö&m:2çq*v'!o&³g y¨`}¶ó' ƒ“(`‡Rye‹©_ªåŠ*MÚW¥dh*Ž‘Q>ÆéžRQê b*ê£/êDªãI0ªC³¾ã*œQöˆá[µ*vk¯ ‹Ø¯¬:%ìЋlrÊ+.[\³ÎF+í´ÔV[Ü­ÖŠí…aòj¶Æl ncâŽ+g±æ¦û@¹ê!ù,;‚=þðÉI«½8OÁ»ÿ  dižhª®lë¾p,Ïtmßx®ï{臼 pH,ȤrÉlÆ~ÐŽsJ­Z¯Ø¬vË=E£Ý°xL.›ÏèÞ÷—n»ßð¸|Ž[³éø¼~ÏïSí>~‚ƒ„…†‡€@ˆŒŽŠ‘•–—˜™)“”šžŸ ¡…œ¢¦§¨©ª«¬­®¯°±²³´„¤Rµ¹º»©·¼ÀÁ‘¾"ÃÇÈÉzÅÊÍÎÏeÌÐÓÔÕMÒÖÙIÜÝÞßàÚ½¾ãæEáéáç¦Øìï8êòÝð îõø1óóùýþæûäýHðY@u* v0݇e5\±¢ª‰à²aüf±ã©þÞ4‚äæ±$¨‘$­¡g²%¦•"GºœY ¦J”4s:²Y§ÎŸ„|N ´è¢q]zT) ¤‡ 2ÚFj «ARÝêë ¯¦À–¸×B,×]fG¤­G–ÅÚ)mÍÄmöCݳvµŽ™K†¯Ñ»&m^âWLa ƒ= Ök¸Ü›ÃýËÄû@2È3¹dÆgy#åÊJOðü¹UgŒŸEË ]zÕé‰N6R­ukס#‘í‰öSÛ·¯ê6óºalÇxYÿ:¼ŒoÂÈÏ*_^‚63Ý\o9=!mëÑ]<§¦{ÁïÍ7…/›ž¼{1è³Wm?dü{ÅôMØG²EÿûÅMwÙ’ö€ÓHS p¯ˆ B æW„¡8ø`AÊ'…'qx!Ûa’ဿihš‡êâ%#šçŠšX˜¢ +ZÒ"ƒ3æH™Œ:º!ù,hG"4þPÈI«/ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‰Š‹Œ‡‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»™Ž¾Ž¼Á¨ÄÂǤ¿ÊŠÈÍÎ=ËËÑÊÏÖ×Ô¿ØÜ,Ú¾±ßÀÝä'âáç‹åì$êëí+ïÌñõö÷øùió‰úþÎüý, Áƒ¢ "Ĥpa6~4421¢EV/j<•q£uECª)²¤É“(iu 1¥ËK+_Ê$s¦MD-oêTsçΞ>ƒn)Ft´œB“JDÚB!P¥PEM1µ¡Õ¬º.;¶ÂÙü ¨ ‚¢7L¡Ã‡Gæ‚H±â‰¸d`¼e±#¼þËb€¬%Á (ÓŒÜÕd¥Æ‘%MzHI³ŒË–0Eæ¬ÉóÎM&?_#sfÏŽC“$e±ôKQNGžr0#UÄÑ‹;—4U±µKÕ«»{‚,سcÌQ‹¶m#¶XAºûç&\ºxÙÍù5¯_G{å>¸û·°¤À +v†c:‹Á5–ø8kä9!_Þ j2CΠ÷ôjáèÐiúžV¢¹ÝjÔT¥Æ|ê¤5»×°É¨–S°Cܹõ.c8q;Æ»Hžƒ¹¢¾¶Ñ8WîEæ¹èg¦Sçb}»íÞ³tOÞJùðæM¢'ƒ}}Œñî㯂/¿¾}Yçïës3ÿþÿj´à€xHàsˆ %!ù,8>R?þ0ÈI« /ëÍ»ÿ`(Ždižhª®lë¾p,Ïtm߸xíWîÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘<”’—˜›œžŸ™]••¢¦Ž © §¬­}ª°œ®³´µQ±±¶º»¼A¸°M¿ª½ÄÅt©ÁÈŸÆÍÎkËÌLÑžÏÖ×bÔÊÚ¡ØßàXÝ›ÜÚáçèPãÞKëéïðGîÓãñö÷"óóíõøþÿôõã×  A{ ÒSøbßÁ‡š[8±á@ˆ÷H¤VŽ# ‡ÕCÚÙ-)JKŠ\Y‡ä2“'w¤|ɲf—È`Æ´`³'Â~ Yììá³(º G†ò4ÊôRcJ+4ªäi±¨¨j5bu«×¯%º‚KvƒØ²*°ZBûì,Ûj%¼…„SØ\X¨7iܾŒÜLxH\ …Û<¬¸±ãÇ#KžL¹²å˘3kÞ|“/ç϶ƒ-I4éÓL£^H5ë׃\Ãúw¶Ù¶S0έ¨gÞvŸ™3àïáÈ“+?‡{¹s4ÍŸŠ:7ºôë`¬cw!ù,>‚>þðÉI«½8ëÍ»ÿ`(Ždižhª®–à¾p, lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl6ШtJ 8¯Ø¬V‹ì¾¶à°X\-WÇè´zñzÙð¸Üd®Gçø¼žçîîÿ€‚ƒ„… }H†Š‹ŒŽ?ˆG”•–—˜Œ’I™žŸ ¡J›2¢¦§¨©ª¤1«¯°±²Ž­0³·¸¹ºhµ_»¿ÀÁÂ:½.NÅ4vvÃÍÎÏ>ÈÇÅÐÕËuÖÚ´ÔÛÞØfßãƒÒäçèéêëìíîïðñòóôõö÷øùú²æûþÿûHžÀ‚*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£ÇÑ CŠI²¤É“(Sª\ɲ¥Ãpe\Êœyæš8sv°IÏ):ƒîú)Å'Q(¿Ž"ý£ÔŠPFM•pRT¦JŸBÍ ªªÖ¯-½‚‹R,Ù³#͆¸Š¶í;µ غý ÷V]rçêí˜wo£»~;,¸pB†ì¦8ãÆ"ŽLyÞä6¤ ^³¹2Î-2?íùi ­4?.}ïô„Ô¬c¿rM•Tߤ\eS¤ý¶îߢxûNÞpÙ¼‹{:®¼9:æÎ£{ƒNwµô}!ù,;‚@þðÉI«½8ëÍ»ÿ`(Ždižhª®–à¾p, lmßx®ï|ïÿÀ pHÄÌŽ³¢rÉl:ŸÐ¨tJõ ¯¯ªvËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„@‡ˆ‰Š‹…Ž‘‘Œ”Œ’—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±² XX³·¸¹º»¼½¾;•Áˆ¿ÄÅÆÇÈÉÊËÌÀÂÁÍÑÒÑÏÐÓרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#N«uE¢Ey‘\Üè.㎎ «xL’f¤Œ(Û˜ŒÑ°Z%5.)í‹i)¥Í›WfÁRçÎ_>]ðì´XPC“^;ª´i4¦)V:z *ÍE¤RÝêÈêÕDYMr;Èë×CaG’]ëK+Û·¸ÜzƒŠ†.Ü»xóêÝË·¯ß¿€µ+˜ÉÙa¥£-ÌxáÆI=ŽLyÏäʘí\Îü*!ù,‚pþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹®hÜȱ£GþC>úHò£È“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§O)@‚~øI4‹P¡E“V9T©Ó§P£Fd DªÕ«X³j­FõÇÖ¯7ºKV†XeÓ=B­ÛlA¼{"îPºxóêÝË·¯ß¿€ƒ³ëA0^Â$ +^̸±ãÇôJJÞhiòdȵ,K®¬™$fZ=W mò³,Ò9£¦l:ÖjŽ_klIöì¶A–É-ƒ7íK¾}“þ‚øïIÆS%g±ú¸šå§ «hîôR×QPwøj÷&Ù§moñ]jù—ã«KM¯*ûöðãËŸ/.<ýšöïë'•¿ÿÿ(à€ˆNê‚`‚-È çiãàƒ8D!ù, VmþðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ËaîÀ pH,Ȥryô9;̨tJ­Z¯ØìôùÔz¿à°xL.«¸N³zÍn»ßpÚ¯Ûïø¼Þ6ïíÿ€‚ƒk}?„ˆ‰Š‹Œ8† ‘’“”’•™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çì y]ò²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´èŒ‘PŒ*Õ”ÃÒ§7šŠ€JJj7«TGaݶ5+¨®ÙÀzK¶¬ÙbϪ­v­Û¶n±ÁE4w]]ŽwãšÈ«7+ß¾PÿL¸°áÈcX̸±ãÇàNÜ ²eÈ’›Rfw¹3ãÌH7‹Mº´é"ž=Ÿ^šºóê×°cËž½¦õeÚAm[Æ T7fÞÀƒ žiòSã.‘+UN¼¹seÌ‹ú~ü¼ºõëØ­GÏν»÷ïàËßj;y)ÓŸG™¾ñzV!ù,nfþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ïüè¼ pH,ȤrÉlV~ÐsJ­Z¯Ø¬v{F¹à°xL.›Ï0/Ín»ß𸜥þÍïø¼~Ï'Ö}}‚ƒ„…z@†Š‹ŒŽHˆ"“”•–—‘!˜œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\ȰáM JÔQÊÄ‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ Ú«¢‡zFIm•©Ñ¥LŸÒk µêªV³nÁªµ«W…\¿þ ˈ¬X~f¥=›om!·á²…#7`ݹxmÜÍË7ÆÞ¾€éH L¸0³¿ž©x±ã'ƒ—4~oüôæ­¿¿þþ•+€NF`äˆà‚ 6Ç}b¤`„ÚMHáZ^¨\†öÁá/v¨G!ù,*‚SþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈËÌÍÎÏÉÒÓÔJÐ×ÐÕÚÛÜ6ØßÌÝâãä&ààåéêéçßëïðÕíØñõö«¬$Mó×÷þÿXòécÂ/ÀƒåsRðY‡…dذYÄ‹/U´˜±£ÇCþÃ}IrOÈe%Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÔ“Ѭjõ‡u«×z]¿~Y(–Wز&¢Õu¶¬Úµ¸ÚŠ} ÷ ]jå~½[— _dÝè}÷·o’ªöŠ8YÅ‹µ6&4yHåq—#‡Ễ37Ïš5Î2ºVéЖN[Q-‹5êG®‘Æ~Íh6í¶oãc‡“îß7r/ñÝ:0p`Â*š•üø§æ)¡;ŸNÝÚÉêØ³kßν»÷ïà•J¿2ùã¡ïkþ|ôCÛ»ŸO¿>Nùöó£_ß¿þÿÀ- LzQà€ŽÅ[Zü%èà>(á Nh¡ ^ø^ƒ÷¨•¡†ó}b%!ù,6‚JþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,H¡`Él:Ÿ‚¤tJ­>€ØuËíz¿S¨ .›Ï,Ín»ßܱœ ¯Û…êõ}Ïïûÿ€Sy@‚†‡ˆ‰Š‹v„?Œ‘’“”•*ŽA–š›œžo˜"Ÿ£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅ`¡!ÆÊËÌ’È ÍÑÒÓ|ÏZÔØÙÚ]ÖÛßàáxÝâåæç.Ý$èìíîêïòóåñô÷øÓöùüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœ iÍqÖnⲩsÏž±~½!t虢—ÈÕté—¦( UJKªÓ-VKdå1gŽ•­W%‚]ÔUÎW¥cÃÎK›¨ì˜³9¯PÆh]söîæÒKƒo8¿àòÎm8Fám‡&–µ¸EcjùF¦–X䪃÷P®ÌTæ;›;‹>ú¹Q¨Ñ¨Ë\.:µk¸Ï^ËÆ¶z¶íTµoë˜{·oN½/ÿMÜqiË+zÜgóåÐY?N½ºõëù’cßË­‚ãrÃ;™*ÚÉï6ÿvkõðS°w_òôyó›HH_¿þþ H€èœx!ù,7‚GþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z%‚¬vËí ®à°xL.›Ï!¯Ú‹n»ßð¸|ZÛµô¼~Ïïûwwƒ„…†‡{vˆŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ5Ù5×ÜÝœÚà1Þãä“ááåéê‡çàëïð{íÚñõönóÙ÷ûüaùÛý H° ·4 *\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç1Ãg|)0¤ ’(Sª\ɲ¥Ë—“­I³šL55sê¬p“ÍN&ÅýŒÔ³ËÐAa…T”ËÒIm̸[ÈÆk=Žd1e'“/k^•y³çÏ C‹–cy´•¸¦1”öŒÚ¬Ú_«S¯k-»6Ó×¶sëÞÍ»rßÞÀƒ N¼¸qa±+w!ù,8‚IþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|%üÀ p(èȤrÉ4Öžµ¦tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâyPå1ãÉDêDèVææíÇëó@ñTïå*øPö•ôôý¤ì{¢o €“þÍCÈÄàÁg0Œ¤pÝD%e\üUQÝF$þÏ}äÕ‘ÝÈ!aœÜUrÈÊ—/[ Ió£Ì 5y¥´‘ÅÍz=síDö󇕢E‚⪴Ҧ·˜Bñ´]UNR§j5ru«Wk]¿Šv¬YfeÁ¥= m­7·l›Áå6÷Cݸ™îfÓË/^EUøß¿ˆÛÎ@ø'¸¬‰-ÆÐøæã”Î Çš|£rEZU5#ýг Ï A&mŒu+Ó-PÿSíøk>·ä^)à,؈vGn|sáá ‹“P®ø8ò€Ì]Eß4ý¹õNÕ¯kßν»÷ïàËO¾šðòè1=Ÿ¾½œõ˜Ý+Ê.¿¾ýûøóëßï‚=Q!ù,9‚IþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,H!pùI:ŸÐ¨tJ­Z¯X“™íz¿à°xL.W¶K³zÍn»ßp,¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚ»ÝÞßàáÛäå|âèâæëìpéïÞíòóôõö÷øùúûüýþÿ Ü1çÇÀƒ7 ’°¡Ã E<œH,bAPÜ <ŒØ=pÉËã;!IªÄe2ÊŒ+Õ„JKt/-ÖÜ ë¦º3Iðº-è"£o|†#º©¤NÛ(ÇÔ\T6Pgʘúm+×nUÃ’ú 6ÙqbÓ>;«¶-3¶nãÊË’ì"¸tóêÝË7ÛÔ\xû®ü[÷«àÈ+^̸±ãǦ®:“ ¹eBH»¸\¨VQœe¶ë9egl¡¥²ú4³Ö~`óííÚ¸sëV|{·ï>½ N¼¸ñãÈy˜ÕtòçWšÃ„NÊòêØ³ku}û¤!ù,8;>HþðÉI«!ëÍ{¸`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø˜gëÉz¿à°xL¦pÏš²zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾AÁÂÃÄÅ¿ÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêºÆíÆëðñThhòö»ôg÷û·ù\ü–ò·E ÁKî ;Ȱ¡Ã‡9*„H±¢ED»”ÉØAGt/~Ü fdš&3ÀJù!$–‚`º¤(Sb™8óÈÌɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©'›îœJJµªÕ«X³>…úN+Ñ^·õ36,¶²fÓª]+ -Û·pãÊK·®Ý»xóêâv¯ß }ÿ ,ØM!ù,<‚GþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßp7¯Û1óß}Ïï#óA~‚i€"ƒ‡ˆ‰>… ŠŽ[Œ“”Š‘S•™L—šžŸpœ$ ¤¥¦§¨(¢©¬­®¯«°³´µ¶c²·º»¼½B¹¾ÁÂÃÄÀÅÈÉÊ·ÇËÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèé%ÍêíîÙìïòóÏñô÷øÁöùüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹¦öaÜÈÑ…ÆŽþ CŠI²¤É“?¢\iQ¥4—V`²¼&s¦†š6§áä³óSÏœõ8ú©‰(PT’*]Ê´© FJíæ´ªS¨B§jgµ«R¬—Ödݪj,YJQÁFRË(gÚ³¼dÉ5Ûð-Üv—Ì ûàmÞ»ÿ&Ù»¶/Ý~ u‘ñÂm}*ææøaå"'Þüä2®ÃœC?-ºt;ϦSÇ$mµê×Â\Þ½Kö]Û´?óÍí‘5ï3¸wð-¼¸ñãÈ“› ®ü(s,ϛی¾z·ôël'S¯±»éî3À{-þW¯ãY•×G|Èù®éã¶.¿¾«õöóëßoú½UþÁD!ù, Ej>þðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬v;F¹à°xL.›Ï,/Ín»ßð¸¥þÍïø¼~Ïïûÿ€wu>…†‡ˆ‰Uƒ@ŠŽ‘’tŒ“—˜™š•–›Ÿ ¡¢\£§¨©ª<¥R«¯°±²­³·¸¹º»¼½¾¿ÀÁÂÃÄÅpµ"ÆÊËÌIÈÍÐÑÒ6ÏÓÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïð¢Õñôõqóöùúdøûþÿ xB€Áƒ*ð®Á‡4J\±¢E3¼È±#;‡¹œjy餓$SòA¹R¤Ê—0cd‰J£F™8›Ðb3£“ž_íÌ)ih  % ¥Ød©B¡.‰†sšP)ÕO¢š3*UÚU¬_ JລÓ,²]_…e˜µÕ±Jgµ¦å†v®Ý»x½†•±Öê×¼€±õ}08°ahƒ ^l,ñ^Ɖ)ŽL¹2Þº–3kÞ̹³çÏ C‹Mz1f<“K«v‘ÉéÕ°g´ŽM;ÔìÚ¸3ÝÎÍ»·o߯‹!ù,K‚8þðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡ˆ‰Š‹ŒA‘’“”•."–š›œ‹˜!ž¢£¤¥.¨©ª«¬k S­³­¦¶·¸†´»©¯°$²¼»¹ÄÅÆpÂÃ1¿É´ÇÑ)ÌÀÒÖ)ϳ¾°ÎÙ¬×àÔáäÞßËÌÝç½åîãîñìªNôíòàðùñ÷¨öþø HЂ?WM\Ȱ_À„JœhL!Ä{3j4e‘IÇþ CRú¨„¤È“(Uì[bIË”0c^XIì¥L6oN¢™ËbÎ1<½üÔÙ(è-ŸY>4Êe(ѧub¼HOÓ-N¡jEö0+‹WµxÝJöŒÔªTÙ![¶­˜³jÓýZ‡Ö­Ý»*àžÛ ¯ß¿;Øf ¸°á<„+FömÒÅ·6ú8²#u–›v­ì³›Äv'gV:tÑš§ºé;5d½ÞøbÂËz´íÛijãÞÍ»·ïßÀƒ nÄ4ñãÈ/OÎùòæÐ£ë|.½:nêÖ³[Æ®½ûaîÞÃû/¾¼D×È›ª~kûõðoÂο>ÔùÏìë—¿Yõþÿ"½ H!ù, Jj5þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH ÖŽµ¢rÉl:ŸÐ¨tªDZcÔ¬vËíz¿`êõ.›Ïè´zÍ[Ùð¸|N¯ƒÝH»~Ïïû[xGNI†‡ˆ‰|„4ƒŒ2Š‘”•–—˜’›œ8MŸXŠ™¦™¤©ª$¢0Ž¢«‡§³•±¶·­6¡­¸}´´¾ÂÃÄÅ]À³ÆÊËÌÍ<ȧÎÒÓÔÕЦÖÚÛÜÆØ¨Ýáâã’ߘäè¾æ—éíîïië–ðâòµôøBö”ùÜûšý>Û'ÐÚ¿‚oL¡+!š…#ž€x¢¡Ä0/jüñE¯Ì^:‚yAä‹ýP.1I²å–!TºœI³¦™6sêÜɳ§˜>ƒ -Ep¨Ñ£Dí!]t©8‹Mmâ$Õ)7¨ENRÕª¶­^* K–X#v-ëó,·ôÖ²å ×GÝwrç꼫EÞ¾5ùü7¬àÁ} ÿÌŠ¸±cŠKiÎ ãɘã¬;¬'ræÏQÖMZ„èÒ¨S欺µk8¬_Ëv{¶íjµ+ä¾Í›Ùî ¿{ |¸ñzE‹_ÎÆó„…XÇ2!ù,PG:3þðÉI«½8ëÍ»ÿ`(Ždižhª®¬$¼p,ÏBkßx®ï|ïÿÀ pˆ¡iĤrÉl:ŸÐ¨4s¬Â¦Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬—VV­±²š¯U³·¸‘µG¹!¿ÀÁÂýÆa»FÇÄÍÄËÐ[ÉHÑÎ×ÀÕÚQÓ3ÛØØßãKÝ2äèédæ1êîïÒì/ðôõNòóöúû@ø5ü@Â]H°` Î *\Ha³}þJœ¸!b ‹3~Áø‡£Æo =‚ P$É“g>Kcr•Êa(ÿ¼¦¦¥ª™ÁbúÁ™%>\<éDis¨Q9A‹5)z´©1¦w’:ºª©T³jƒu«WY]¿Šdn¬ÙVeS=ËvHZ3a-YmK—Òܺx7þÌËÓݾÇ"!ù, Kj4þðÉI«½8ëÍ»ÿ`(Ždižhª®¬*¼p,ÏBkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍ[Ùð¸|N¯ƒø¼~ϸÜGv‚ƒ„…†‡€ˆŒŽZŠI‘•–—˜™&“3šžŸ ¡fœ2¤1¢©ª«¬B§X¯/­´µ¶·!²5±²¸¾¿À´º¦½ÁÆÇÈ‘ÃÉÌÍΟËÏÒÓÔ…ÑÕØÙÚ£ÅÛÞßàP×áäåæ:ãçêëì¹Ýíˆ}ò}ðêé$÷õ‚óüyúæùDü7§_?‚ä‚Pˆ°‰A~ÎkŽ¡‹ÑH”—ñ Fî7„Tµ‘Þ£’|:z™ƒ%—*¹ Ü“Õ2˜pÖ¤2SŠžþvf¹ùN¨1 x~"5*¦˜N¦šúI!ª¢¯’U%·EW«N°ž ö+Ù%bI…jv-‘§n™¶.ÝsïzØj—]ß¼zÿñ-jõïÒÀÖ#Nœ•êáÅ‚úB^©xÄàI“»HÎŒM-gI•?×ólsӢײzaèF¨SËnÑ:ÑkFi9ÍÞ}£öÅÛˆbóN·6áÄ“0ž ¹òçCŸ~W:õëÇúZÇÎ[cÚw\|‡ðßÉ«‡„~lŠíë}E!ù,G‚8þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´ x®ï|àþÀ pH,ȤrÉLÖžµ¦tJ­Z¯Ø¬vËõ@¿±®xL.›Ïè´º¯ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„fm_…‰Š‹Œi‡POŽ•–—˜™l“4’œ3š¡¢£¤wŸ §2¥¬­®¯vªa°´µ¶·U²0¸¼½¾¿)º6ÀÄÅÆÇÈÉÊËÌÍÎÏÐ\ÂÑÔÕÖqÓ×ÚÛÜYÙÝàáâDßãæçè#åéìíîž²ïòóæë‹öôù[ø‰ü…þúR8ˆ Àƒ "\ÈЕÂ2Jœ8!â‹3"ÄØ…£F\à=BöøHÂã>]$Sj4©…¥F‘0s¨dærf¡˜1m*«©³§Ï–( º†§ £D“žCŠ‚)7œ0B9Ñ© «J­M Y5è@¯Y¥nåÑ5^.°a±ºKV¢ZuhÃêc»C]ÀÞŠÐ+·Ù]™)þâèK¸Ò©9‚}\¸ñÏÄv;žŒr"Ë_ÍÎáK™fBŸ·qî,*´ Ó×F“Ö„ºHëjHU¯Æôzvª¸%qÛNV{·Ù¾õN¼ø±áFbë6Μò"Ê57Ÿ^ç9¹åԳò®½»÷ïàÕpO^`!ù,G‚9þðÉI«½8ëÍ»ÿ`(Ždižhª®¬$¼p,ÏBkßx®ï|ïÿÀ pHäÑŽ´b%Àl:ŸÐ€rJ­Z¯Ø¬v;DzaÖ¨8Ê-›Ïè´zÍÆ|¿á±œÙ®Ûïø¼~ÿöÆçc{‚ƒ„…†‡'}H€dˆ‘’“‘ŠG*”›œžŸ ™b¡¥¦§¨©ª«¬­®¯°±²³´µ¶–I·»¼½¾Z¹3¿ÃÄÅÆ6Á2ÇËÌÍÎÉ1ÏÓÔÅÑ`©×/ÕÜÝÞªÚ5ßãäåáæéêëuèìïðñUîòõö÷8ôøûüýúþâ(° Áƒ*\Ȱ¡Ã‡µAœH±¢Å‹3jÜȱ£ÇþxF9"RžH(%Ñœ|âBbÊ{+´¼63ÚK 1›ÔLvÓ^N:Ü‘ìùà§” .‰¶0Š)RšOm*]òsg°ŠCE8ýäThÒ©¶‚Ê3…ØN]]fËVÄZg9¥…úöGݶ ãÚò •Ê]¼õÖâ+ÕïWÀ {#\Öp_Ä©1¾:ïpäËË&ç²ò³ç+ù¨µL¤óçÓBëÑl‰3é.¯QËÞÁZ¦ªd)ÏÞ=xôcs ó«vŸÛ9­n&Îü™iœ¸Ÿ7Ÿ®Cqé‚7¦Îˆu Øo„ïNþÄw»±¯§/ϾÕxCçÛËŸò¾Püùø…ÔÏÏÿÞþþ (à€˜n&ÈO!ù,G‚9þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏJßt«ï|ïÿÀ pH,<œf[*‘ШtJ­Z¯Ø¬¶é¼m¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ_]8€„…†‡ˆg‚^‰Ž‘r‹9’–—˜™”3šžŸ ¡qœ2¢¦§¨©U¤1ª®¯°±)¬L²¶·¸¹º»¼½;´/¾ÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙCÜÝÞßàÚãä-áçáŽèëÝåîï$ììêòèð÷øõöûçùJð—®Áo]K˜ì Bƒ¹1Vƒá±ˆí F´ÈqF‰ÆvÌ÷Q\Ã*JVQ9òKd,c¢¤ò²¥»šÆpÒiSÏa?íimh/£}]êKé§L£â‚š‡j&ŠRGZÍj+ׯ`Íx K¶¬Ù]cϪ]ÂkZ¶pã^p»P®Ý»³êâÝËÓV;û N Eà,^^¬Fñ•Ä3K®‘ãɘÁ\†³ùÁÛÌ ;‹ݦógÐIƒPº5=ŒHX»žM»¶íÛ¸sëFtzwGÙ¾ƒÃ¬,¼ø;àÆ“óB®¼ù­!ù,8IR4þðÉI«½8ëÍ»ÿ`(ŽdižhªfAë¾p¬tmßx®ï|ïÿÀ p˜’eĤrÉl:ŸÐ¨4w¬º¦Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯ÛÕVë}Ïïûÿs‚ƒ„…†€‰Š‹ŒŒ‡‡yU•–—˜L›ƒ™žŸ ¡Kœœ¢¦§¨©ª«¬­®¯°±²]“G³·¸¹nµFº¾™¤›¿ÃÄÅRÁÆÊËQÈΑÌÓÔCцÕÙÚÛÜ{¼HÝáâãäåæçèéêëìíîïðñòìß1ã×…óúûüpõ0ý H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱc®U/<ŠlòÊÈ“K¶@ɲ¥K *gèÃGè%Ę’TÚ¼sg¨ž>ƒºü'´¨;¢g€]Šƒf'?J¹EeJµªUŸS¯jÝʵ«×¯`ÊK¶ì˜¬fF!ù,J‚2þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÑŽ´¢rÉl:ŸÐ¨tJõ ¯0[íz¿à°xL.W¶W³zÍn»ßp*)Øïø¼^ïûÿ€‚p{…{ƒˆ‰Š‹ŒdsG‘’“”•~I–š›œž@˜3N¡2Ÿ¦§¨©>¤1£¬/ª±²³´¯°M·5µ¼a†¿w½ÂÃÄÅNÀÀÆÊËÌÍ)È¿ÎÒÓÔІÕÙ`ºÚÝ+×…ÞâQÜãæçèŠåéìíîïðñòóôõö‰ë÷úûü#ùý tqk Áƒúþ!üîЇ#Jœ¨L!Å‹#•³˜qàÆ‚Š—||òáHV%•pLɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£æêAÊ´é¥yê­tª *ª_¦bÝT+V¯\í1¶éIRaá”ݱ6퇶nã„‹­Ü»RA¢°[Q¯<ºxo¶À7°ávƒÏ„:̸±ãÇ#K®g5ØäË#!ù,PM:1þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p ¢Bmßx.Ì|ïÿÀ pH,ÈKlK:ŸÐ¨tJ­Z¯N¦¶¥Ún±à°xL.›Ç^m7½<»ßð¸|NG²Ûõ¼~Ïïû­wMƒ„…†‡ˆ0‰Ž‘I‹/’–”.—›n™\Už,œ£¤¥¦¡2 ¡§­®¯‰©€¬°µ¶·r²¸»¼½¾º¿ÂÃÄÅÆÇÈÉY´ÊÍÎÏqÁÐÓÔÕSÒÖÙÚÛ>ØÜßàáÞâåæçèŠÌéìäì¤îïáñòõö¼ô÷úûüýþÿ1ä XJ×@‚W ®CøJ¡'†h„hÉa&Šf,RÂØp!ÇAq}I²¤É“(Sª\ɲ¥Ë—0 MŒI³¦Í›8sêÜɳ§ÏŸ@ƒ *Ó#Q"3‡$=ªÄ(Ó K¡:}:n*UXQ¯ª{h,«µ´Šð*¶,?²6š]k -µlãnr;®Ü»èâÝ‹K/ß¿¹:‰!ù,I‚5þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËXI`N¯Ûï·~ÏïûÿNpI€„…†‡ˆ‰)‚HŠŽ‘’jŒJ“—˜™š‡xx*•4›£¤¥¦^ž©t ¡2§¯°±²=ªª¬­0³º»¼½µ©·¸¾ÄÅÆÇÈÉÊ*ÀžËÏc¸ZÐÔ8ÍÕÙ[Ò¹Ü6Úן˜ãwáè{ßéævìðñoÜò,ëõø¨î«l÷ù'þþ ”²ßš€E LÈÐHÁ9m6ì q¢Eóô£wñCÅŽþ odŒÈ1ä†&S¢¹QšJ (_Bc‰,fJ›2•Ñ<†3dÏœÇvøs(1¡ïÝ´4%RHOó)-É«©É¨B¬õÈQë%¯±»õdWª»ÈZ dªË²Üó¥v"Ûr[Á{öm¯{wáî‘7Ô^ …+ý|¸±¢ÄŒ® ÕÅØ±åBIöË«òåÏ}2ÃÙzøI¨H„6A¡ƒvH܆•`èáˆð$H≠ƇâŠ,>§â!ù,8@R>þðÉI«"ëÍ»¸`(Ždižhª®lë¾p,ÏtmßxŽ{¼§ÿÀ pH,ȤrYé95̨tJ­Z¯ØìòùÔz¿à°xL.›¸N³zÍn»ßpº¯Ûïø¼^6çíÿ€4}>‚†g„‡‹Œ‰ŠŽ’“—˜v•P™Œ›¡¢£¤nŸ¥©ª«¬J§­°±²³.¯´·¸¹´¶º½¾¿˜¼ÀÃÄ)ÇÈÉÊËÅDÂÎÑÒÌÕÌÓ@ÐØÛÜÝIÚÞáâミäçèé*àêíîèìïò»æñ¬÷óú#ÖýÈp¶ò©¸¯`þ:¬ç‰¡Á‡"öFOEˆû$Z£èðÐE/ø«a$ò°TJ.ë¤RÙÈ1-“qÜD©ã˜ÿ2á<öRÌÎf'ë¡ìI´è—…4*]ji%¦P£zq IªÕ«R¨&ÂʵÑO…Bmv«çk&­„È*ŠÅl°°IÕe{Å­Ü»ÅèZ±ÛN/^£|[Nç÷/ÑÁ†C í’¸'âÆ§Ù"òÇ–1Àíäpæ/˜?K¦C9®»Ð†P®µµôSyªWníªò¹Ø²s¯Æ­»wcÞ¾ƒßðÌr§ðãGlGμ¯íæÐ£KŸN½ºõëîˆcß>N;÷ïàËOþÝr,Þ˫ϕ~½û÷ðãËŸO¿¾ý(çï!ù,4‚IþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌh¬ÍÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùjüýþÿèH°JÀƒ *\Ȱ¡ÃiÏH<œH±IÄŠ3nz¦±£Ç½ CŠIrÇ’(^Lɲ¥Ë—0å œÙ/Mš/oÎŒéM'œ>òê.¨P¢H“*]Úm%Ó§&YÁq µª6ªV³VÊŒ«)¯Z߀ [d,Yg'Íqzdö¬[amßÊK·®Ý»xóêÝkÌ(@¾€eùýXS\¨ƒýÎtøiâš‹#›zÌO²]Ê-×Âl“rçÇšCgâ,º´éÓo£^=G5ë×n\ÞmF6íÛ¸s‹!­»·ïßÀƒ?á-¼8–!ù,)‚TþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóô&¤Súûüýþõ \sD¾ý \ÈpSÁ†#â(hP¢Å‹-(bÜÈÑÞÃŽþ C~ù(²$G&S^D©²eC–.c„)³f<š6s²Ã©³ç9ž+ Ýç³h. *†•¡T¨¤F£"Š¢iB©XcQ=aaÖ¯­¶‚ÛL¬(³tÐ’e¥¶gÛµ©Þæ” ×Ýšwë‚Ê“¯^M~ÿ ®„2ð`F]ÿÍýhøð¡Ä ?h,eûUÞ,ær‹Ìü8‹Þâ™h¢£S[)­ºµëׯ8ÁžM»¶íÛ­NëÃÍ;“n€½ƒ Ìz¸ñ.Å+Ç’|¹óçУKŸNvóê4~÷¾’{íØ}ë–å=¼ù àËŸ7~½û,íß˧¾ý%õïëßÏ¿¿ÿGùý §‹zº( .h_!ù, &jXþðÉI«½8OÁ»ÿ  dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑ0QQÒÖ×[ÔPØÜÝNÚ?ÞâãEà>äèé8æ@êîï.ì ðôõö÷øùúûsþÿ À¯ Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç÷ CŠI²¤É“¾ª(a¥Ë(cÊL!ïÃÌd/_«éá&²œ.Õ]éSO)M†ª,ÊtÇQN”²lJÕÆSI¥¬ÊuÆÕ®`ÿ| K¶¬Ù³\Ç¢]˶­Û^Z·¾K÷l\€ucÝ…9l¯¿¼°ü|7°_ÀÇ ¿Œ¸ñÆŽ#[,¹rÖ½2Ô^¢lù g3š;‹.÷TMèÑO“Q:"k1¯[;Œ †¶lš¥“Ùö²û6ÂÞ\€;Íí–p-Çs$/þiùçÌíA¯2=:¼êÖ³cÏ};÷âÞ¿£^¼YòÄÍ£FT½lö<ÝËÏP~~åúößD!ù,8&RRþðÉI«!ëÍ{¸`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂhÅÆÇÈÉÃÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéÐìêï¿íòðõ»óóöú·øòûÿ H° Áƒ*\Ȱ¡Ã‡#J„¦¬¢2%ýÚMÜÄ¢Gcö3ºãH’ÇÇDŽTÙK%£ô˜ò%½6oÆ48Ó¢’žkæjs§Ñ&@/âÌù! Ó¦G&M&æiÔ¨S‘]ÝÊÕZÖc]þù R¬Y5d‹Ý˜vY˜¶k'Â}›6®Ä¹`ðÚu¨×Kß:V÷úË…ðœÀ‚ÿÖ²8qÁÆX ;Öƒ8Žd+—'ß ü2o]ºdÅdÖÜ¢ó—ÑSPKQMzkX¯[Šm¡²#ÚlËn¤›W`Ü»Çô¾ÇTðàa†ëúý9àâáŽ;÷¢<›ôé\ªcßå:íÜÏyO^Äøòè+œOÏþúzö Ý7‡W~hú"!ù, 'jSþðÉI«½8ÏÀ»ÿ` dižhª®lë¾p,Ïtmßx®ïc臼 pH,ȤrÉl>~ÐŽsJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊQQËÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíî;ñòóôõïøÞöûöùþÚüÊûGК@ÞjEÂÁ€ #ÎbøÃáÃ}3¾¢èÃâÅzìC®âäÁÇ~"Sú: R¥K],齜y+æ<š8sêÜÉÈæ@ž@QùŒ'ƒ$ˆ Hë ½Ãè>N=$MUJš¥SÕ`ÍjckU\™l ;嫲IÆ¢eb¶èW®j×*iÛôíª¸r¿ÑU…7¯ßD}ÿ L¸°áÈ+^̸±ãÇ¢öBžìÄ«]ʘ—X®š¹sÉdA{Í…®SÒ¨‹˜6šzOà‚§[ËžM»¶íÛ¸Ÿ\v,:·ov¯CÞU¸ñ Äc‹ê–óñq½Gýù¶êE¦ŸÀn÷îàI|OþÂøòèO_~={&!ù,%‚WþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|Ž Øïø¼>@ïûÿDpI€„j{‡{…Š‹ŒG‚J‘Vˆ”w’—˜‘™K••ž¢£m›4¤¨? ”©­®[¦3¯³-«ˆ´¸¹±Zº¾"¶‡¿ÃÄ-¼½ÅÉÊËÌCÇ0ÍÑÒÓÔŽÇÕØÙÚÔÏ6Ûßàá´Ýâåæç’äèëìílêîñòóoÏô÷øùBðúýþÿ'øH° *Ô‡p¡Ã‡ìBœHq›ÄŠ32»¨±£GBþÁ=àø±¤I6!õ\±w²¥K”)ñ¬¼ö²¦M01eŽdy³§O:$ ÊE]P¢H“ª0ÊS©Ó§KY…Jµê¦4­jÝša*ׯ`9x K¶ìL^fÓªÅ0v­[¨mßÊE—mÓ¹xÞ}±7¯_yu¯öýKxhàˆ5NÌxââÆ>ŽL¹²å˘3kÞ̹s›œ–”¶ã™Öh>ÓN/S]úki¯‹Ånj63Û¿pÓö¤;Yw» .¼x9â_NG9çÌ£¯®ºôëb¬×½{íÀ{?E|óäÓ7A¯¾½û÷ØÃŸ’;ýûøów—¯¿þþnk“Y €_8Ø\¬Å„  fEXƒ)=xF„h!FaHŽa,‰mL‡$n!¢-(X¢{'®rŠ™¸âŒüÉ8ãE؈ãŽ@èÈã@)äD™Œ»HhdiH:³à’™5 åqöMiå!ù,‚`þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€)zH‚†‡ˆ‰Šj„J‹‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÏÐÑÒÓÍÖ×¾ÔÚÔØÝÞµÛáÐßäå¬ââæêë£èáìðñšîÛòö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ [ÑÓ²dÀ‘ÜLªä‡rÚÊ—ùZJƒI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯òш$3Xžbg-ûììδ2Ö²u«®ºxY°m;È®¼ öVC%¸Ý^~ÿîºøTcPM$–9keÃs^¾º9TgÀ ½|Mº´éÓ¨—ŽNmzµ׬CÃæ0;vÞÚpÛ–¢_ï ¿w; .¸ðEÆá%?þm9óçCŸÎÃ9õŠ“¯kw‘}»÷¾vUXÿnl¼‘î'Ì·–N>êb™(ÔŸ‘ßÞÒû–Déׯpåþïýô߀!ÀGà&¨à‚ 6èàƒ©éá%NèV!ù,‚cþðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÜÝÞßàÚãäKáçáåêë>èîÝìñò-ïïó÷ø$õîùýþûÐýHPBÀs*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱc™ƒþé<ŠÔÜÈ“(Sª$RòÛÊ—­ZzƒY$‰Í4ÍÈ„—SÈÍ›=Éìä4ÈO›EÅ —ÔÇÑ$M£nzŠDª©¥ ©*±Ê•’V]ÃFú:C¬ÙFdeœ]›(-N¶p ¹…·n ¹6ìêåƒw¯ß<}ÿ ¦x°áÈ+^̸qF¬Ž#{,¹rÊ–3k–Šyó“Âl;í.é!§KGJ}ˆ5תÁf6;¶¢Ú¶sÓª»÷ܾƒ Þ4ñã'Œ—ŽÜ‹r`ÏG0oþš÷ƒè §Sog{BíÛy@ö^|x+ä?˜?/5½‡õ웺ï?~ÑùêÛ÷£¿ÿÿ1Y9ÇGCà‘`–-蟃 FYKÆ6aIªv!H–¶áAzöa@!îGá0–(HŠ*!ù,‚dþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë5î5ìñÛïô1ò÷×õõøüÓúôý>û÷N ÁeÝIÀ°¡Ã‡œø*!¼3F¤Èq•Eþ 5Šdرä©3BŽÔhÒJ-/¬“ÓK{5)Ìd™3ÓM=ƒÚ™Q¨ÑVD7]Š*)D¦P£JJµªU?m\ÝJ)+ׯ`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ßJNþUå5X`‡ƒSNÌ8ÉâÆ‰<ŽLùÇäʵ.cÞ|CóÏœ¯‚MÚÄ貇 KMòÁéÒyXKÌööÙÚjÛn„;˜îÝÀ/üN\Âðâz#ïWøx応/Ï!ýt_Õ§»ÈÞâz/îÚW€_á×øð‘ϯS^üO£ìÛ§ˆŽ¾|Dö锿Ÿù}¤ýBä+Ç9!à€âˆÅ"£à 6h̃bFa…”]ˆa(mˆ\Vzh[!ù, jbþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïð`óôõö÷ñúûüýþÿ H¾ƒø ^ Á†BB#Ò{X¡¡EI”˜qÂÅ‹Ía}´HmdïL2Dɲ¥Ë—0cÊœI³¦Í›8sfQéP§O:B8áâÇ"CN¸Æä•cf¾lv3çÏçß“ät(ÑöHK6- u=Õ}Y·v=Oö—Ò¸p—ÐmïÞUó|ñâÈ“+'x|¹óçУK'ˆ:!ù, j`þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüÿ ( ŸAa<ÈЗ‡JœH±¢Å‹3jÜȱ£GQác¬|ÌÉ·’GFâB™ÄË*o½”qr&–˜µlÞì¦óΟ–zÖJ4’ТHMjli1§L‡A•Ú3êÓªV³jÝʵ«×¯`ÊK¶¬Ù³hÓ†›ª¶­Û·pãÊK·®Ý»xóêÝË·¯_Clÿ ØOá«:ûÌXÃâÆ£«’ eT—+wʬy0çÎ?ƒý"DÒ¨˜~XHtj„«¶ÆŠÓõk»¶oÓÍ­[.ïÞ7~›~/¶lBÄÉ%žv9óçLœ'“î—ºëMiC­}ûvìÏGôÞXü¿!ù, !j]þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë­cVìðäîHñ’óGõùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹³ÝK’±ã¦þ3<ŠÄRÆÈ“”JÆ@É’J,-c.zùâÍ2‹Ý<¶3'±ž:iúü)ÔСÀŽSŠ´Ó`O›êŠú‹ªÔ«s¬bÝêF+×*E¿zýJd¬L³dÓ~A«¶­Û·pãÊ­( ®Ý»xó ˜;‰m5½€õòœ%°a»„G9|X±ã‘~¯Š<вäË(,cÞ̹ˆfPŸ;ƒ++´hO¦OsJ½š´êW¬?º~Ýn6lÛ´UÅÖ´ÛDïÜ@~ÛÄm‘±á?½%÷g<0Ææ€ A\pz^àg¬ã5¨ý.öï!º#Ož‡øºåÓg8¿W½û4Ëß3d/A{ü¥Äå³¹/¬'ý%ü—TQ(B!ù, %jZþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pHäÐŽ´¢rÉl:ŸÐ¨tªDZaÔ¬vËíz¿`êõ.›Ïè´zÍ[Ùð¸|N¯ƒÝH»~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéê¦xGë¡íIïwñ2óŸõö÷^ù1ûÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(öÃ’²e¦•/\Ê´³ÆÌ›‘jâÜéH'ÏŸ‰|JȧP¢HÿMÊTÏÒ¦På<:rª«TAb ³uX׊K¶¬'_w¦íh¶­Ùin㊭µ6+2¹ré´[ o\½+]ìå;ʯ[Àý&,Êp[ÆÃ8~¹2—Ée-#«Ë 3YÍ C‹Mº´i|ƒsyËó6תVÏ];[mT²ÃžÞý#÷YÞÀuø¦z;¸ñ Å“J^Šù çÊ—@5Eõ“ï¦VsÝD÷ßIf~DùèχPÏ4»çtìÑqY¾ýûøóëßÏq¾uFm×!ù,8+>UþðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pÈ¡iĤrÉl:ŸÐ¨´s¬Â¦Ø¬vËíz¿%«L.›Ïè´º(>®ßð¸|N_µÝõ¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙwFÚ?ÜHÞ°à3â=ä2æêëè1ìðñîWñõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£ÇÖ CЉL€É“(Sª@²å¹y5R¬œ¹Ò¥Í0c¢ ÉóäÍŸ-rªèÙ¨ÑBe¥y´i˜C—Îtê)i¨¤I¥N¥jÏê¬P¹6ôš†¬X„fϤ=[pm·lã*{‰î»rᥴ—ͼ¼€ ì¨/áÃ( ÓZqá°Ñ«tL¹²å˘3cQ¬³f(ž±…þœy4éÓ¨'™Níx5ë×°?INéÚIíØ¯f£ÄÍ»òíÞÙ~ŸÜñ§‹ 89²å?•/kÖ“y³g9?‹Vz´é2S·ýUø4(Õ‚¯öÕZ_íf°÷Ê6˰©Û=€/ËMw·ØÞ` §GÜ*ò»–'“±¸5êǰ;´nB»ï®Ã‹O¾¼ùóè_NϾIéöð{¼ßü0~óé#Š!ù,9‚GþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿À:eXÁÅÆ²ÃIÇËÌÍÎÏÐÑÒvÉHÓרŽÕJÙÝÞ„Û4ßãäåæçèéêëìíîïðñBôõö÷øòûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3j•¯c¾Á ¥yY¯ I’!y…›!áäÈi.=¶Œù1¥®•2fÒ¼s'Ï>ÚÌÔ^Ï¢ú€"M:´)ª¥I¡:êK*Õ«¹¬¢Šµë ­KÀšà구 ±h¬’MƒSKж0ÌRTës \oáÊHwçÞ¿–úÒLX’à˜…;:ìR±cEŒO>žL¹²å˘3kÞÌÙÍÝΠE. ës´—P“>¨zµ/ÓÑZ»žG6íÛllãÞÍ»·ïßÀ]Àe8<ÝÄ+E!ù,=‚DþðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€)zH‚†‡ˆ‰Šj„J‹‘’“:4”˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄO–3ÅÉÊË*Ç2mÑÒÓÔÕÌØÙgÎZlÖßÖÚâã[Ü0ÐàéÑäìíNæ6Þêéî,ðõÙ÷òóßøÍæþòáNà }º!ØOá„#Jìq¢Å‹*bÜÈÆŽþ 1 ²¤I9#«\É’HJj^NkI“™LiNn®{ óZÍŸÄzæÔ“(УÀ„6QªÅK¤PEeÂtꉧQ³jº¤êMXµŠ%çU&Ø”cñq5¸¶HØ´pã–x{¦­Ü»©èޱ‹÷ÆÇ¾.Ê\ð=€Ã ‡̰UÃ~ S †ñ<Ç_!çøË‹òÏv@kF$z\é9§G«>™zµëŽ­_Ëž]3íÛmãÞ-Q7ïß}N¼¸ñã!b#_žô1óçØ”CŸ~K:õ‰Ö“e_!¼G÷ë:¶ßþ^“x6úÈ—ÿ}žIzÄê×Ë—óžÛÉóóÿ©ïL¿ÿ[ñý'`;í h`$çx (.èà >(á"!ù,F‚;þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€)zH‚†‡ˆ‰Šj„JM‘’“”‹—˜™š_4N• •›£¤¥¦>3§«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂî©2ÄÈÉʆÆZËÏÐÑlÍ0»¡×‘ÒÚÛoÔÖØ×ÜâãKÔ6˜àáé¡äîï¨Þèì¢ðæöù÷ò—ôõúðH°`*ÌáÒ%„ #J<ÑÐÒ"ˆ3j†q£Ç®‰*JºÂ¤É“DfCɲe)•]ê(SL‹5sÚ„©³§O>7 J´¨Ñ£H“*]Ê´©Ó§¦hBJÕ„ÔªX³r¸ªµ«W’;ŠK¶¬Ù³hÓª]˶­Û€%}K·®Ý£sïêE™w¯_}ÿ L¸°á¶\+fw±ãq‰÷ ,¹r4ÊÚ"[ÆŠyfã#ò:oî)Z–@Í£§–~†šÇêÔ°ÝµŽ½æ5íÛ´"!ù,Mn5þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p Ïtmp®ï|ïÿÀ pH,?·äíÈl:ŸÐ¨tJ­Z¯Ø¬vËízIÊðìK.›Ïè´š'¯ßð¸|N—¶Ãõ¼~Ïïû+wJƒ„…†‡OIˆŒŽHŠ6‘•–—˜{“”›5™ ¡¢Nž4£§¨©ª@¥ci­2«²³´>°8µ¹º»³·¼¿ÀÁq¾ÄÂÇÈÉXÄ̰ÊÏÐÑ&Í­ÆÒØÙÚÔ¥ÛßàáÝžâ¯ÎæéLä›êfì“îò#ðŠó„×÷úõû~ùþé H¤ß]ÿ$8gaƒmT˜H±¢Å‹Ô8䳑ᛎ³¶Ð쀱$FlСÌ32eµb*WÊi)óD75gÆÌ9&OŽ;"Tè!ŸFC!Mzi)Ó¦EŸ¦r*µªÕwQ¯jÝzî%ׯ`±z K¶ì²¬fÓª-B5RÛµp»ÜÄÓ mÜ»)ޮЋ·¯_~vÿ Ü/áÃq #^lV1ãÇsLJ¦¹òãÉ“-kÞ̹³çÏ C§u,º4Ò¦S›CM†µêA˜%Wuýº¶4Ú¶s'í[`!ù,8OR1þðÉI«½8ëÍ»ÿ`(Ždižhª®lë~A,Ït¼x®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~ÏïÓm€6~ƒ„…†‡ˆ‰Š‹eŽ2Œ‘’“”•–—˜™š›œžG‚Ÿ£¤¥¦§¨“¡Ž©­®¯°±²³´µ¶·¸ž«¹½¾¿ÀÁ‡ÄÅÆÇÈÂËÌÍÎÏÐÑ»€ÒÖ×ØÙ‹Ô¢ÚÞß]Ü5bâ4àç‘ÉêÉzå3èð‰ëóÅäî1÷øñü„ôôöîåÓׯ`Ÿó”è»ñ`á@#~sØ`Eˆ3j´@q£ÇT%:‚I²¤É“(Sª\‰I¤%—,3Â$1S•Ř8sÔÌÉÓÛΞ@­ý JTãPh×]z-©:¦P£JJµªÕ«X 9e—âhÖ¯`ÃVõ*oë1±Œ"!ù,P‚3þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p Ïtmp®ï|ïÿÀ pH,w·äíÈl:ŸÐ¨tJ­2•Ø™uËíz¿à°Ø›ÍŽÏè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š~eX‹‘’}J“—˜™šA•IK›¢£¤¥ 6¦ª«¬­®¯°±²†¨8³·¸¹ˆµº½¾qµ4¬¼¿ÅÆgÁZÇËÌÍUÉ2ÎÒÓÔBжÕ_×ÙÜÝÞ&ÛßâãäáåwêëìíîèñœÐòvï÷ïõuçúý.ø×ù“Ão Á|Sp¡C Jœ¸("Å‹YÌȱã‹CŠI²¤I A¤<ɲ儕`ºœI2œMz4sê‡SæÎŸ@o&J´(¡ÁŒ*UŠ”ØR >ÉE7õ©ˆªß°¾H°V«`_âdŸױaÍ¡5ò5íž¶nçÀK·æÚºxóêÝË·¯ß¿.æW0ay†ý&>Ì8ðÝ?‹KžL¹rÈ–'F!ù,T‚0þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p Ïtmp®ï|ïÿÀ pH,w·äíÈl:ŸÐ¨tJ­2•Ø™uËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†jpJ‡‹ŒŽŽ‰I‘K–—˜™n”6“œ4š¡¢£¤OŸ ¥©ª«¬M§Z­±²³´†Ÿµ¸¹º»·¼¿ÀÁ¢¾ÂÅÆx¯2ž¯ÇÍÎGÑÒÓÔÕµÉ8ÙÏÝÞßBÜàãäå®Éæcâéìíî,ëïòóôñõøù=÷}üúÿUøÛ30 Áƒ æQˆ°¡Ã‡Ù0ŒH±â£‰3j„q£Ç~ÈÐI’ HKª\™ð䉔,cÊŒs¦Í›CjâÜÉ3‡N ?{ ÔBQžG‡*]ʨ˦P'$]1uQUsWgf}ù´ÕÖq_£NöLYogÅ*MûŒ­Ú·*ÝÂõÚuî ¹vâÍpo>¿|7¼ X°a€…+Él±â!ù,Y‚,þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p Ïtmp®ï|ïÿÀ pH,w·äíÈl:ŸÐ¨tJ­2•Ø™uËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯Ûïx \™ïûÿ€‚"{Iƒ‡ˆ‰Š‹A…KŽ6Œ“”•–—‘5š4˜Ÿ ¡¢rZ¥8£ª«¬­N¨©W‘®´­°µ¸=š¹¼Ÿ·½+¿Œ»ÀÅÆÇ%‹ÄÈÍ΢ʽÌÏÔÕèÖÙÚÛÜÝÞßàáâãäåæçèéGìíîïðÇÑ€ôê÷]ñúñó؇öøRÙG°]¿Rˆ \ø¤`ÁƒúcH1ŠC‚§RXñÙÅ}žN>êëh‡#Id"ù¥H OËw'cÊ<òë¥;6 >ÈÉn¦ÏŸ>jòÄ9tgQ H“6›?j)²¤É$O2t¨²¥Ë )]Æ|IS&Ëš3kê,™s§ÏŸ@ƒþ3(aÏG‹Î"ªô_ÒO›Æ±ÇTªUM7¯ú¡ O«×¨^K±«6 Ù©YË’:«¶­[slßÊ»´+Ý»xó’«·¯_7|ÿ ¾×Ma+^ì$1ãÇ#KžL¹²å˘3k–wx³g­Ž?‹Îz´i!ù,U‚.þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯ÛïmxÏïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯vzH°´µ¶‹¹º»¼½·ÀÁ‘²Jl¾Ç¾ÂÊˈÄ4mÈѺÌÔÕÎ3ÐÒÑ*ÛÜ)ØÖâ?ÞÈã$åÇÝé½*áçð8ìíñ ó¼ë÷¹õüjúÓý:üÛ÷`ூ*\ˆ+! 2œHQ“ćú®`ÓR±£Ç:r?Šé)$É“(Sª\ɲ¥Ë—0cÊ,µ‘ãÌ›8K˜Ìɳ§ÏŸ@ƒ z¡& ¢H“î0jC©Ó§àŒBJ5ÓªX³b¸ªµë¥^ÃŽãÊä"Y±hM³6­Û·pã¢m+·.LºvóºÀK‘¯Þ¿#ýF!ù, T>0þðÉI«½8ëÍ»ÿ`(Ždižhª®¬*¼p,ÏBkßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™k4œ4šŸ ¡¢£¤“§0¥ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÅÆÇÈÉÃÌÍTÊÐÊÎÑÕÆÓØ)ÖÖÙÛÕ*ßÑÝäÃâÐáçÉåì¿êëÞïÇòóí÷ºõ×ñúôúËø¶ûP Áƒ*\x*†:<±¢Å‹3jÜȱ£Ç5 CŠélb'1&9‘\ɲ¥Ë2_Ê3EJO3sêÜɳ§ÏŸWnÎJt‘PE“Òü§TQ!ù,Pb:#þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pE+҆ȤrÉl:ŸÐ”q ‹Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßpõ¯Ûïx°`Ïïûÿy‚ƒ„…†!€‰€‡ŒQŠ|Ž“‘‘”˜™>–šœŠž¢£* ‰¤…¦‹RsF¨¯iª°‚²~´¸¹ºy¶}½’»ÂÃÄeÀ{¿ÇÅËÌÍVÇÐÉÀÎ$ÓÖÙÌØÚ?Ü݆­®àäXßåèéêëáâtìðñòîïó÷øñõ3ùýþÿ H°`‡s*d„p¡Ã‡#J¼·O†“†3jÔ£l£Ç& CŠI²¤I8Oª\ɤb –0cžI)³¦Í›8sbpYE§O!ù,8TR1þðÉI«½8ëÍ»ÿ`(Ždižhª®¬¼p,ÏAkßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïï§€‚ƒ„~‡ˆ‰ŠL……Ž‘‹”•–—’’šŽ˜Ÿ ¡vž¤¢©ª«f§¦®ƒ¬³´µV±²°¸€¶½¾¿&»“º»œÂ*¸ÀÊËu¼ÄÉбÈÓÌÖ×;4Ú4ÔÇÒ®ÆÅ)ÑØåŸÛè0*ééÝâÎ†ß§î¤æö—ìèbðáÑüãÕî Ìðo ‹Ñëd°a…‚Q@ ¦pËĈÍ*b Îè´z-°ßì²|N¯Ûïx|vó÷y‚ƒ„…†<€‰p‡Ž‘’yŒo~•j“*˜kšžŸ `œ™)£i¡%¦}¨¬­®Cªg¯¢±³¶·¸(±m¹V»½ÀÁ¿ÃQÅÆÉʨÈs£tÍËÒÓŽÑeÏεÔÛÜÝÞºÚßâã?YYä_Öèëì'æXí[êñôõïIöSóúýÂøHüáá'° €JR ¤a°Á†—,œ¡b¢ŒV#jÜÈÁ¢Ž CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêܹ-#ÏŸ@ ù új(ÑiF2Óæ†R\IŸ~*ÖÔ†ÔYQ3d½„jS®EÙ öÓ¯ª–]+hk[²/вۤ˜[ºxóN° W¯ß wGòUõ·°a +^̸±ã‰Kfy²å˘3[¨¬¹³Î!ù,VV*þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾pü tm߸ ï|ïÿÀ pH,a¹dN¢lÖŽ)§J­Z¯Øl%Àíz¿à€vLFI›å´zÍf‡ßá¶|~VÎïø¼~ïw÷€VuI…†‡y~~ˆŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈŠ}ÉÍÂËpÎÐoÒÖ¼Ôq×Ù`Ûßà´Ý_Üãáèéiæç(ì\ÛƒKêôjïb)÷ñò7UúõÈþ¹{·ß€³L(à †#¢rxP¢Å‹(ÒÀȱ£G!U ?jÔñ±¤?‚&SŠÔ¨²¥Ë6#_Ê„s¦Í›Gjâô s'Ξ>#…,24h  Féý+š” ˦—¢„JµªÕ«X³jÝÊ•ÎÓ®`“" KvæØ²hUF!ù,V‚)þðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾pütmßx ï|ïÿÀ pH,­œ2'Y:kÈèèù”Z¯Ø¬vËuQݰxL.›ÏhŸ`Ín»ß‚´|N¯Ûïø-|Ïûÿ€‚ƒx|†l„‰Š‹ŒA_KŽ’“”•–J—›œžŸ™8 ¤¥¦§¨¢£©­®¯°«7±;³µ¸¹ºM³P»I«¿ÂÃ¥½¾ÄÈÉÊËÌÍÎÏÐÑÒÓÔ‡‡Õ׆ÙÝÞDÛ|ßá{ãçè0å}éëoíñò$ïnóõmxÆ4røˆóÏù[£o_¿*\Ȱ¡Ã‡#JœXmŸŠ\Æédã§Žxµh”EÉ—N¢”22ŠÊ•0ci‰ä¥Ì›8sêÜɳ§0šÃlúº (Ñ£H“*]Ê´© ¡BŒÎDè´j1ƒQ¤‚£jµë¨A´¦ëU)ØZdÏ´L[öáÙXlÛÊë".]fv#æ³÷®ß¿úL˜‚à¸"!ù,#‚\þðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùº÷úýþªüþ ¨) ÁƒLȰaŸ…#J„q¢Å‹c*bÜÈÑŠÆŽþ C"ù(²¤IpíNª\9+%Ë—0kŒI³&;V6sê41s§O•= t¨QŒE*˜t©S„MŸJýuªU|U¯j}—u«Wt]¿Šçr¬YaÏNLËŒ­Z‡nE%‹{”.4»Ÿæ–}›oÛ½öÚùý9XYad‚ó½Ij`Ö#KžL9¢Ãj1§«Ì¹²„Π#_V¼˜†fOCƒ~uzlëL¯mÅö:[is8±ÞFQ›`o'Y» ¾[¨p&Äs×KÞØêñ%Ì9å‹>éês@Åyf'G]‘õíÁCOVù‹ëúÐ$ß—=–dª)#wA½nó×ì«Ð? þóþ8ˆ€ÚùçEw”Ö_sSX}ŒI§`{â V€àd˜Ž‡9€ˆƒˆlÈF‡ÂD¢ +Ê”¢B‰UX׋q´h£åf£7™Æ„è%£Q=âX¢‘3ꈤIEÉÛ’C É UøÆ}Sb§¤“ð츆‘^Zå1fi”>f4Mš9]™i:²æ]cúPç sº€fuMä‰ÔûŠ››bnI¨~RY衉ÀÉç|\**iK†Æ©%£“fÚÞÞõ)¨¦ Rˆi¨b%z„©¤‚õéñuÖ ª©Þ \«œ}i¬‘ÀJ„•m<@«g1èŠë Âþ߯“Ù:ê°Ì¦Rl³Ðb¸j´Ôêñlµ)D!ù,‚wþðÉI«½8ëm…ÿ`( \ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­Z¯Ø¬vËíR¤R¯xL.›Ïè´ U»ßð¸|N‡±õ¼~Ïïû•w?ƒ„…†‡…AˆŒŽTŠ"‘•–—˜™)“!šžŸ ¡†œ ¢¦§¨©d¤Sª®¯°±C¬²¶·¸¹'´$º¾¿À°¼ÁÄÅÆ˜ÃÇÊËÌ~ÉÍÐÑÒgÏÓÖרOÕÙÜÝÞ:Ûßâãä›´åèéêçëîïßáðóôËòõøùº÷úýþªüþ ¨) Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`Ê{Ä Ù³tÌ¢]ûF-Û·ÔÚu w ]«wë"ÉK•¯Þ"~¥þ+d0TÄw vº81ŽÆL!;®!YiåÉk䊽ŒÙŽfœ/†îÜò芧I«0ýfjÕ(X³ªùšYí‚­}ävy[Yod»Wgù{Kñƒ²IÑNè¸Mç°K@§9=º†äœ^V·Žû$í̹ob{?óâ¿—¾>$úôÞ7 @¿¾ýûøL“Ÿžÿ‹üæØ'A€Ö·_{ðS`.`‚žààƒVhá…f8‘¾Åa‡ †ˆÆ‡{!øÉ„öy6[[&’DbY-j‚¢/¼(ÜŠ"‚c&3Ò§¢r,âèDõ¨_;FEä_KªÔd]O¢%SŠSeIW¢•åH[’Õ¥{IæØ]˜7%ó¥˜:‰æšÆ‘Éf‚j¾™›rŠgI݉'"z2Ñ瞉РɟÍš„¡º  ¢¾ :£F@jŒ¤…¶C©^—þ‘) œvêé§k™"¨!ŠJ#©šê#ª|D!ù,9‚?þðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›ÏåqÍncÕF·|N§Âõ¼^wÇïÿ€}0‚†‡„/ˆŒmŠ.Ž’ŒW“—˜S•,™y›2ž¢£¤¥¦4 §ª«¬­¥©®±²³´s°µ¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌͼ·ÎÑÒÓ›ÔרÙZÐÚÝÞßv•àãäå*ÜæéêëìíRèîñò×ðóö÷Éõøûü¿úýÎú'° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç½ CŠI²¤É“(S¦À²¥Ë—0¨œ 1¦Í˜nêlI³'Ã;s½éÓÁ/Gg %ú`©Í¢Ý’v‘Ë)ÎIT·d]·5KW¨¾j²&Pì;²`Ób2…­Ú·hÜ>‘ ·®<ºvórE«Ñ*K½aáíæW&à‰ƒ>Œ˜/ãÇüCž,M2åËË,cÞlL3çÏ C‹m·°K[ŽI«bš§Ï«c³‚-ûíF·kƒÌˆ·îßÀƒ ïzø°!ù, 7jDþðÉI«½8ëÍ»ÿ`(Ždiž('¬lë¾B*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿àkqÌ ›Ïè´zÍ‘Éí¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²hoc³·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊË5µEÌÐÑÒÓÔÕÖרÙÚÛÜŽßàáâãÝæçQäêäèíîHëñàïôõö÷øùúû…òòübðO Áƒ*\Èð“3" #¢{hD¢Åm_\܈-£ Ž™ ©yl²ä™‘eÒ \a²¥KVבXCåÊ—%cªÃÉÓ”Nv~ŽëIL¨¸iFÃIH:¨0¦ßB]:Õ©ÕNPË]Ýʵ«×¯`e K–ÔØ²hÓÊ1ª¶­'¶nãf‚+—ÄÙºaèâ qw¯½~=ô L¸°áÈ+^üe0ãÇqCžœF2å˘3kÞ̹³g?–?‹nz´®!ù,°TÚ$àðÉI«½8ëÍ»ÿ`(ŽdižhªfAë¾p¬tmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø,TÆ•i¿à°$(›Ïè´`Ìn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•]˜.–›œžŸ™™ ¤¥¦§¨©ª:¢˜«¯°A­]³\±¸¹8¶^¼1ºÁÂ'¿0ÃÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚۦŠÅ/njãjÜSÞæéêëìíîïðñòóôõ>àšöúŠø-Jý3ö T!ù, "j^þðÉI«½8ëÍ»ÿ`(Ždiž('¬lë¾B*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨¬HeI¯Ø¬vËíz¿›jL.›Ïè´+¦®ßð¸|NW·‹õ¼~ÏïûMwDƒ„…†‡dFˆŒŽ4Š/‘•–—˜“.™žŸ v›V¡¥¦§¨I£¤©­®¯°#«+±µ¶·±³1¸¼½¾—º¿ÂÃÄÁÅÈÉÊhÇËÎÏÐPÍÑÔÕÖC³×ÚÛÜ€ÙÝàáâÓãæçèéêëìíîïðñòóôõ†øùúûüöÿõØ/ Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(Sª\©† Ë|,cÊœI³¦Í›8sêÜɳ§Ï‹/_þJ´¨Ñ£H“*] «Ó§¸œBÚôÕ«UWaÝ*˪(­‚ºäMª³÷Ä$ m"¯Ô®eëÌ-»tÙâm'·`^v{Ùõå÷0\zƒ÷^XÅáÅ4ó8²e“5d¾ÌyÍæÎ ÏV¶œXœÒ0q~ÍÚËê¨ñµ†ôzNíÙoãÞÍ»·ïßÀƒ gÛßðã6ŠKP޼¹ æÌK/=öôaºqUG}]Xö[Ñ»?ù΄|­ð⛘W²>½Æöîq£ÿ$1Öùô›Ø¿Š?ÿ’ýþ78€h&‚ 6ȃÑô'„„öDa… ^ˆá†"hÈ¡€~è_ˆ"–hâ‰Z‡¢%!ù,‚eþðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WÙð¸|N¯Û1nã}Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôñ÷øùúûõþÿø ä° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠü7°$¾‘(q™4™²¥Ë—0cÊœI³¦MfyЍXYò¦O49¤à9ð§Ñ0Aaì$JðhĤ/œJ¥ÕÅÔ«ª^ÁÊu‘V]ÊK¶¬Ù³hÓ*bÚT­[6l÷½ÝöU†®¸úæj«» o>½€‡ø=¸°—Á÷ +Þ‚¸ßâÇRCžüD2åËJ,ÏÒ¬†3æÏ 5zMÇèÒ¨gœNÍÚÄêÖ°cËžM»öD¾CÛ6‹{·ÃÞ¾ƒSÞõµðÚÆ¶œ\ù\æº o.5õꨯÛÐN‰ûïØ?ƒy<ùóèÓ«ï€7¥ùõ%Ú£|ß}÷ëÏ˯¿¿ÿòÑý `kD!ù,niþðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëAîïðñòìõÇóøóöûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹òi|‡±ã¡Í=ŠI²¤É“(Sª\ɲ%1]ÊL3ßÌ›ejâÃÉ3ŒN}=ƒ J´¨Ñ£H“*]Ê´©Ó§P£úù)OªÕTã]ÝZ#+<®`Sxå¶,‰±î̪ –ÞÚ¨m!Åõ‰ö­Ý»xóêÝË·/Ϲ~í¼v0áI1Ç8̸±ãÇ#KžL¹²e:Š3·¸Ì¹³çÏ C_4<‚4#Ӣ͠NÍšäêÖ8_ÞM»¶íÛ¸ ÉÎr7o“¾»®+œ]ðâçGP9qæ …$!ù,‚iþðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷ø=Fû-ùþÍüøý˜,à>‚‹4’°¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠÉfa’(#™<’’ÇJ-¥¼|sÇL5sêÜIêf?ž@ƒ J´¨Ñ£H‘ød‘´éš¥2œJ5uªÕ1U¯jõ’ukÇ®^ÊK¶¬Ù³hÓª]˶­ pãÊKW€[¯uóÖ• ·o\¾~ûÞÝXpŠÂz§«q^ÀŽç‚a†²b—KD¦ y3ÜÉ™ËX¾¬c´Ïr;{&Mõß®?ÞÌ:el»°c«X]›ämÕ´gGîí[wn×»ƒ/…é:¿£–•÷rÑ£WW~ÝcvãÛ‡wÿøùƒðŽÇ“7®=´uõËOž¾Ñè(ÞÛŠÿ„þý@õX÷wh\~¸“€%ü§`N ’àÙsŒPø`(^H\†ÖÆa‡­%âˆ$–˜Q„&Þc¡(¦XÏŠ=´è"ì8ãQ2ÞÈ“|ê¸`æùX" F!ù, Ej<þðÉI«!ëÍ{¸`(Ždižhª®lë¾p,Ïtmßx®»^ïíÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ'>“‘–S””—›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅ0™“fËÌÍÎÏÆÒÓ È>ÊÐÙÏÔÜÜÖ=ØÚâÑÝåætããéâçîï8ìÚëòÐôõÎðúû/øÛþò ÈŒŸÁƒ&Œ¡p‡£4$±¢E#/jÜø& Çz mx I²$‹€ß~”IÙÁ¤,–\ÊœI³¦Í›8sêÜ 2#ÏŸ§`nJ´¨Ñ£H‰ùLÊÔØÒ¦P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãJl(Ah%¹xUyóØw¥~y ÓéëGa?;þõûŸDñ=Ÿ€^@ sÿq—àƒL,¨Bh¡2× pvXD†Ëm8Ÿ‡ô¢rœ˜\DÆÐbW†©xÞC/¾PãV1ª¸L…6ÜØ‚)ɸ‡/5¹‚’'醓ß9È’Z0™•Y@—•(p9ˆ—$†)æ˜d–iæ™h¦©æšl¶é&Z¾)§ qÎI˜]´hdvÊçeXâ°§ŽðÙ§n‘¨†ê(>ÊW¤'P*éU& ƒ¥—Ž!ù,0‚OþðÉI«½8ëmƒÿ`(\ižhª®lë¾p,Ïtmßx®ï<;þ£žpH,ȤrÉl:7ÀèçI­ZqRéuËíz¿Ð,L.oÅc³zÍnÇÐ?·|Ž…‹èø¼žl¿ïÿ€}!…†‡:ƒ ˆŒzŠS‘’“”˜e–$™ž›Ÿ¢U¡£¦§f¥¨«¬­®¯•–°³´µ¶ª·º»¼½\¹¾ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Çþ CŠI²¤É“(S榲e>–.cÊœIÌš8ÓÝd´3焞ÕJ´¨Q úT:í¨Ó£Ieù$µÛÓ«C£>šJu+×cL¿Š½vlDzfÓ>Cû²ªZ¶±¼Ž‚{¦Ï\·ié^лoÐ]¹oñ¶à[+Vµƒ#FB˜‚á«‹W4ŽüàñS “%XvJ¹3˜ÍPd® º¨çÓ\J›­x…j¢¨cWyÕÔhÙ2i =u·KÝHm·öMÜVïâÈKO 8¹ó•Ë,gý¹Áé¾°sÐ.½:5îÖSyç3^øðä›»9¾½û÷ðãËŸO¿¾ýûd€Ëпþþ( >hàF¥xà‚Ðy¥ ƒRñ`„ðD!ù,9‚FþðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›ÏèÒ¸šn»ßð¸|Ž[éø¼~ÏïGíE~‚ƒ„…†‡€GˆŒŽPŠ0‘•–—˜™!“/šžŸ ¡†œ.¢¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ~#uE Áƒ²@Ȱ¡Ã‡ƒ(”±"¿‰3jÜȱ£G\—?ŠTr$¯’&SŠC©²e7–.¥ ˜I³¦Í›œÀŒÉ³ÚN3œzê ‰³(N¡H{ýLºj)Ó§ÆœBL*U‰ ¯j-fu«×Z]¿Š…v¬Ù³hÓª]«¶,Û·4Üê›….\vvoå½›c/_<~%eýKXSàˆ+^̸±ãÇ#3J™¦ä˘3kNsx³çÏ CuM.!ù, =jCþðÉI«½8ëÍ»ÿ`(Ždiž(¬lë¾A*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨¬HeI¯Ø¬vËíz¿›jL.›Ïè´+¦®ßð¸|NW·‹õ¼~ÏïûMwDƒ„v/…‰_‡ˆŠŽWŒ.”Q’-•™šA—V›ŸB+ ¤¥S¢¦©ª«¬e¢1­±²³´@¯µ¸¹º» ·¼¿ÀÁ´¾ÂÅÆÇ•ÄÈËÌÍuÊÎÑÒÓ^ÐÔרÙIÖÚÝÞß4Üàãäåa¨æéêëâìïðÑîñôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#Æ›'±¢Åpè.jÜ8ƒ"ÇÌ 3øò²dI’&SnD©²¥D–.uÁŒI³¦Í›8s›©³ç>ž>ƒŽ‰ ¢B“v@jÉè ¦J¥@6Õ‰¤££®© Œ+“«O³jMã•WYB\Ï&U;¶GZ±mãN„+·®:¶vÝÒÍ+u/_-xÿvô+¸h§Âˆ½NÌØÔb[„K|¸]ä1_ž¬¹r2t™=„Öë9ÄhΉFn–vzNkÁ¯™Å†3Ûð%Ô¸+ÔÎÍÛõêÞÀƒ N¼¸ñãÈ›¨.¼¹óçùvC_!ù, Gj<þðÉI«½8ëÍ»ÿ`(Ždiž(¬lë¾A*Ïtmßx®ï|ïÿÀàF„ ȤrÉl:ŸÐ¨¬HeI¯Ø¬vËíz¿›jL.›Ïè´+¦®ßð¸|NW·‹õ¼~ÏïûMwDƒ„…†‡dFˆŒŽ4Š/‘•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬R“.­±²³‘¯-´¸¹º{¶V»¿ÀÁ‰½1ÂÆÇÈMÄÅÉÍÎÏ8ËÐÓÔÕ"ÒÖÙÚÛØÜßàÈÞáäpãå’Äèëì¬çíðñžïòõ5øùúûüæê¥èÙˆ¢ŸÁ~ÿz™H°áˆƒó%´µ Ã‹%"FœøJC>ä1ŠÌ b-‹#Sª´ƒr¥Ë—]Bœ©C&Í›8}ØÌɳ§ÏŸ@ƒ J”NɃÛ]ÊôCǦâZBýñÔ©~vbM§…Ö­I»‚¥:ÉëÕ±y¾¢£ví™¶8Žt"¡O¸n ÕåGw¯>8~ÿ›wP`‰Mã¬áÂ~ûKÜødÇg!CºLù0cσ3kvÄyZé¹RÍZËi©gÄne6m{Ør‹eû¶¼ÞЀûf»{¸ñmÂ+Ç•|¹óVÍŸKGe[·Â騳kßn#:÷ƒò:ùó"!ù,E‚>þðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WÙð¸|N¯Û1nã}Ïïûÿ€8yE…†‡ˆ‰sƒGŠŽ‘’@Œ0“—˜™š›•/œ ¡¢£vž.‘¦W¤«¬­®R©,¯³´µ¶6±2·»¼½¾¹¿ÂÃÄ£ÁÅÈÉʉÇËÎÏÐrÍÑÔÕÖ[Ó×ÚÛÜD±Ýàáâ¸ßãæçèÙéìíãëîñòÕðóö÷Åõøûü¶Ç H0@¿ƒý+È`‡#JœH±¢Å‹3jÜȱ£Ç þ CüˆC¤Èj&C’¼‘²áJ-¢Œéð¥M:4kFË9ð¦Ï' y” t¤«¢C*UT(Q¤¯\ªHꮦ<Ÿ •j"«·ô…ÛŠ¬×³Ä1»Š-Z/jÄ¥R®M9Okܾå2·G_±Ý­”·ëÞ/u$αË1¼jôÎÒøFer©à<&Ùðd¾u—\®1Ji4’?à ­:Ãi$`S·ž=1¶gÚ¸)ÚÞš»wí®²ç½†4Ü·‰ÝNbÍ‰ŠµñçHŠ+t½º\ꮤÓþƒû2ḭ́[y;‰wQç“ߘ~Kû=È³ŽŸïãýøÌéë×a_ø±åí)'`ýYö߀R f¦$è`- >(á5Nh!4`­wᆓdx ‡F!ù,A‚BþðÉI«½8ëÍ»ÿ`(Ždižhº lë¾° Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–cU—›œž6™FŸ£¤¥¦¡E§«¬­‘©G®²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòíõö÷øùóüý5úõùHDÀƒö *\¸!B†#Jœ¸ Š3*´øB£ÇÀ CŠIrG%S2:y¥ K*TÉð¥Œ2ª°Y('À/1Y¤ù̧@`FóIHЍB¦÷‚AMˆsê>§­^ý¥u©U¬Y¿"Û¬ÙheϪe–v­Û·p;ðŒK7Ø\OwëêÝË·¯ßždÅþ̨l[ˆ ¬&oâÄ‹§¶qü8ed¨^%³¡\yÞe¦™1WÕ¼†sçÓóRkK¯[˾az¶m7skßÞ&wPÞÀ'ÿNîâN#!ù, J>5þðÉI«½8ëÍ»ÿ`(Ždižhª®¬*¼p,ÏBkßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃLÆÇÈÉÊÄÍÎ9ËÑËÏÔÕÖרÙÚÛ‰4Þ4ÜáâãäåæçèéêëìíîïðñòóôõÃ񿂻ùùöÖüøöŒæ¯`¨ œf°!§…ÊJÌ1ÙÄ‹•*"Ãȱ£Ç1 CŠI²¤É“(Sª\yR£>….™=øFË›?bÊÔ)¡fM%>iâÉ3IÐoCCF!ù,A‚?þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéê¨íîïðñëôÝò÷òøûîõþ©1ÆÐÇoß¿ƒ½*lA°à=„s-\(É!¼ˆƒLT(ÆâÃÏûeÉc£ÀŽ!/‚LI²e ”*a¾sI3•L‘7Û1Ê9¯¦Ï†2ÂÜ™óçOžBY.Bj´&S¦Š 6mù´èR«S©Z•ŠˆkV&&ªªz“hÙ`aæI C˜WCo¿&aûB]c±&Š+÷È]†ÁøÜ—È_…¿N¬ñ0ã.‹K¾¹PåÉÜÈMryGgÌÙ4å¬×ÈgÐ×D+E¡:¤’Ó¨K–±ò,ë­¸mií1¶§Ù*`_àmñuî;— ÜBó&Ï“;[.½ú!ù,B‚>þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Ît(Üx®ïBíÿÀ pH,ȤrkÆ–Ð oÊ‹Z¯Ø¬vËíz+Îp뻤šqä´zÍn»ßðøç|–Ûïø¼~χÓÍ}‚ƒ„…†‡T‡‹ŒŽ@‰S‘•–—˜™ƒ“UšžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíÜœ;îòó˜ð:ôøùŒö9úþÿ}ø¡H° 7$ ì!k¡Á‡û*”Ø"Ä‹›(:¬(£ÇöQl ‹äÇ“#Fj\Ù‘#?”0˰|ùÀd {{lÆü FL(—T¶ /§Å!z†ùyÔP%Biådt(ÒcOm4g ¯y²^ý%vÎV(]‹º;¶XYo‹Äí5·-ººBðêÒk7ŠR'}=ümRïlàÑ?A̸±ãÇ#KžL¹²å˘3kÌw³çl?›µzQ1 ¦-C‹î z騥®öÒzBíÙp ã¾r»¦np¯]ü½-ñѲ‹+GÕ»ùq7½—WŽî‰ºtÉi©‚²~}w߃>ï®-|,óäý¡OÏÞQð1¾I·Ÿïv<ýû "!ù,@‚?þðÉI«½8ëÍ»ÿ`(Ždižhª®l[ p,Ï´àÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»­¸|N¯Þø¼~Ïï‹ì€v~ƒ„…†‡]ŠrˆŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑcIÔ1Òר£ÕÕÙÝÞšÛÔßãä‘áIåéê„çH íJëòónð4ôø‡ö3¸û2ùù³vk Œ€÷´QÐ`‡#JœH±b·…3j¤‚±Ì¾® C®ø(²$‹Ž&Sª”‚r¥Ë—0c>Y´H¦M4ÝÜɳ§ÏŸ@ƒ J4cÎ@E“z; è'SAJE¶”ö´NT©³U¥s5äÔ®`‘} {bì³1Ñ’¢DÛoWÆ]«§£Ý¬tóšËzw Þ¿§úús´u`]s±&‰¨0£ÃýðNãKÙo#Çq ¿“,&±æÏ*<[ ºôΦS«^­š4ëד\ÞíH6íÛ…"!ù,H‚4þðÉI«½8ëÍ»ÿ`(Ždižhºlë¾p Îtmßx®ï|ïÿÀ P+ƆȤrÉl:ŸÐ¨Ôg¬¶¦Ø¬vËíz¿à”Õ.›Ïè´z½WÙð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·º»¼½¾¸ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝnFÞâãßàGæçmé2äîïðñòóôõö÷øùúûüýþÿòc÷B Áƒ!º@È0ɯ‡¿Jœ(¢Å]3"¼xQ£Ç€`-TÈ⣾G’4YåC8.#²œIdI31}9ÉÙ«"OŒ4ƒÚl‡é'P£º‚*=1TR`K£JJµªÕ«3žbÝÊÕŽÖ®`Úh*¶¬#²fÓª]˶­[_ßÊ]!ù,@‚>þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžnI¡1Ÿ¤¥¦v¢¢§«¬­f©¡®²³´V°Iµ¹º»B·H¼ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛܾJÝáâãäåæçèŒß4éíîïðñòóôõö÷øùúûüýþÿZ7CA¯Ö \øáà¨&a0œ¸-¢ ŠéYÌÈ1ÞÆŽl CŠI²¤É“(±}LÉ2ÚÊ–0cÊœùï%ÍrêÜɳ§€›@ƒ²´)´¨¬>“ú4š‡(Ó§P£s*µªÕ«X³jݺ‰*ׯ`Ê¥â5DÙ±hO|<›V‘Ò·:5FlK·®]ylïê]“wo°!ù,B‚<þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µApI¶º»¼>¸H½ÁÂÃ&¿JÄÈÉÊÆ4ËdÍ2ÏÓaÑÒÔVÖZØÜÙÚ6ÝSßàáåOãæQèéìFëíð!ïñhóô÷öø`úûþýþ DPUÁDµ0¡C> JœH±¢ÅN2jÜȱ£€6÷Cj¼Hr˜È“#Ù ôX²%¯•'AÂÜÈdfH6Yºü”³£“žË¥™bhÊH%͈siÒ§—~,êªÕR›½.¢¿¬T·råæuXgÇN+‹/­ ·/¾©µÄö\wçê=“—Kß'ÖÍXiU1…=€Mül0Æ !/Z|˜ã`/ “¬ˆ²Øvš[d– s"ÓÿBCQý²²%Ôu`3bTö^ ¶ÑÞ™ûö…ÞIû¾ø¡ÝÄ“cv­¼¹-ãÆKg}ºõnž‡^~½;«ì@·koÍû%äÔ™án¾}£êîã·þ,¿~;øöñE!ù,G‚4þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,’jÈšqÉl:ŸÐ¨tJ­J’ؘuËíz¿à°Ø›ÍŽÏè´zÍnSËX·|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿vpIÀÄÅÄÂHÆÊ˸ÈJÌÐÑÒÓÔÕÖcÙÚÛÜÝ×àá—ÞäÞWÎ3åëÚâîØìëçèZMñÝL÷åóô6úäÞ ìÓ¯&€æ„¡!·±><´ÐßA‰í.lˆñÄW•³9 éEÅ(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒâ 9í¤ÐIFF!ª± RIÕD}Êf*ÕEV¯¢Éªµ«×¯`ÃR`Š‚¬Ø³®Ì¢]»Cí&·lã¶€›‰)]¹rïŽ É#Þ¿»ìòLøšÞˆ‰N,s±2ÇŒBfli²âÁù0SeXçŸ7CŠ!ù,Ln.þðÉI«½8ëÍ»ÿ`(Ždižhª®l[p,ÏtàÞx®ï|ïÿÀ pH,ÖŽµ¢rÉl:ŸÐ¨têDZcÔ¬vËíz¿`îõ.›Ïè´z [Ùð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰(ŒŽŠ“”•–€‘™‘—œžŸa𢠥¦§¨@££©­®¯°«¢±µ¶·¨³š¸¼½¾ˆº™¿ÃÄÅxÁ›ÆÊJÈËÏГnHkÍÑØÙ‚ÓGÚÞßà:ÜIáåæ­ã4*é3çîïðì2ñõö÷øùúkóXûý`ü˜-  X *|–a@[Ö-Œ×ðUEXIM|wÝÃZŸmÉ«£«’HJ@©ÒÉV,[ÆlIÓÌL’7™…Dô²¦œê³KOD‘”IÒ¢œž‚ú…ª†V{d…ªhë¯ZÀfËÖ¦'ÈNQ+…mÙ‚ù…2÷íT´„ކ¨ ¯Ý¿&ôÞÍhŽ/à¿‚¯ô«¸±>Ë;ž\2å˘9XÎ\h3ç´K=}Y4éÓŠM£Þ!ù,PB:7þðÉI«½8ëÍ»ÿ`(ŽdinBª®l+œp,Ïtmßx®ï|ïÿ%—Ð,ȤrÉl:Ÿ’¡T­Z¯Ø¬vËEN§Ý°xL.›Ï¸¯Ín»ßð¸W-”Ûïø¼ÞN¯ïÿ€‚ƒ@}D„ˆ‰Š‹Œ†-‘’“”g,•™š›œG—+¡¢£¤"ŸT¥©ª«¡§)¬°±²‰®/³·¸¹oµº½¾¿Z¼“ÄÅÆÇÈÀËÌNÂ’ÉÑÉÍÔÕEÏ‘ÒÚÅÖÝÞß"ÛÛàäåæâÚçëìÍéÒíñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱa•wÑJ‘Û‰ŠÈ&jì‚ñœŽÎC^èhì#Ib2N¢ÉR‰Jeº^¶Ä€m¦™MpÚtä NM4?×éÜI)裦zÎJTÒOADmJnª «°rÐ:ŠéN®{Àf«Ï«M²xÐZP{Ï,G•>•²•3wB]zn¹ä%#ìî.¥0üÊÛ ‚pÃWGò+˜êÄ óh|‹²c$’7dÖaY–°Í—o€Æ0úFçXŸá†v©Ú©âv©O®žM»¶íÛ¸sÏ9¥»÷ÈÖ¾ƒÞè´pÛ¥ï?N;y•åÌ£·z-}a;cava-0.7.4/example_files/config000066400000000000000000000130031405100172200164260ustar00rootroot00000000000000## Configuration file for CAVA. Default values are commented out. Use either ';' or '#' for commenting. [general] # Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0 ; mode = normal # Accepts only non-negative values. ; framerate = 60 # 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off # new as of 0.6.0 autosens of low values (dynamic range) # 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0 ; autosens = 1 ; overshoot = 20 # Manual sensitivity in %. If autosens is enabled, this will only be the initial value. # 200 means double height. Accepts only non-negative values. ; sensitivity = 100 # The number of bars (0-200). 0 sets it to auto (fill up console). # Bars' width and space between bars in number of characters. ; bars = 0 ; bar_width = 2 ; bar_spacing = 1 # Lower and higher cutoff frequencies for lowest and highest bars # the bandwidth of the visualizer. # Note: there is a minimum total bandwidth of 43Mhz x number of bars. # Cava will automatically increase the higher cutoff if a too low band is specified. ; lower_cutoff_freq = 50 ; higher_cutoff_freq = 10000 # Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and # only check for input once per second. Cava will wake up once input is detected. 0 = disable. ; sleep_timer = 0 [input] # Audio capturing method. Possible methods are: 'pulse', 'alsa', 'fifo', 'sndio' or 'shmem' # Defaults to 'pulse', 'alsa' or 'fifo', in that order, dependent on what support cava was built with. # # All input methods uses the same config variable 'source' # to define where it should get the audio. # # For pulseaudio 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink # (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them). # # For alsa 'source' will be the capture device. # For fifo 'source' will be the path to fifo-file. # For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address ; method = pulse ; source = auto ; method = alsa ; source = hw:Loopback,1 ; method = fifo ; source = /tmp/mpd.fifo ; sample_rate = 44100 ; sample_bits = 16 ; method = shmem ; source = /squeezelite-AA:BB:CC:DD:EE:FF ; method = portaudio ; source = auto [output] # Output method. Can be 'ncurses', 'noncurses' or 'raw'. # 'noncurses' uses a custom framebuffer technique and draws only changes # from frame to frame. 'ncurses' is default if supported # # 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data # stream of the bar heights that can be used to send to other applications. # 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above. ; method = ncurses # Visual channels. Can be 'stereo' or 'mono'. # 'stereo' mirrors both channels with low frequencies in center. # 'mono' outputs left to right lowest to highest frequencies. # 'mono_option' set mono to either take input from 'left', 'right' or 'average'. ; channels = stereo ; mono_option = average # Raw output target. A fifo will be created if target does not exist. ; raw_target = /dev/stdout # Raw data format. Can be 'binary' or 'ascii'. ; data_format = binary # Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530). ; bit_format = 16bit # Ascii max value. In 'ascii' mode range will run from 0 to value specified here ; ascii_max_range = 1000 # Ascii delimiters. In ascii format each bar and frame is separated by a delimiters. # Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)). ; bar_delimiter = 59 ; frame_delimiter = 10 [color] # Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow. # Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires # ncurses output method and a terminal that can change color definitions such as Gnome-terminal or rxvt. # if supported, ncurses mode will be forced on if user defined colors are used. # default is to keep current terminal color ; background = default ; foreground = default # Gradient mode, only hex defined colors (and thereby ncurses mode) are supported, # background must also be defined in hex or remain commented out. 1 = on, 0 = off. # You can define as many as 8 different colors. They range from bottom to top of screen ; gradient = 1 ; gradient_count = 8 ; gradient_color_1 = '#59cc33' ; gradient_color_2 = '#80cc33' ; gradient_color_3 = '#a6cc33' ; gradient_color_4 = '#cccc33' ; gradient_color_5 = '#cca633' ; gradient_color_6 = '#cc8033' ; gradient_color_7 = '#cc5933' ; gradient_color_8 = '#cc3333' [smoothing] # Percentage value for integral smoothing. Takes values from 0 - 100. # Higher values means smoother, but less precise. 0 to disable. ; integral = 77 # Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable. ; monstercat = 0 ; waves = 0 # Set gravity percentage for "drop off". Higher values means bars will drop faster. # Accepts only non-negative values. 50 means half gravity, 200 means double. Set to 0 to disable "drop off". ; gravity = 100 # In bar height, bars that would have been lower that this will not be drawn. ; ignore = 0 [eq] # This one is tricky. You can have as much keys as you want. # Remember to uncomment more then one key! More keys = more precision. # Look at readme.md on github for further explanations and examples. ; 1 = 1 # bass ; 2 = 1 ; 3 = 1 # midtone ; 4 = 1 ; 5 = 1 # treble cava-0.7.4/example_files/etc/000077500000000000000000000000001405100172200160145ustar00rootroot00000000000000cava-0.7.4/example_files/etc/asound.conf000066400000000000000000000010411405100172200201500ustar00rootroot00000000000000pcm.!default { type plug # <-- no { here slave.pcm { type multi slaves { a { channels 2 pcm "hw:0,0" } # the real device b { channels 2 pcm "hw:Loopback,0" } # the loopback driver } bindings { 0 { slave a channel 0 } 1 { slave a channel 1 } 2 { slave b channel 0 } 3 { slave b channel 1 } } } ttable [ [ 1 0 1 0 ] # left -> a.left, b.left [ 0 1 0 1 ] # right -> a.right, b.right ] } cava-0.7.4/example_files/etc/modprobe.d/000077500000000000000000000000001405100172200200455ustar00rootroot00000000000000cava-0.7.4/example_files/etc/modprobe.d/alsa-aloop.conf000066400000000000000000000001001405100172200227330ustar00rootroot00000000000000options snd-aloop index=1 enable=1 pcm_substreams=4 id=Loopback cava-0.7.4/iniparser/000077500000000000000000000000001405100172200144205ustar00rootroot00000000000000cava-0.7.4/iniparser/AUTHORS000066400000000000000000000003661405100172200154750ustar00rootroot00000000000000Author: Nicolas Devillard This tiny library has received countless contributions and I have not kept track of all the people who contributed. Let them be thanked for their ideas, code, suggestions, corrections, enhancements! cava-0.7.4/iniparser/LICENSE000066400000000000000000000020731405100172200154270ustar00rootroot00000000000000Copyright (c) 2000-2011 by Nicolas Devillard. MIT License 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. cava-0.7.4/iniparser/Makefile.am000066400000000000000000000002131405100172200164500ustar00rootroot00000000000000noinst_LTLIBRARIES = libiniparser.la libiniparser_la_SOURCES = src/iniparser.c src/dictionary.c #libiniparser_la_LDFLAGS = -version-info 4 cava-0.7.4/iniparser/README.md000066400000000000000000000055431405100172200157060ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Iniparser 4](#iniparser-4) - [I - Overview](#i---overview) - [II - Building project](#ii---building-project) - [III - License](#iii---license) - [IV - Versions](#iv---versions) - [V - FAQ](#v---faq) - [Is Iniparser thread safe ?](#is-iniparser-thread-safe-) - [Your build system isn't portable, let me help you...](#your-build-system-isnt-portable-let-me-help-you) [![Build Status](https://travis-ci.org/ndevilla/iniparser.svg?branch=master)](https://travis-ci.org/ndevilla/iniparser) # Iniparser 4 # ## I - Overview This modules offers parsing of ini files from the C level. See a complete documentation in HTML format, from this directory open the file html/index.html with any HTML-capable browser. Key features : - Small : around 1500 sloc inside 4 files (2 .c and 2 .h) - Portable : no dependancies, written in `-ansi -pedantic` C89 - Fully reintrant : easy to make it thread-safe (just surround library calls by mutex) ## II - Building project A simple `make` at the root of the project should be enough to get the static (i.e. `libiniparser.a`) and shared (i.e. `libiniparser.so.0`) libraries compiled. You should consider trying the following rules too : - `make check` : run the unitary tests - `make example` : compile the example, run it with `./example/iniexample` ## III - License This software is released under MIT License. See LICENSE for full informations ## IV - Versions Current version is 4.0 which introduces breaking changes in the api. Older versions 3.1 and 3.2 with the legacy api are available as tags. ## V - FAQ ### Is Iniparser thread safe ? Starting from version 4, iniparser is designed to be thread-safe, provided you surround it with your own mutex logic. The choice not to add thread safety inside the library has been done to provide more freedom for the developer, especially when dealing with it own custom reading logic (i.g. acquiring the mutex, reading plenty of entries in iniparser, then releasing the mutex). ### Your build system isn't portable, let me help you... I have received countless contributions from distrib people to modify the Makefile into what they think is the "standard", which I had to reject. The default, standard Makefile for Debian bears absolutely no relationship with the one from SuSE or RedHat and there is no possible way to merge them all. A build system is something so specific to each environment that it is completely pointless to try and push anything that claims to be standard. The provided Makefile in this project is purely here to have something to play with quickly. cava-0.7.4/iniparser/src/000077500000000000000000000000001405100172200152075ustar00rootroot00000000000000cava-0.7.4/iniparser/src/dictionary.c000066400000000000000000000270741405100172200175320ustar00rootroot00000000000000/*-------------------------------------------------------------------------*/ /** @file dictionary.c @author N. Devillard @brief Implements a dictionary for string variables. This module implements a simple dictionary object, i.e. a list of string/string associations. This object is useful to store e.g. informations retrieved from a configuration file (ini files). */ /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- Includes ---------------------------------------------------------------------------*/ #include "dictionary.h" #include #include #include #include /** Maximum value size for integers and doubles. */ #define MAXVALSZ 1024 /** Minimal allocated number of entries in a dictionary */ #define DICTMINSZ 128 /** Invalid key token */ #define DICT_INVALID_KEY ((char *)-1) /*--------------------------------------------------------------------------- Private functions ---------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /** @brief Duplicate a string @param s String to duplicate @return Pointer to a newly allocated string, to be freed with free() This is a replacement for strdup(). This implementation is provided for systems that do not have it. */ /*--------------------------------------------------------------------------*/ static char *xstrdup(const char *s) { char *t; size_t len; if (!s) return NULL; len = strlen(s) + 1; t = (char *)malloc(len); if (t) { memcpy(t, s, len); } return t; } /*-------------------------------------------------------------------------*/ /** @brief Double the size of the dictionary @param d Dictionary to grow @return This function returns non-zero in case of failure */ /*--------------------------------------------------------------------------*/ static int dictionary_grow(dictionary *d) { char **new_val; char **new_key; unsigned *new_hash; new_val = (char **)calloc(d->size * 2, sizeof *d->val); new_key = (char **)calloc(d->size * 2, sizeof *d->key); new_hash = (unsigned *)calloc(d->size * 2, sizeof *d->hash); if (!new_val || !new_key || !new_hash) { /* An allocation failed, leave the dictionary unchanged */ if (new_val) free(new_val); if (new_key) free(new_key); if (new_hash) free(new_hash); return -1; } /* Initialize the newly allocated space */ memcpy(new_val, d->val, d->size * sizeof(char *)); memcpy(new_key, d->key, d->size * sizeof(char *)); memcpy(new_hash, d->hash, d->size * sizeof(unsigned)); /* Delete previous data */ free(d->val); free(d->key); free(d->hash); /* Actually update the dictionary */ d->size *= 2; d->val = new_val; d->key = new_key; d->hash = new_hash; return 0; } /*--------------------------------------------------------------------------- Function codes ---------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /** @brief Compute the hash key for a string. @param key Character string to use for key. @return 1 unsigned int on at least 32 bits. This hash function has been taken from an Article in Dr Dobbs Journal. This is normally a collision-free function, distributing keys evenly. The key is stored anyway in the struct so that collision can be avoided by comparing the key itself in last resort. */ /*--------------------------------------------------------------------------*/ unsigned dictionary_hash(const char *key) { size_t len; unsigned hash; size_t i; if (!key) return 0; len = strlen(key); for (hash = 0, i = 0; i < len; i++) { hash += (unsigned)key[i]; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } /*-------------------------------------------------------------------------*/ /** @brief Create a new dictionary object. @param size Optional initial size of the dictionary. @return 1 newly allocated dictionary objet. This function allocates a new dictionary object of given size and returns it. If you do not know in advance (roughly) the number of entries in the dictionary, give size=0. */ /*-------------------------------------------------------------------------*/ dictionary *dictionary_new(size_t size) { dictionary *d; /* If no size was specified, allocate space for DICTMINSZ */ if (size < DICTMINSZ) size = DICTMINSZ; d = (dictionary *)calloc(1, sizeof *d); if (d) { d->size = size; d->val = (char **)calloc(size, sizeof *d->val); d->key = (char **)calloc(size, sizeof *d->key); d->hash = (unsigned *)calloc(size, sizeof *d->hash); } return d; } /*-------------------------------------------------------------------------*/ /** @brief Delete a dictionary object @param d dictionary object to deallocate. @return void Deallocate a dictionary object and all memory associated to it. */ /*--------------------------------------------------------------------------*/ void dictionary_del(dictionary *d) { ssize_t i; if (d == NULL) return; for (i = 0; i < d->size; i++) { if (d->key[i] != NULL) free(d->key[i]); if (d->val[i] != NULL) free(d->val[i]); } free(d->val); free(d->key); free(d->hash); free(d); return; } /*-------------------------------------------------------------------------*/ /** @brief Get a value from a dictionary. @param d dictionary object to search. @param key Key to look for in the dictionary. @param def Default value to return if key not found. @return 1 pointer to internally allocated character string. This function locates a key in a dictionary and returns a pointer to its value, or the passed 'def' pointer if no such key can be found in dictionary. The returned character pointer points to data internal to the dictionary object, you should not try to free it or modify it. */ /*--------------------------------------------------------------------------*/ const char *dictionary_get(const dictionary *d, const char *key, const char *def) { unsigned hash; ssize_t i; hash = dictionary_hash(key); for (i = 0; i < d->size; i++) { if (d->key[i] == NULL) continue; /* Compare hash */ if (hash == d->hash[i]) { /* Compare string, to avoid hash collisions */ if (!strcmp(key, d->key[i])) { return d->val[i]; } } } return def; } /*-------------------------------------------------------------------------*/ /** @brief Set a value in a dictionary. @param d dictionary object to modify. @param key Key to modify or add. @param val Value to add. @return int 0 if Ok, anything else otherwise If the given key is found in the dictionary, the associated value is replaced by the provided one. If the key cannot be found in the dictionary, it is added to it. It is Ok to provide a NULL value for val, but NULL values for the dictionary or the key are considered as errors: the function will return immediately in such a case. Notice that if you dictionary_set a variable to NULL, a call to dictionary_get will return a NULL value: the variable will be found, and its value (NULL) is returned. In other words, setting the variable content to NULL is equivalent to deleting the variable from the dictionary. It is not possible (in this implementation) to have a key in the dictionary without value. This function returns non-zero in case of failure. */ /*--------------------------------------------------------------------------*/ int dictionary_set(dictionary *d, const char *key, const char *val) { ssize_t i; unsigned hash; if (d == NULL || key == NULL) return -1; /* Compute hash for this key */ hash = dictionary_hash(key); /* Find if value is already in dictionary */ if (d->n > 0) { for (i = 0; i < d->size; i++) { if (d->key[i] == NULL) continue; if (hash == d->hash[i]) { /* Same hash value */ if (!strcmp(key, d->key[i])) { /* Same key */ /* Found a value: modify and return */ if (d->val[i] != NULL) free(d->val[i]); d->val[i] = (val ? xstrdup(val) : NULL); /* Value has been modified: return */ return 0; } } } } /* Add a new value */ /* See if dictionary needs to grow */ if (d->n == d->size) { /* Reached maximum size: reallocate dictionary */ if (dictionary_grow(d) != 0) return -1; } /* Insert key in the first empty slot. Start at d->n and wrap at d->size. Because d->n < d->size this will necessarily terminate. */ for (i = d->n; d->key[i];) { if (++i == d->size) i = 0; } /* Copy key */ d->key[i] = xstrdup(key); d->val[i] = (val ? xstrdup(val) : NULL); d->hash[i] = hash; d->n++; return 0; } /*-------------------------------------------------------------------------*/ /** @brief Delete a key in a dictionary @param d dictionary object to modify. @param key Key to remove. @return void This function deletes a key in a dictionary. Nothing is done if the key cannot be found. */ /*--------------------------------------------------------------------------*/ void dictionary_unset(dictionary *d, const char *key) { unsigned hash; ssize_t i; if (key == NULL || d == NULL) { return; } hash = dictionary_hash(key); for (i = 0; i < d->size; i++) { if (d->key[i] == NULL) continue; /* Compare hash */ if (hash == d->hash[i]) { /* Compare string, to avoid hash collisions */ if (!strcmp(key, d->key[i])) { /* Found key */ break; } } } if (i >= d->size) /* Key not found */ return; free(d->key[i]); d->key[i] = NULL; if (d->val[i] != NULL) { free(d->val[i]); d->val[i] = NULL; } d->hash[i] = 0; d->n--; return; } /*-------------------------------------------------------------------------*/ /** @brief Dump a dictionary to an opened file pointer. @param d Dictionary to dump @param f Opened file pointer. @return void Dumps a dictionary onto an opened file pointer. Key pairs are printed out as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as output file pointers. */ /*--------------------------------------------------------------------------*/ void dictionary_dump(const dictionary *d, FILE *out) { ssize_t i; if (d == NULL || out == NULL) return; if (d->n < 1) { fprintf(out, "empty dictionary\n"); return; } for (i = 0; i < d->size; i++) { if (d->key[i]) { fprintf(out, "%20s\t[%s]\n", d->key[i], d->val[i] ? d->val[i] : "UNDEF"); } } return; } cava-0.7.4/iniparser/src/dictionary.h000066400000000000000000000146741405100172200175410ustar00rootroot00000000000000 /*-------------------------------------------------------------------------*/ /** @file dictionary.h @author N. Devillard @brief Implements a dictionary for string variables. This module implements a simple dictionary object, i.e. a list of string/string associations. This object is useful to store e.g. informations retrieved from a configuration file (ini files). */ /*--------------------------------------------------------------------------*/ #ifndef _DICTIONARY_H_ #define _DICTIONARY_H_ /*--------------------------------------------------------------------------- Includes ---------------------------------------------------------------------------*/ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*--------------------------------------------------------------------------- New types ---------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /** @brief Dictionary object This object contains a list of string/string associations. Each association is identified by a unique string key. Looking up values in the dictionary is speeded up by the use of a (hopefully collision-free) hash function. */ /*-------------------------------------------------------------------------*/ typedef struct _dictionary_ { int n; /** Number of entries in dictionary */ ssize_t size; /** Storage size */ char **val; /** List of string values */ char **key; /** List of string keys */ unsigned *hash; /** List of hash values for keys */ } dictionary; /*--------------------------------------------------------------------------- Function prototypes ---------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /** @brief Compute the hash key for a string. @param key Character string to use for key. @return 1 unsigned int on at least 32 bits. This hash function has been taken from an Article in Dr Dobbs Journal. This is normally a collision-free function, distributing keys evenly. The key is stored anyway in the struct so that collision can be avoided by comparing the key itself in last resort. */ /*--------------------------------------------------------------------------*/ unsigned dictionary_hash(const char *key); /*-------------------------------------------------------------------------*/ /** @brief Create a new dictionary object. @param size Optional initial size of the dictionary. @return 1 newly allocated dictionary objet. This function allocates a new dictionary object of given size and returns it. If you do not know in advance (roughly) the number of entries in the dictionary, give size=0. */ /*--------------------------------------------------------------------------*/ dictionary *dictionary_new(size_t size); /*-------------------------------------------------------------------------*/ /** @brief Delete a dictionary object @param d dictionary object to deallocate. @return void Deallocate a dictionary object and all memory associated to it. */ /*--------------------------------------------------------------------------*/ void dictionary_del(dictionary *vd); /*-------------------------------------------------------------------------*/ /** @brief Get a value from a dictionary. @param d dictionary object to search. @param key Key to look for in the dictionary. @param def Default value to return if key not found. @return 1 pointer to internally allocated character string. This function locates a key in a dictionary and returns a pointer to its value, or the passed 'def' pointer if no such key can be found in dictionary. The returned character pointer points to data internal to the dictionary object, you should not try to free it or modify it. */ /*--------------------------------------------------------------------------*/ const char *dictionary_get(const dictionary *d, const char *key, const char *def); /*-------------------------------------------------------------------------*/ /** @brief Set a value in a dictionary. @param d dictionary object to modify. @param key Key to modify or add. @param val Value to add. @return int 0 if Ok, anything else otherwise If the given key is found in the dictionary, the associated value is replaced by the provided one. If the key cannot be found in the dictionary, it is added to it. It is Ok to provide a NULL value for val, but NULL values for the dictionary or the key are considered as errors: the function will return immediately in such a case. Notice that if you dictionary_set a variable to NULL, a call to dictionary_get will return a NULL value: the variable will be found, and its value (NULL) is returned. In other words, setting the variable content to NULL is equivalent to deleting the variable from the dictionary. It is not possible (in this implementation) to have a key in the dictionary without value. This function returns non-zero in case of failure. */ /*--------------------------------------------------------------------------*/ int dictionary_set(dictionary *vd, const char *key, const char *val); /*-------------------------------------------------------------------------*/ /** @brief Delete a key in a dictionary @param d dictionary object to modify. @param key Key to remove. @return void This function deletes a key in a dictionary. Nothing is done if the key cannot be found. */ /*--------------------------------------------------------------------------*/ void dictionary_unset(dictionary *d, const char *key); /*-------------------------------------------------------------------------*/ /** @brief Dump a dictionary to an opened file pointer. @param d Dictionary to dump @param f Opened file pointer. @return void Dumps a dictionary onto an opened file pointer. Key pairs are printed out as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as output file pointers. */ /*--------------------------------------------------------------------------*/ void dictionary_dump(const dictionary *d, FILE *out); #ifdef __cplusplus } #endif #endif cava-0.7.4/iniparser/src/iniparser.c000066400000000000000000000555171405100172200173640ustar00rootroot00000000000000 /*-------------------------------------------------------------------------*/ /** @file iniparser.c @author N. Devillard @brief Parser for ini files. */ /*--------------------------------------------------------------------------*/ /*---------------------------- Includes ------------------------------------*/ #include "iniparser.h" #include /*---------------------------- Defines -------------------------------------*/ #define ASCIILINESZ (1024) #define INI_INVALID_KEY ((char *)-1) /*--------------------------------------------------------------------------- Private to this module ---------------------------------------------------------------------------*/ /** * This enum stores the status for each parsed line (internal use only). */ typedef enum _line_status_ { LINE_UNPROCESSED, LINE_ERROR, LINE_EMPTY, LINE_COMMENT, LINE_SECTION, LINE_VALUE } line_status; /*-------------------------------------------------------------------------*/ /** @brief Convert a string to lowercase. @param in String to convert. @param out Output buffer. @param len Size of the out buffer. @return ptr to the out buffer or NULL if an error occured. This function convert a string into lowercase. At most len - 1 elements of the input string will be converted. */ /*--------------------------------------------------------------------------*/ static const char *strlwc(const char *in, char *out, unsigned len) { unsigned i; if (in == NULL || out == NULL || len == 0) return NULL; i = 0; while (in[i] != '\0' && i < len - 1) { out[i] = (char)tolower((int)in[i]); i++; } out[i] = '\0'; return out; } /*-------------------------------------------------------------------------*/ /** @brief Duplicate a string @param s String to duplicate @return Pointer to a newly allocated string, to be freed with free() This is a replacement for strdup(). This implementation is provided for systems that do not have it. */ /*--------------------------------------------------------------------------*/ static char *xstrdup(const char *s) { char *t; size_t len; if (!s) return NULL; len = strlen(s) + 1; t = (char *)malloc(len); if (t) { memcpy(t, s, len); } return t; } /*-------------------------------------------------------------------------*/ /** @brief Remove blanks at the beginning and the end of a string. @param str String to parse and alter. @return unsigned New size of the string. */ /*--------------------------------------------------------------------------*/ unsigned strstrip(char *s) { char *last = NULL; char *dest = s; if (s == NULL) return 0; last = s + strlen(s); while (isspace((int)*s) && *s) s++; while (last > s) { if (!isspace((int)*(last - 1))) break; last--; } *last = (char)0; memmove(dest, s, last - s + 1); return last - s; } /*-------------------------------------------------------------------------*/ /** @brief Get number of sections in a dictionary @param d Dictionary to examine @return int Number of sections found in dictionary This function returns the number of sections found in a dictionary. The test to recognize sections is done on the string stored in the dictionary: a section name is given as "section" whereas a key is stored as "section:key", thus the test looks for entries that do not contain a colon. This clearly fails in the case a section name contains a colon, but this should simply be avoided. This function returns -1 in case of error. */ /*--------------------------------------------------------------------------*/ int iniparser_getnsec(const dictionary *d) { int i; int nsec; if (d == NULL) return -1; nsec = 0; for (i = 0; i < d->size; i++) { if (d->key[i] == NULL) continue; if (strchr(d->key[i], ':') == NULL) { nsec++; } } return nsec; } /*-------------------------------------------------------------------------*/ /** @brief Get name for section n in a dictionary. @param d Dictionary to examine @param n Section number (from 0 to nsec-1). @return Pointer to char string This function locates the n-th section in a dictionary and returns its name as a pointer to a string statically allocated inside the dictionary. Do not free or modify the returned string! This function returns NULL in case of error. */ /*--------------------------------------------------------------------------*/ const char *iniparser_getsecname(const dictionary *d, int n) { int i; int foundsec; if (d == NULL || n < 0) return NULL; foundsec = 0; for (i = 0; i < d->size; i++) { if (d->key[i] == NULL) continue; if (strchr(d->key[i], ':') == NULL) { foundsec++; if (foundsec > n) break; } } if (foundsec <= n) { return NULL; } return d->key[i]; } /*-------------------------------------------------------------------------*/ /** @brief Dump a dictionary to an opened file pointer. @param d Dictionary to dump. @param f Opened file pointer to dump to. @return void This function prints out the contents of a dictionary, one element by line, onto the provided file pointer. It is OK to specify @c stderr or @c stdout as output files. This function is meant for debugging purposes mostly. */ /*--------------------------------------------------------------------------*/ void iniparser_dump(const dictionary *d, FILE *f) { int i; if (d == NULL || f == NULL) return; for (i = 0; i < d->size; i++) { if (d->key[i] == NULL) continue; if (d->val[i] != NULL) { fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); } else { fprintf(f, "[%s]=UNDEF\n", d->key[i]); } } return; } /*-------------------------------------------------------------------------*/ /** @brief Save a dictionary to a loadable ini file @param d Dictionary to dump @param f Opened file pointer to dump to @return void This function dumps a given dictionary into a loadable ini file. It is Ok to specify @c stderr or @c stdout as output files. */ /*--------------------------------------------------------------------------*/ void iniparser_dump_ini(const dictionary *d, FILE *f) { int i; int nsec; const char *secname; if (d == NULL || f == NULL) return; nsec = iniparser_getnsec(d); if (nsec < 1) { /* No section in file: dump all keys as they are */ for (i = 0; i < d->size; i++) { if (d->key[i] == NULL) continue; fprintf(f, "%s = %s\n", d->key[i], d->val[i]); } return; } for (i = 0; i < nsec; i++) { secname = iniparser_getsecname(d, i); iniparser_dumpsection_ini(d, secname, f); } fprintf(f, "\n"); return; } /*-------------------------------------------------------------------------*/ /** @brief Save a dictionary section to a loadable ini file @param d Dictionary to dump @param s Section name of dictionary to dump @param f Opened file pointer to dump to @return void This function dumps a given section of a given dictionary into a loadable ini file. It is Ok to specify @c stderr or @c stdout as output files. */ /*--------------------------------------------------------------------------*/ void iniparser_dumpsection_ini(const dictionary *d, const char *s, FILE *f) { int j; char keym[ASCIILINESZ + 1]; int seclen; if (d == NULL || f == NULL) return; if (!iniparser_find_entry(d, s)) return; seclen = (int)strlen(s); fprintf(f, "\n[%s]\n", s); sprintf(keym, "%s:", s); for (j = 0; j < d->size; j++) { if (d->key[j] == NULL) continue; if (!strncmp(d->key[j], keym, seclen + 1)) { fprintf(f, "%-30s = %s\n", d->key[j] + seclen + 1, d->val[j] ? d->val[j] : ""); } } fprintf(f, "\n"); return; } /*-------------------------------------------------------------------------*/ /** @brief Get the number of keys in a section of a dictionary. @param d Dictionary to examine @param s Section name of dictionary to examine @return Number of keys in section */ /*--------------------------------------------------------------------------*/ int iniparser_getsecnkeys(const dictionary *d, const char *s) { int seclen, nkeys; char keym[ASCIILINESZ + 1]; int j; nkeys = 0; if (d == NULL) return nkeys; if (!iniparser_find_entry(d, s)) return nkeys; seclen = (int)strlen(s); sprintf(keym, "%s:", s); for (j = 0; j < d->size; j++) { if (d->key[j] == NULL) continue; if (!strncmp(d->key[j], keym, seclen + 1)) nkeys++; } return nkeys; } /*-------------------------------------------------------------------------*/ /** @brief Get the number of keys in a section of a dictionary. @param d Dictionary to examine @param s Section name of dictionary to examine @param keys Already allocated array to store the keys in @return The pointer passed as `keys` argument or NULL in case of error This function queries a dictionary and finds all keys in a given section. The keys argument should be an array of pointers which size has been determined by calling `iniparser_getsecnkeys` function prior to this one. Each pointer in the returned char pointer-to-pointer is pointing to a string allocated in the dictionary; do not free or modify them. */ /*--------------------------------------------------------------------------*/ const char **iniparser_getseckeys(const dictionary *d, const char *s, const char **keys) { int i, j, seclen; char keym[ASCIILINESZ + 1]; if (d == NULL || keys == NULL) return NULL; if (!iniparser_find_entry(d, s)) return NULL; seclen = (int)strlen(s); sprintf(keym, "%s:", s); i = 0; for (j = 0; j < d->size; j++) { if (d->key[j] == NULL) continue; if (!strncmp(d->key[j], keym, seclen + 1)) { keys[i] = d->key[j]; i++; } } return keys; } /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key @param d Dictionary to search @param key Key string to look for @param def Default value to return if key not found. @return pointer to statically allocated character string This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the pointer passed as 'def' is returned. The returned char pointer is pointing to a string allocated in the dictionary, do not free or modify it. */ /*--------------------------------------------------------------------------*/ const char *iniparser_getstring(const dictionary *d, const char *key, const char *def) { const char *lc_key; const char *sval; char tmp_str[ASCIILINESZ + 1]; if (d == NULL || key == NULL) return def; lc_key = strlwc(key, tmp_str, sizeof(tmp_str)); sval = dictionary_get(d, lc_key, def); return sval; } /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key, convert to an int @param d Dictionary to search @param key Key string to look for @param notfound Value to return in case of error @return integer This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned. Supported values for integers include the usual C notation so decimal, octal (starting with 0) and hexadecimal (starting with 0x) are supported. Examples: "42" -> 42 "042" -> 34 (octal -> decimal) "0x42" -> 66 (hexa -> decimal) Warning: the conversion may overflow in various ways. Conversion is totally outsourced to strtol(), see the associated man page for overflow handling. Credits: Thanks to A. Becker for suggesting strtol() */ /*--------------------------------------------------------------------------*/ int iniparser_getint(const dictionary *d, const char *key, int notfound) { const char *str; str = iniparser_getstring(d, key, INI_INVALID_KEY); if (str == INI_INVALID_KEY) return notfound; return (int)strtol(str, NULL, 0); } /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key, convert to a double @param d Dictionary to search @param key Key string to look for @param notfound Value to return in case of error @return double This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned. */ /*--------------------------------------------------------------------------*/ double iniparser_getdouble(const dictionary *d, const char *key, double notfound) { const char *str; str = iniparser_getstring(d, key, INI_INVALID_KEY); if (str == INI_INVALID_KEY) return notfound; return atof(str); } /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key, convert to a boolean @param d Dictionary to search @param key Key string to look for @param notfound Value to return in case of error @return integer This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned. A true boolean is found if one of the following is matched: - A string starting with 'y' - A string starting with 'Y' - A string starting with 't' - A string starting with 'T' - A string starting with '1' A false boolean is found if one of the following is matched: - A string starting with 'n' - A string starting with 'N' - A string starting with 'f' - A string starting with 'F' - A string starting with '0' The notfound value returned if no boolean is identified, does not necessarily have to be 0 or 1. */ /*--------------------------------------------------------------------------*/ int iniparser_getboolean(const dictionary *d, const char *key, int notfound) { int ret; const char *c; c = iniparser_getstring(d, key, INI_INVALID_KEY); if (c == INI_INVALID_KEY) return notfound; if (c[0] == 'y' || c[0] == 'Y' || c[0] == '1' || c[0] == 't' || c[0] == 'T') { ret = 1; } else if (c[0] == 'n' || c[0] == 'N' || c[0] == '0' || c[0] == 'f' || c[0] == 'F') { ret = 0; } else { ret = notfound; } return ret; } /*-------------------------------------------------------------------------*/ /** @brief Finds out if a given entry exists in a dictionary @param ini Dictionary to search @param entry Name of the entry to look for @return integer 1 if entry exists, 0 otherwise Finds out if a given entry exists in the dictionary. Since sections are stored as keys with NULL associated values, this is the only way of querying for the presence of sections in a dictionary. */ /*--------------------------------------------------------------------------*/ int iniparser_find_entry(const dictionary *ini, const char *entry) { int found = 0; if (iniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) { found = 1; } return found; } /*-------------------------------------------------------------------------*/ /** @brief Set an entry in a dictionary. @param ini Dictionary to modify. @param entry Entry to modify (entry name) @param val New value to associate to the entry. @return int 0 if Ok, -1 otherwise. If the given entry can be found in the dictionary, it is modified to contain the provided value. If it cannot be found, the entry is created. It is Ok to set val to NULL. */ /*--------------------------------------------------------------------------*/ int iniparser_set(dictionary *ini, const char *entry, const char *val) { char tmp_str[ASCIILINESZ + 1]; return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val); } /*-------------------------------------------------------------------------*/ /** @brief Delete an entry in a dictionary @param ini Dictionary to modify @param entry Entry to delete (entry name) @return void If the given entry can be found, it is deleted from the dictionary. */ /*--------------------------------------------------------------------------*/ void iniparser_unset(dictionary *ini, const char *entry) { char tmp_str[ASCIILINESZ + 1]; dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str))); } /*-------------------------------------------------------------------------*/ /** @brief Load a single line from an INI file @param input_line Input line, may be concatenated multi-line input @param section Output space to store section @param key Output space to store key @param value Output space to store value @return line_status value */ /*--------------------------------------------------------------------------*/ static line_status iniparser_line(const char *input_line, char *section, char *key, char *value) { line_status sta; char *line = NULL; size_t len; line = xstrdup(input_line); len = strstrip(line); sta = LINE_UNPROCESSED; if (len < 1) { /* Empty line */ sta = LINE_EMPTY; } else if (line[0] == '#' || line[0] == ';') { /* Comment line */ sta = LINE_COMMENT; } else if (line[0] == '[' && line[len - 1] == ']') { /* Section name */ sscanf(line, "[%[^]]", section); strstrip(section); strlwc(section, section, len); sta = LINE_SECTION; } else if (sscanf(line, "%[^=] = \"%[^\"]\"", key, value) == 2 || sscanf(line, "%[^=] = '%[^\']'", key, value) == 2) { /* Usual key=value with quotes, with or without comments */ strstrip(key); strlwc(key, key, len); /* Don't strip spaces from values surrounded with quotes */ /* * sscanf cannot handle '' or "" as empty values * this is done here */ if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { value[0] = 0; } sta = LINE_VALUE; } else if (sscanf(line, "%[^=] = %[^;#]", key, value) == 2) { /* Usual key=value without quotes, with or without comments */ strstrip(key); strlwc(key, key, len); strstrip(value); sta = LINE_VALUE; } else if (sscanf(line, "%[^=] = %[;#]", key, value) == 2 || sscanf(line, "%[^=] %[=]", key, value) == 2) { /* * Special cases: * key= * key=; * key=# */ strstrip(key); strlwc(key, key, len); value[0] = 0; sta = LINE_VALUE; } else { /* Generate syntax error */ sta = LINE_ERROR; } free(line); return sta; } /*-------------------------------------------------------------------------*/ /** @brief Parse an ini file and return an allocated dictionary object @param ininame Name of the ini file to read. @return Pointer to newly allocated dictionary This is the parser for ini files. This function is called, providing the name of the file to be read. It returns a dictionary object that should not be accessed directly, but through accessor functions instead. The returned dictionary must be freed using iniparser_freedict(). */ /*--------------------------------------------------------------------------*/ dictionary *iniparser_load(const char *ininame) { FILE *in; char line[ASCIILINESZ + 1]; char section[ASCIILINESZ + 1]; char key[ASCIILINESZ + 1]; char tmp[(ASCIILINESZ * 2) + 1]; char val[ASCIILINESZ + 1]; int last = 0; int len; int lineno = 0; int errs = 0; dictionary *dict; if ((in = fopen(ininame, "r")) == NULL) { return NULL; } dict = dictionary_new(0); if (!dict) { fclose(in); return NULL; } memset(line, 0, ASCIILINESZ); memset(section, 0, ASCIILINESZ); memset(key, 0, ASCIILINESZ); memset(val, 0, ASCIILINESZ); last = 0; while (fgets(line + last, ASCIILINESZ - last, in) != NULL) { lineno++; len = (int)strlen(line) - 1; if (len == 0) continue; /* Safety check against buffer overflows */ if (line[len] != '\n' && !feof(in)) { fprintf(stderr, "iniparser: input line too long in %s (%d)\n", ininame, lineno); dictionary_del(dict); fclose(in); return NULL; } /* Get rid of \n and spaces at end of line */ while ((len >= 0) && ((line[len] == '\n') || (isspace(line[len])))) { line[len] = 0; len--; } if (len < 0) { /* Line was entirely \n and/or spaces */ len = 0; } /* Detect multi-line */ if (line[len] == '\\') { /* Multi-line value */ last = len; continue; } else { last = 0; } switch (iniparser_line(line, section, key, val)) { case LINE_EMPTY: case LINE_COMMENT: break; case LINE_SECTION: errs = dictionary_set(dict, section, NULL); break; case LINE_VALUE: sprintf(tmp, "%s:%s", section, key); errs = dictionary_set(dict, tmp, val); break; case LINE_ERROR: fprintf(stderr, "iniparser: syntax error in %s (%d):\n", ininame, lineno); fprintf(stderr, "-> %s\n", line); errs++; break; default: break; } memset(line, 0, ASCIILINESZ); last = 0; if (errs < 0) { fprintf(stderr, "iniparser: memory allocation failure\n"); break; } } if (errs) { dictionary_del(dict); dict = NULL; } fclose(in); return dict; } /*-------------------------------------------------------------------------*/ /** @brief Free all memory associated to an ini dictionary @param d Dictionary to free @return void Free all memory associated to an ini dictionary. It is mandatory to call this function before the dictionary object gets out of the current context. */ /*--------------------------------------------------------------------------*/ void iniparser_freedict(dictionary *d) { dictionary_del(d); } cava-0.7.4/iniparser/src/iniparser.h000066400000000000000000000272231405100172200173620ustar00rootroot00000000000000 /*-------------------------------------------------------------------------*/ /** @file iniparser.h @author N. Devillard @brief Parser for ini files. */ /*--------------------------------------------------------------------------*/ #ifndef _INIPARSER_H_ #define _INIPARSER_H_ /*--------------------------------------------------------------------------- Includes ---------------------------------------------------------------------------*/ #include #include #include /* * The following #include is necessary on many Unixes but not Linux. * It is not needed for Windows platforms. * Uncomment it if needed. */ /* #include */ #include "dictionary.h" #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*/ /** @brief Get number of sections in a dictionary @param d Dictionary to examine @return int Number of sections found in dictionary This function returns the number of sections found in a dictionary. The test to recognize sections is done on the string stored in the dictionary: a section name is given as "section" whereas a key is stored as "section:key", thus the test looks for entries that do not contain a colon. This clearly fails in the case a section name contains a colon, but this should simply be avoided. This function returns -1 in case of error. */ /*--------------------------------------------------------------------------*/ int iniparser_getnsec(const dictionary *d); /*-------------------------------------------------------------------------*/ /** @brief Get name for section n in a dictionary. @param d Dictionary to examine @param n Section number (from 0 to nsec-1). @return Pointer to char string This function locates the n-th section in a dictionary and returns its name as a pointer to a string statically allocated inside the dictionary. Do not free or modify the returned string! This function returns NULL in case of error. */ /*--------------------------------------------------------------------------*/ const char *iniparser_getsecname(const dictionary *d, int n); /*-------------------------------------------------------------------------*/ /** @brief Save a dictionary to a loadable ini file @param d Dictionary to dump @param f Opened file pointer to dump to @return void This function dumps a given dictionary into a loadable ini file. It is Ok to specify @c stderr or @c stdout as output files. */ /*--------------------------------------------------------------------------*/ void iniparser_dump_ini(const dictionary *d, FILE *f); /*-------------------------------------------------------------------------*/ /** @brief Save a dictionary section to a loadable ini file @param d Dictionary to dump @param s Section name of dictionary to dump @param f Opened file pointer to dump to @return void This function dumps a given section of a given dictionary into a loadable ini file. It is Ok to specify @c stderr or @c stdout as output files. */ /*--------------------------------------------------------------------------*/ void iniparser_dumpsection_ini(const dictionary *d, const char *s, FILE *f); /*-------------------------------------------------------------------------*/ /** @brief Dump a dictionary to an opened file pointer. @param d Dictionary to dump. @param f Opened file pointer to dump to. @return void This function prints out the contents of a dictionary, one element by line, onto the provided file pointer. It is OK to specify @c stderr or @c stdout as output files. This function is meant for debugging purposes mostly. */ /*--------------------------------------------------------------------------*/ void iniparser_dump(const dictionary *d, FILE *f); /*-------------------------------------------------------------------------*/ /** @brief Get the number of keys in a section of a dictionary. @param d Dictionary to examine @param s Section name of dictionary to examine @return Number of keys in section */ /*--------------------------------------------------------------------------*/ int iniparser_getsecnkeys(const dictionary *d, const char *s); /*-------------------------------------------------------------------------*/ /** @brief Get the number of keys in a section of a dictionary. @param d Dictionary to examine @param s Section name of dictionary to examine @param keys Already allocated array to store the keys in @return The pointer passed as `keys` argument or NULL in case of error This function queries a dictionary and finds all keys in a given section. The keys argument should be an array of pointers which size has been determined by calling `iniparser_getsecnkeys` function prior to this one. Each pointer in the returned char pointer-to-pointer is pointing to a string allocated in the dictionary; do not free or modify them. */ /*--------------------------------------------------------------------------*/ const char **iniparser_getseckeys(const dictionary *d, const char *s, const char **keys); /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key @param d Dictionary to search @param key Key string to look for @param def Default value to return if key not found. @return pointer to statically allocated character string This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the pointer passed as 'def' is returned. The returned char pointer is pointing to a string allocated in the dictionary, do not free or modify it. */ /*--------------------------------------------------------------------------*/ const char *iniparser_getstring(const dictionary *d, const char *key, const char *def); /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key, convert to an int @param d Dictionary to search @param key Key string to look for @param notfound Value to return in case of error @return integer This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned. Supported values for integers include the usual C notation so decimal, octal (starting with 0) and hexadecimal (starting with 0x) are supported. Examples: - "42" -> 42 - "042" -> 34 (octal -> decimal) - "0x42" -> 66 (hexa -> decimal) Warning: the conversion may overflow in various ways. Conversion is totally outsourced to strtol(), see the associated man page for overflow handling. Credits: Thanks to A. Becker for suggesting strtol() */ /*--------------------------------------------------------------------------*/ int iniparser_getint(const dictionary *d, const char *key, int notfound); /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key, convert to a double @param d Dictionary to search @param key Key string to look for @param notfound Value to return in case of error @return double This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned. */ /*--------------------------------------------------------------------------*/ double iniparser_getdouble(const dictionary *d, const char *key, double notfound); /*-------------------------------------------------------------------------*/ /** @brief Get the string associated to a key, convert to a boolean @param d Dictionary to search @param key Key string to look for @param notfound Value to return in case of error @return integer This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned. A true boolean is found if one of the following is matched: - A string starting with 'y' - A string starting with 'Y' - A string starting with 't' - A string starting with 'T' - A string starting with '1' A false boolean is found if one of the following is matched: - A string starting with 'n' - A string starting with 'N' - A string starting with 'f' - A string starting with 'F' - A string starting with '0' The notfound value returned if no boolean is identified, does not necessarily have to be 0 or 1. */ /*--------------------------------------------------------------------------*/ int iniparser_getboolean(const dictionary *d, const char *key, int notfound); /*-------------------------------------------------------------------------*/ /** @brief Set an entry in a dictionary. @param ini Dictionary to modify. @param entry Entry to modify (entry name) @param val New value to associate to the entry. @return int 0 if Ok, -1 otherwise. If the given entry can be found in the dictionary, it is modified to contain the provided value. If it cannot be found, the entry is created. It is Ok to set val to NULL. */ /*--------------------------------------------------------------------------*/ int iniparser_set(dictionary *ini, const char *entry, const char *val); /*-------------------------------------------------------------------------*/ /** @brief Delete an entry in a dictionary @param ini Dictionary to modify @param entry Entry to delete (entry name) @return void If the given entry can be found, it is deleted from the dictionary. */ /*--------------------------------------------------------------------------*/ void iniparser_unset(dictionary *ini, const char *entry); /*-------------------------------------------------------------------------*/ /** @brief Finds out if a given entry exists in a dictionary @param ini Dictionary to search @param entry Name of the entry to look for @return integer 1 if entry exists, 0 otherwise Finds out if a given entry exists in the dictionary. Since sections are stored as keys with NULL associated values, this is the only way of querying for the presence of sections in a dictionary. */ /*--------------------------------------------------------------------------*/ int iniparser_find_entry(const dictionary *ini, const char *entry); /*-------------------------------------------------------------------------*/ /** @brief Parse an ini file and return an allocated dictionary object @param ininame Name of the ini file to read. @return Pointer to newly allocated dictionary This is the parser for ini files. This function is called, providing the name of the file to be read. It returns a dictionary object that should not be accessed directly, but through accessor functions instead. The returned dictionary must be freed using iniparser_freedict(). */ /*--------------------------------------------------------------------------*/ dictionary *iniparser_load(const char *ininame); /*-------------------------------------------------------------------------*/ /** @brief Free all memory associated to an ini dictionary @param d Dictionary to free @return void Free all memory associated to an ini dictionary. It is mandatory to call this function before the dictionary object gets out of the current context. */ /*--------------------------------------------------------------------------*/ void iniparser_freedict(dictionary *d); #ifdef __cplusplus } #endif #endif cava-0.7.4/input/000077500000000000000000000000001405100172200135635ustar00rootroot00000000000000cava-0.7.4/input/alsa.c000066400000000000000000000137351405100172200146600ustar00rootroot00000000000000// input: ALSA #include "input/alsa.h" #include "debug.h" #include "input/common.h" #include #include #include // assuming stereo #define CHANNELS_COUNT 2 #define SAMPLE_RATE 44100 static void initialize_audio_parameters(snd_pcm_t **handle, struct audio_data *audio, snd_pcm_uframes_t *frames) { // alsa: open device to capture audio int err = snd_pcm_open(handle, audio->source, SND_PCM_STREAM_CAPTURE, 0); if (err < 0) { fprintf(stderr, "error opening stream: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } else debug("open stream successful\n"); snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); // assembling params snd_pcm_hw_params_any(*handle, params); // setting defaults or something // interleaved mode right left right left snd_pcm_hw_params_set_access(*handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); // trying to set 16bit snd_pcm_hw_params_set_format(*handle, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(*handle, params, CHANNELS_COUNT); unsigned int sample_rate = SAMPLE_RATE; // trying our rate snd_pcm_hw_params_set_rate_near(*handle, params, &sample_rate, NULL); // number of frames pr read snd_pcm_hw_params_set_period_size_near(*handle, params, frames, NULL); err = snd_pcm_hw_params(*handle, params); // attempting to set params if (err < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = snd_pcm_prepare(*handle)) < 0) { fprintf(stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror(err)); exit(EXIT_FAILURE); } // getting actual format snd_pcm_hw_params_get_format(params, (snd_pcm_format_t *)&sample_rate); // converting result to number of bits if (sample_rate <= 5) audio->format = 16; else if (sample_rate <= 9) audio->format = 24; else audio->format = 32; snd_pcm_hw_params_get_rate(params, &audio->rate, NULL); snd_pcm_hw_params_get_period_size(params, frames, NULL); // snd_pcm_hw_params_get_period_time(params, &sample_rate, &dir); } static int get_certain_frame(signed char *buffer, int buffer_index, int adjustment) { // using the 10 upper bits this would give me a vert res of 1024, enough... int temp = buffer[buffer_index + adjustment - 1] << 2; int lo = buffer[buffer_index + adjustment - 2] >> 6; if (lo < 0) lo = abs(lo) + 1; if (temp >= 0) temp += lo; else temp -= lo; return temp; } /* static void fill_audio_outs(struct audio_data* audio, signed char* buffer, const int size) { int radj = audio->format / 4; // adjustments for interleaved int ladj = audio->format / 8; static int audio_out_buffer_index = 0; // sorting out one channel and only biggest octet for (int buffer_index = 0; buffer_index < size; buffer_index += ladj * 2) { // first channel int tempr = get_certain_frame(buffer, buffer_index, radj); // second channel int templ = get_certain_frame(buffer, buffer_index, ladj); // mono: adding channels and storing it in the buffer if (audio->channels == 1) audio->audio_out_l[audio_out_buffer_index] = (templ + tempr) / 2; else { // stereo storing channels in buffer audio->audio_out_l[audio_out_buffer_index] = templ; audio->audio_out_r[audio_out_buffer_index] = tempr; } ++audio_out_buffer_index; audio_out_buffer_index %= audio->FFTbufferSize; } } */ void *input_alsa(void *data) { int err; struct audio_data *audio = (struct audio_data *)data; snd_pcm_t *handle; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; snd_pcm_uframes_t frames = audio->FFTtreblebufferSize; initialize_audio_parameters(&handle, audio, &frames); snd_pcm_get_params(handle, &buffer_size, &period_size); int radj = audio->format / 4; // adjustments for interleaved int ladj = audio->format / 8; int16_t buf[period_size]; int32_t buffer32[period_size]; frames = period_size / ((audio->format / 8) * CHANNELS_COUNT); // printf("period size: %lu\n", period_size); // exit(0); // frames * bits/8 * channels // const int size = frames * (audio->format / 8) * CHANNELS_COUNT; signed char *buffer = malloc(period_size); while (!audio->terminate) { switch (audio->format) { case 16: err = snd_pcm_readi(handle, buf, frames); break; case 32: err = snd_pcm_readi(handle, buffer32, frames); for (uint16_t i = 0; i < frames * 2; i++) { buf[i] = buffer32[i] / pow(2, 16); } break; default: err = snd_pcm_readi(handle, buffer, frames); // sorting out one channel and only biggest octet for (uint16_t i = 0; i < period_size * 2; i += ladj * 2) { // first channel buf[i] = get_certain_frame(buffer, i, ladj); // second channel buf[i + 1] = get_certain_frame(buffer, i, radj); } // fill_audio_outs(audio, buffer, period_size); break; } if (err == -EPIPE) { /* EPIPE means overrun */ debug("overrun occurred\n"); snd_pcm_prepare(handle); } else if (err < 0) { debug("error from read: %s\n", snd_strerror(err)); } else if (err != (int)frames) { debug("short read, read %d %d frames\n", err, (int)frames); } pthread_mutex_lock(&lock); write_to_fftw_input_buffers(frames, buf, data); pthread_mutex_unlock(&lock); } free(buffer); snd_pcm_close(handle); return NULL; } cava-0.7.4/input/alsa.h000066400000000000000000000001241405100172200146510ustar00rootroot00000000000000// header file for alsa, part of cava. #pragma once void *input_alsa(void *data); cava-0.7.4/input/common.c000066400000000000000000000076641405100172200152340ustar00rootroot00000000000000#include "input/common.h" #include #include void reset_output_buffers(struct audio_data *data) { memset(data->in_bass_r, 0, sizeof(double) * data->FFTbassbufferSize); memset(data->in_bass_l, 0, sizeof(double) * data->FFTbassbufferSize); memset(data->in_mid_r, 0, sizeof(double) * data->FFTmidbufferSize); memset(data->in_mid_l, 0, sizeof(double) * data->FFTmidbufferSize); memset(data->in_treble_r, 0, sizeof(double) * data->FFTtreblebufferSize); memset(data->in_treble_l, 0, sizeof(double) * data->FFTtreblebufferSize); memset(data->in_bass_r_raw, 0, sizeof(double) * data->FFTbassbufferSize); memset(data->in_bass_l_raw, 0, sizeof(double) * data->FFTbassbufferSize); memset(data->in_mid_r_raw, 0, sizeof(double) * data->FFTmidbufferSize); memset(data->in_mid_l_raw, 0, sizeof(double) * data->FFTmidbufferSize); memset(data->in_treble_r_raw, 0, sizeof(double) * data->FFTtreblebufferSize); memset(data->in_treble_l_raw, 0, sizeof(double) * data->FFTtreblebufferSize); } int write_to_fftw_input_buffers(int16_t frames, int16_t buf[frames * 2], void *data) { if (frames == 0) return 0; struct audio_data *audio = (struct audio_data *)data; for (uint16_t n = audio->FFTbassbufferSize; n > frames; n = n - frames) { for (uint16_t i = 1; i <= frames; i++) { audio->in_bass_l_raw[n - i] = audio->in_bass_l_raw[n - i - frames]; if (audio->channels == 2) audio->in_bass_r_raw[n - i] = audio->in_bass_r_raw[n - i - frames]; } } for (uint16_t n = audio->FFTmidbufferSize; n > frames; n = n - frames) { for (uint16_t i = 1; i <= frames; i++) { audio->in_mid_l_raw[n - i] = audio->in_mid_l_raw[n - i - frames]; if (audio->channels == 2) audio->in_mid_r_raw[n - i] = audio->in_mid_r_raw[n - i - frames]; } } for (uint16_t n = audio->FFTtreblebufferSize; n > frames; n = n - frames) { for (uint16_t i = 1; i <= frames; i++) { audio->in_treble_l_raw[n - i] = audio->in_treble_l_raw[n - i - frames]; if (audio->channels == 2) audio->in_treble_r_raw[n - i] = audio->in_treble_r_raw[n - i - frames]; } } uint16_t n = frames - 1; for (uint16_t i = 0; i < frames; i++) { if (audio->channels == 1) { if (audio->average) { audio->in_bass_l_raw[n] = (buf[i * 2] + buf[i * 2 + 1]) / 2; } if (audio->left) { audio->in_bass_l_raw[n] = buf[i * 2]; } if (audio->right) { audio->in_bass_l_raw[n] = buf[i * 2 + 1]; } } // stereo storing channels in buffer if (audio->channels == 2) { audio->in_bass_l_raw[n] = buf[i * 2]; audio->in_bass_r_raw[n] = buf[i * 2 + 1]; audio->in_mid_r_raw[n] = audio->in_bass_r_raw[n]; audio->in_treble_r_raw[n] = audio->in_bass_r_raw[n]; } audio->in_mid_l_raw[n] = audio->in_bass_l_raw[n]; audio->in_treble_l_raw[n] = audio->in_bass_l_raw[n]; n--; } // Hann Window for (int i = 0; i < audio->FFTbassbufferSize; i++) { audio->in_bass_l[i] = audio->bass_multiplier[i] * audio->in_bass_l_raw[i]; if (audio->channels == 2) audio->in_bass_r[i] = audio->bass_multiplier[i] * audio->in_bass_r_raw[i]; } for (int i = 0; i < audio->FFTmidbufferSize; i++) { audio->in_mid_l[i] = audio->mid_multiplier[i] * audio->in_mid_l_raw[i]; if (audio->channels == 2) audio->in_mid_r[i] = audio->mid_multiplier[i] * audio->in_mid_r_raw[i]; } for (int i = 0; i < audio->FFTtreblebufferSize; i++) { audio->in_treble_l[i] = audio->treble_multiplier[i] * audio->in_treble_l_raw[i]; if (audio->channels == 2) audio->in_treble_r[i] = audio->treble_multiplier[i] * audio->in_treble_r_raw[i]; } return 0; } cava-0.7.4/input/common.h000066400000000000000000000022421405100172200152240ustar00rootroot00000000000000#pragma once #include #include #include #include #include #include #include #include #include #include struct audio_data { int FFTbassbufferSize; int FFTmidbufferSize; int FFTtreblebufferSize; int bass_index; int mid_index; int treble_index; double *bass_multiplier; double *mid_multiplier; double *treble_multiplier; double *in_bass_r_raw, *in_bass_l_raw; double *in_mid_r_raw, *in_mid_l_raw; double *in_treble_r_raw, *in_treble_l_raw; double *in_bass_r, *in_bass_l; double *in_mid_r, *in_mid_l; double *in_treble_r, *in_treble_l; int format; unsigned int rate; char *source; // alsa device, fifo path or pulse source int im; // input mode alsa, fifo or pulse unsigned int channels; bool left, right, average; int terminate; // shared variable used to terminate audio thread char error_message[1024]; }; void reset_output_buffers(struct audio_data *data); int write_to_fftw_input_buffers(int16_t frames, int16_t buf[frames * 2], void *data); extern pthread_mutex_t lock; cava-0.7.4/input/fifo.c000066400000000000000000000052021405100172200146510ustar00rootroot00000000000000#include "input/fifo.h" #include "input/common.h" #include int open_fifo(const char *path) { int fd = open(path, O_RDONLY); int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; } // input: FIFO void *input_fifo(void *data) { struct audio_data *audio = (struct audio_data *)data; int SAMPLES_PER_BUFFER = audio->FFTtreblebufferSize * 2; int bytes_per_sample = audio->format / 8; __attribute__((aligned(sizeof(uint16_t)))) uint8_t buf[SAMPLES_PER_BUFFER * bytes_per_sample]; uint16_t *samples = bytes_per_sample == 2 ? (uint16_t *)&buf : calloc(SAMPLES_PER_BUFFER, sizeof(uint16_t)); int fd = open_fifo(audio->source); while (!audio->terminate) { int time_since_last_input = 0; unsigned int offset = 0; do { int num_read = read(fd, buf + offset, sizeof(buf) - offset); if (num_read < 1) { // if no bytes read sleep 10ms and zero shared buffer nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 10000000}, NULL); time_since_last_input++; if (time_since_last_input > 10) { reset_output_buffers(audio); close(fd); fd = open_fifo(audio->source); time_since_last_input = 0; offset = 0; } } else { offset += num_read; time_since_last_input = 0; } } while (offset < sizeof(buf)); switch (bytes_per_sample) { case 2: // [samples] = [buf] so there's nothing to do here. break; case 3: for (int i = 0; i < SAMPLES_PER_BUFFER; i++) { // Really, a sample is composed of buf[3i + 2] | buf[3i + 1] | buf[3i], but our FFT // only takes 16-bit samples. Since we need to scale them eventually, we can just // do so here by taking the top 2 bytes. samples[i] = (buf[3 * i + 2] << 8) | buf[3 * i + 1]; } break; case 4: for (int i = 0; i < SAMPLES_PER_BUFFER; i++) { samples[i] = (buf[4 * i + 3] << 8) | buf[4 * i + 2]; } break; } // We worked with unsigned ints up until now to save on sign extension, but the FFT wants // signed ints. pthread_mutex_lock(&lock); write_to_fftw_input_buffers(SAMPLES_PER_BUFFER / 2, (int16_t *)samples, audio); pthread_mutex_unlock(&lock); } close(fd); if (bytes_per_sample != 2) { free(samples); } return 0; } cava-0.7.4/input/fifo.h000066400000000000000000000001241405100172200146540ustar00rootroot00000000000000// header files for fifo, part of cava #pragma once void *input_fifo(void *data); cava-0.7.4/input/portaudio.c000066400000000000000000000132441405100172200157410ustar00rootroot00000000000000#include "input/portaudio.h" #include "input/common.h" #include #define SAMPLE_SILENCE -32767 #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; typedef struct { int frameIndex; /* Index into sample array. */ int maxFrameIndex; SAMPLE *recordedSamples; } paTestData; static struct audio_data *audio; int16_t silence_buffer[8092] = {SAMPLE_SILENCE}; static int recordCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { paTestData *data = (paTestData *)userData; SAMPLE *rptr = (SAMPLE *)inputBuffer; long framesToCalc; int finished; unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; (void)outputBuffer; // Prevent unused variable warnings. (void)timeInfo; (void)statusFlags; (void)userData; if (framesLeft < framesPerBuffer) { framesToCalc = framesLeft; finished = paComplete; } else { framesToCalc = framesPerBuffer; finished = paContinue; } pthread_mutex_lock(&lock); if (inputBuffer == NULL) write_to_fftw_input_buffers(framesToCalc, silence_buffer, audio); else write_to_fftw_input_buffers(framesToCalc, rptr, audio); pthread_mutex_unlock(&lock); data->frameIndex += framesToCalc; if (finished == paComplete) { data->frameIndex = 0; finished = paContinue; } if (audio->terminate == 1) finished = paComplete; return finished; } void portaudio_simple_free(paTestData data) { Pa_Terminate(); free(data.recordedSamples); } void *input_portaudio(void *audiodata) { audio = (struct audio_data *)audiodata; PaStreamParameters inputParameters; PaStream *stream; PaError err = paNoError; paTestData data; // start portaudio err = Pa_Initialize(); if (err != paNoError) { fprintf(stderr, "Error: unable to initilize portaudio - %s\n", Pa_GetErrorText(err)); exit(EXIT_FAILURE); } // get portaudio device int deviceNum = -1, numOfDevices = Pa_GetDeviceCount(); if (!strcmp(audio->source, "list")) { if (numOfDevices < 0) { fprintf(stderr, "Error: portaudio was unable to find a audio device! Code: 0x%x\n", numOfDevices); exit(EXIT_FAILURE); } for (int i = 0; i < numOfDevices; i++) { const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i); printf("Device #%d: %s\n" "\tInput Channels: %d\n" "\tOutput Channels: %d\n" "\tDefault SampleRate: %lf\n", i + 1, deviceInfo->name, deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels, deviceInfo->defaultSampleRate); } exit(EXIT_SUCCESS); } else if (!strcmp(audio->source, "auto")) { deviceNum = Pa_GetDefaultInputDevice(); if (deviceNum == paNoDevice) { fprintf(stderr, "Error: no portaudio input device found\n"); exit(EXIT_FAILURE); } } else if (sscanf(audio->source, "%d", &deviceNum)) { if (deviceNum > numOfDevices) { fprintf(stderr, "Error: Invalid input device!\n"); exit(EXIT_FAILURE); } deviceNum--; } else { for (int i = 0; i < numOfDevices; i++) { const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i); if (!strcmp(audio->source, deviceInfo->name)) { deviceNum = i; break; } } if (deviceNum == -1) { fprintf(stderr, "Error: No such device '%s'!\n", audio->source); exit(EXIT_FAILURE); } } inputParameters.device = deviceNum; // set parameters data.maxFrameIndex = audio->FFTtreblebufferSize * 1024; data.recordedSamples = (SAMPLE *)malloc(2 * data.maxFrameIndex * sizeof(SAMPLE)); if (data.recordedSamples == NULL) { fprintf(stderr, "Error: failure in memory allocation!\n"); exit(EXIT_FAILURE); } else memset(data.recordedSamples, 0x00, 2 * data.maxFrameIndex); inputParameters.channelCount = 2; inputParameters.sampleFormat = PA_SAMPLE_TYPE; inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; inputParameters.hostApiSpecificStreamInfo = NULL; // set it to work err = Pa_OpenStream(&stream, &inputParameters, NULL, audio->rate, audio->FFTtreblebufferSize, paClipOff, recordCallback, &data); if (err != paNoError) { fprintf(stderr, "Error: failure in opening stream (%x)\n", err); exit(EXIT_FAILURE); } // main loop while (1) { // start recording data.frameIndex = 0; err = Pa_StartStream(stream); if (err != paNoError) { fprintf(stderr, "Error: failure in starting stream (%x)\n", err); exit(EXIT_FAILURE); } // record while ((err = Pa_IsStreamActive(stream)) == 1) { Pa_Sleep(1000); if (audio->terminate == 1) break; } // check for errors if (err < 0) { fprintf(stderr, "Error: failure in recording audio (%x)\n", err); exit(EXIT_FAILURE); } // check if it bailed if (audio->terminate == 1) break; } // close stream if ((err = Pa_CloseStream(stream)) != paNoError) { fprintf(stderr, "Error: failure in closing stream (%x)\n", err); exit(EXIT_FAILURE); } portaudio_simple_free(data); return 0; } cava-0.7.4/input/portaudio.h000066400000000000000000000000661405100172200157440ustar00rootroot00000000000000#pragma once void *input_portaudio(void *audiodata); cava-0.7.4/input/pulse.c000066400000000000000000000110261405100172200150570ustar00rootroot00000000000000#include "input/pulse.h" #include "input/common.h" #include #include #include pa_mainloop *m_pulseaudio_mainloop; void cb(__attribute__((unused)) pa_context *pulseaudio_context, const pa_server_info *i, void *userdata) { // getting default sink name struct audio_data *audio = (struct audio_data *)userdata; free(audio->source); audio->source = malloc(sizeof(char) * 1024); strcpy(audio->source, i->default_sink_name); // appending .monitor suufix audio->source = strcat(audio->source, ".monitor"); // quiting mainloop pa_context_disconnect(pulseaudio_context); pa_context_unref(pulseaudio_context); pa_mainloop_quit(m_pulseaudio_mainloop, 0); pa_mainloop_free(m_pulseaudio_mainloop); } void pulseaudio_context_state_callback(pa_context *pulseaudio_context, void *userdata) { // make sure loop is ready switch (pa_context_get_state(pulseaudio_context)) { case PA_CONTEXT_UNCONNECTED: // printf("UNCONNECTED\n"); break; case PA_CONTEXT_CONNECTING: // printf("CONNECTING\n"); break; case PA_CONTEXT_AUTHORIZING: // printf("AUTHORIZING\n"); break; case PA_CONTEXT_SETTING_NAME: // printf("SETTING_NAME\n"); break; case PA_CONTEXT_READY: // extract default sink name // printf("READY\n"); pa_operation_unref(pa_context_get_server_info(pulseaudio_context, cb, userdata)); break; case PA_CONTEXT_FAILED: printf("failed to connect to pulseaudio server\n"); exit(EXIT_FAILURE); break; case PA_CONTEXT_TERMINATED: // printf("TERMINATED\n"); pa_mainloop_quit(m_pulseaudio_mainloop, 0); break; } } void getPulseDefaultSink(void *data) { struct audio_data *audio = (struct audio_data *)data; pa_mainloop_api *mainloop_api; pa_context *pulseaudio_context; int ret; // Create a mainloop API and connection to the default server m_pulseaudio_mainloop = pa_mainloop_new(); mainloop_api = pa_mainloop_get_api(m_pulseaudio_mainloop); pulseaudio_context = pa_context_new(mainloop_api, "cava device list"); // This function connects to the pulse server pa_context_connect(pulseaudio_context, NULL, PA_CONTEXT_NOFLAGS, NULL); // printf("connecting to server\n"); // This function defines a callback so the server will tell us its state. pa_context_set_state_callback(pulseaudio_context, pulseaudio_context_state_callback, (void *)audio); // starting a mainloop to get default sink // starting with one nonblokng iteration in case pulseaudio is not able to run if (!(ret = pa_mainloop_iterate(m_pulseaudio_mainloop, 0, &ret))) { printf("Could not open pulseaudio mainloop to " "find default device name: %d\n" "check if pulseaudio is running\n", ret); exit(EXIT_FAILURE); } pa_mainloop_run(m_pulseaudio_mainloop, &ret); } void *input_pulse(void *data) { struct audio_data *audio = (struct audio_data *)data; uint16_t frames = audio->FFTtreblebufferSize; int channels = 2; int16_t buf[frames * channels]; /* The sample type to use */ static const pa_sample_spec ss = {.format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2}; audio->format = 16; const int frag_size = frames * channels * audio->format / 8 * 2; // we double this because of cpu performance issues with pulseaudio pa_buffer_attr pb = {.maxlength = (uint32_t)-1, // BUFSIZE * 2, .fragsize = frag_size}; pa_simple *s = NULL; int error; if (!(s = pa_simple_new(NULL, "cava", PA_STREAM_RECORD, audio->source, "audio for cava", &ss, NULL, &pb, &error))) { sprintf(audio->error_message, __FILE__ ": Could not open pulseaudio source: %s, %s. \ To find a list of your pulseaudio sources run 'pacmd list-sources'\n", audio->source, pa_strerror(error)); audio->terminate = 1; } while (!audio->terminate) { if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { sprintf(audio->error_message, __FILE__ ": pa_simple_read() failed: %s\n", pa_strerror(error)); audio->terminate = 1; } pthread_mutex_lock(&lock); write_to_fftw_input_buffers(frames, buf, data); pthread_mutex_unlock(&lock); } pa_simple_free(s); pthread_exit(NULL); return 0; } cava-0.7.4/input/pulse.h000066400000000000000000000001621405100172200150630ustar00rootroot00000000000000// header file for pulse, part of cava. #pragma once void *input_pulse(void *data); void getPulseDefaultSink(); cava-0.7.4/input/shmem.c000066400000000000000000000054751405100172200150530ustar00rootroot00000000000000#include "input/shmem.h" #include "input/common.h" #include #include #include typedef unsigned int u32_t; typedef short s16_t; int rc; // See issue #375 // Hard-coded in squeezelite's output_vis.c, but // this should be the same as mmap_area->buf_size // if you were to dynamically allocate. #define VIS_BUF_SIZE 16384 typedef struct { pthread_rwlock_t rwlock; u32_t buf_size; u32_t buf_index; bool running; u32_t rate; time_t updated; s16_t buffer[VIS_BUF_SIZE]; } vis_t; // input: SHMEM void *input_shmem(void *data) { struct audio_data *audio = (struct audio_data *)data; vis_t *mmap_area; int fd; /* file descriptor to mmaped area */ int mmap_count = sizeof(vis_t); int buf_frames; struct timespec req = {.tv_sec = 0, .tv_nsec = 0}; s16_t silence_buffer[VIS_BUF_SIZE]; for (int i = 0; i < VIS_BUF_SIZE; i++) silence_buffer[i] = 0; printf("input_shmem: source: %s", audio->source); fd = shm_open(audio->source, O_RDWR, 0666); if (fd < 0) { printf("Could not open source '%s': %s\n", audio->source, strerror(errno)); exit(EXIT_FAILURE); } else { mmap_area = mmap(NULL, sizeof(vis_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((intptr_t)mmap_area == -1) { printf("mmap failed - check if squeezelite is running with visualization enabled\n"); exit(EXIT_FAILURE); } } while (!audio->terminate) { // audio rate may change between songs (e.g. 44.1kHz to 96kHz) audio->rate = mmap_area->rate; buf_frames = mmap_area->buf_size / 2; // reread after the whole buffer has changed req.tv_nsec = (1000000 / mmap_area->rate) * buf_frames; if (mmap_area->running) { // Frames are written by squeezelite to the buffer array starting from // buffer[buf_index + 1], looping around the whole array. // Thus, the starting position only affects the phase spectrum of the // fft, and not the power spectrum, so we can just read in the // whole buffer. pthread_mutex_lock(&lock); write_to_fftw_input_buffers(buf_frames, mmap_area->buffer, audio); pthread_mutex_unlock(&lock); nanosleep(&req, NULL); } else { write_to_fftw_input_buffers(buf_frames, silence_buffer, audio); nanosleep(&req, NULL); } } // cleanup if (fd > 0) { if (close(fd) != 0) { printf("Could not close file descriptor %d: %s", fd, strerror(errno)); } } else { printf("Wrong file descriptor %d", fd); } if (munmap(mmap_area, mmap_count) != 0) { printf("Could not munmap() area %p+%d. %s", mmap_area, mmap_count, strerror(errno)); } return 0; } cava-0.7.4/input/shmem.h000066400000000000000000000001261405100172200150440ustar00rootroot00000000000000// header file for shmem, part of cava. #pragma once void *input_shmem(void *data); cava-0.7.4/input/sndio.c000066400000000000000000000026671405100172200150560ustar00rootroot00000000000000#include "input/sndio.h" #include "input/common.h" #include void *input_sndio(void *data) { struct audio_data *audio = (struct audio_data *)data; struct sio_par par; struct sio_hdl *hdl; int16_t buf[audio->FFTtreblebufferSize * 2]; sio_initpar(&par); par.sig = 1; par.bits = 16; par.le = 1; par.rate = 44100; par.rchan = 2; par.appbufsz = sizeof(buf) / par.rchan; if ((hdl = sio_open(audio->source, SIO_REC, 0)) == NULL) { fprintf(stderr, __FILE__ ": Could not open sndio source: %s\n", audio->source); exit(EXIT_FAILURE); } if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par) || par.sig != 1 || par.le != 1 || par.rate != 44100 || par.rchan != audio->channels) { fprintf(stderr, __FILE__ ": Could not set required audio parameters\n"); exit(EXIT_FAILURE); } if (!sio_start(hdl)) { fprintf(stderr, __FILE__ ": sio_start() failed\n"); exit(EXIT_FAILURE); } uint16_t frames = (sizeof(buf) / sizeof(buf[0])) / 2; while (audio->terminate != 1) { if (sio_read(hdl, buf, sizeof(buf)) == 0) { fprintf(stderr, __FILE__ ": sio_read() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } pthread_mutex_lock(&lock); write_to_fftw_input_buffers(frames, buf, audio); pthread_mutex_unlock(&lock); } sio_stop(hdl); sio_close(hdl); return 0; } cava-0.7.4/input/sndio.h000066400000000000000000000001261405100172200150470ustar00rootroot00000000000000// header file for sndio, part of cava. #pragma once void *input_sndio(void *data); cava-0.7.4/output/000077500000000000000000000000001405100172200137645ustar00rootroot00000000000000cava-0.7.4/output/raw.c000066400000000000000000000027231405100172200147250ustar00rootroot00000000000000#include #include #include #include int16_t buf_16; int8_t buf_8; int print_raw_out(int bars_count, int fd, int is_binary, int bit_format, int ascii_range, char bar_delim, char frame_delim, int const f[200]) { if (is_binary) { for (int i = 0; i < bars_count; i++) { int f_limited = f[i]; if (f_limited > (pow(2, bit_format) - 1)) f_limited = pow(2, bit_format) - 1; switch (bit_format) { case 16: buf_16 = f_limited; write(fd, &buf_16, sizeof(int16_t)); break; case 8: buf_8 = f_limited; write(fd, &buf_8, sizeof(int8_t)); break; } } } else { // ascii for (int i = 0; i < bars_count; i++) { int f_ranged = f[i]; if (f_ranged > ascii_range) f_ranged = ascii_range; // finding size of number-string in byte int bar_height_size = 2; // a number + \0 if (f_ranged != 0) bar_height_size += floor(log10(f_ranged)); char bar_height[bar_height_size]; snprintf(bar_height, bar_height_size, "%d", f_ranged); write(fd, bar_height, bar_height_size - 1); write(fd, &bar_delim, sizeof(bar_delim)); } write(fd, &frame_delim, sizeof(frame_delim)); } return 0; } cava-0.7.4/output/raw.h000066400000000000000000000002411405100172200147230ustar00rootroot00000000000000int print_raw_out(int bars_count, int fd, int is_binary, int bit_format, int ascii_range, char bar_delim, char frame_delim, int const f[200]); cava-0.7.4/output/terminal_bcircle.c000066400000000000000000000035501405100172200174310ustar00rootroot00000000000000#include "output/terminal_bcircle.h" #include #include #include #include #include #include #ifndef M_PI #define M_PI 3.141592 #endif #define DEGTORAD(deg) (deg * (180.0f / M_PI)) #define DOT 0x2588 int init_terminal_bcircle(int col, int bgcol) { initscr(); curs_set(0); timeout(0); noecho(); start_color(); use_default_colors(); init_pair(1, col, bgcol); if (bgcol != -1) bkgd(COLOR_PAIR(1)); attron(COLOR_PAIR(1)); // attron(A_BOLD); return 0; } void get_terminal_dim_bcircle(int *w, int *h) { getmaxyx(stdscr, *h, *w); clear(); // clearing in case of resieze } int draw_terminal_bcircle(int tty, int h, int w, int f[200]) { const wchar_t *bars[] = {L"\u2581", L"\u2582", L"\u2583", L"\u2584", L"\u2585", L"\u2586", L"\u2587", L"\u2588"}; // output: check if terminal has been resized if (!tty) { if (LINES != h || COLS != w) { return -1; } } float deg, width, height; int y, x; /* Convert to int */ width = f[1] / 10; height = f[1] / 15; int oy, ox; oy = LINES / 2 - height / 2; ox = COLS / 2 - width / 2; for (x = 0; x < COLS; x++) { for (y = 0; y < LINES; y++) { mvaddstr(y, x, " "); } } /* Draw circle */ for (deg = 0; deg < 360.0f; deg += 1.0f) { x = ox + width + (int)(width * cos(DEGTORAD(deg))); y = oy + height + (int)(height * sin(DEGTORAD(deg))); mvaddwstr(y, x, bars[7]); } refresh(); return 0; } // general: cleanup void cleanup_terminal_bcircle(void) { echo(); system("setfont >/dev/null 2>&1"); system("setfont /usr/share/consolefonts/Lat2-Fixed16.psf.gz >/dev/null 2>&1"); system("setterm -blank 10"); endwin(); system("clear"); } cava-0.7.4/output/terminal_bcircle.h000066400000000000000000000003311405100172200174300ustar00rootroot00000000000000#pragma once int init_terminal_bcircle(int col, int bgcol); void get_terminal_dim_bcircle(int *w, int *h); int draw_terminal_bcircle(int virt, int height, int width, int f[200]); void cleanup_terminal_bcircle(void); cava-0.7.4/output/terminal_ncurses.c000066400000000000000000000233441405100172200175130ustar00rootroot00000000000000#include "output/terminal_ncurses.h" #include #include #include #include #include "util.h" int gradient_size = 64; struct colors { NCURSES_COLOR_T color; NCURSES_COLOR_T R; NCURSES_COLOR_T G; NCURSES_COLOR_T B; }; #define COLOR_REDEFINITION -2 #define MAX_COLOR_REDEFINITION 256 const wchar_t *bar_heights[] = {L"\u2581", L"\u2582", L"\u2583", L"\u2584", L"\u2585", L"\u2586", L"\u2587", L"\u2588"}; int num_bar_heights = (sizeof(bar_heights) / sizeof(bar_heights[0])); // static struct colors the_color_redefinitions[MAX_COLOR_REDEFINITION]; static void parse_color(char *color_string, struct colors *color) { if (color_string[0] == '#') { if (!can_change_color()) { cleanup_terminal_ncurses(); fprintf(stderr, "Your terminal can not change color definitions, " "please use one of the predefined colors.\n"); exit(EXIT_FAILURE); } color->color = COLOR_REDEFINITION; sscanf(++color_string, "%02hx%02hx%02hx", &color->R, &color->G, &color->B); } } /* static void remember_color_definition(NCURSES_COLOR_T color_number) { int index = color_number - 1; // array starts from zero and colors - not if(the_color_redefinitions[index].color == 0) { the_color_redefinitions[index].color = color_number; color_content(color_number, &the_color_redefinitions[index].R, &the_color_redefinitions[index].G, &the_color_redefinitions[index].B); } } */ // ncurses use color range [0, 1000], and we - [0, 255] #define CURSES_COLOR_COEFFICIENT(X) ((X)*1000.0 / 0xFF + 0.5) #define COLORS_STRUCT_NORMALIZE(X) \ CURSES_COLOR_COEFFICIENT(X.R), CURSES_COLOR_COEFFICIENT(X.G), CURSES_COLOR_COEFFICIENT(X.B) static NCURSES_COLOR_T change_color_definition(NCURSES_COLOR_T color_number, char *const color_string, NCURSES_COLOR_T predef_color) { struct colors color = {0}; parse_color(color_string, &color); NCURSES_COLOR_T return_color_number = predef_color; if (color.color == COLOR_REDEFINITION) { // remember_color_definition(color_number); init_color(color_number, COLORS_STRUCT_NORMALIZE(color)); return_color_number = color_number; } return return_color_number; } void init_terminal_ncurses(char *const fg_color_string, char *const bg_color_string, int predef_fg_color, int predef_bg_color, int gradient, int gradient_count, char **gradient_colors, int *width, int *lines) { initscr(); curs_set(0); timeout(0); noecho(); start_color(); use_default_colors(); getmaxyx(stdscr, *lines, *width); clear(); NCURSES_COLOR_T color_pair_number = 16; NCURSES_COLOR_T bg_color_number; bg_color_number = change_color_definition(0, bg_color_string, predef_bg_color); if (!gradient) { NCURSES_COLOR_T fg_color_number; fg_color_number = change_color_definition(1, fg_color_string, predef_fg_color); init_pair(color_pair_number, fg_color_number, bg_color_number); } else if (gradient) { // 0 -> col1, 1-> col1<=>col2, 2 -> col2 and so on short unsigned int rgb[2 * gradient_count - 1][3]; char next_color[14]; gradient_size = *lines; if (gradient_size > COLORS) gradient_size = COLORS - 1; if (gradient_size > COLOR_PAIRS) gradient_size = COLOR_PAIRS - 1; if (gradient_size > MAX_COLOR_REDEFINITION) gradient_size = MAX_COLOR_REDEFINITION - 1; for (int i = 0; i < gradient_count; i++) { int col = (i + 1) * 2 - 2; sscanf(gradient_colors[i] + 1, "%02hx%02hx%02hx", &rgb[col][0], &rgb[col][1], &rgb[col][2]); } // sscanf(gradient_color_1 + 1, "%02hx%02hx%02hx", &rgb[0][0], &rgb[0][1], &rgb[0][2]); // sscanf(gradient_color_2 + 1, "%02hx%02hx%02hx", &rgb[1][0], &rgb[1][1], &rgb[1][2]); int individual_size = gradient_size / (gradient_count - 1); for (int i = 0; i < gradient_count - 1; i++) { int col = (i + 1) * 2 - 2; if (i == gradient_count - 1) col = 2 * (gradient_count - 1) - 2; for (int j = 0; j < individual_size; j++) { for (int k = 0; k < 3; k++) { rgb[col + 1][k] = rgb[col][k] + (rgb[col + 2][k] - rgb[col][k]) * (j / (individual_size * 0.85)); if (rgb[col + 1][k] > 255) rgb[col][k] = 0; if (j > individual_size * 0.85) rgb[col + 1][k] = rgb[col + 2][k]; } sprintf(next_color, "#%02x%02x%02x", rgb[col + 1][0], rgb[col + 1][1], rgb[col + 1][2]); change_color_definition(color_pair_number, next_color, color_pair_number); init_pair(color_pair_number, color_pair_number, bg_color_number); color_pair_number++; } } int left = individual_size * (gradient_count - 1); int col = 2 * (gradient_count)-2; while (left < gradient_size) { sprintf(next_color, "#%02x%02x%02x", rgb[col][0], rgb[col][1], rgb[col][2]); change_color_definition(color_pair_number, next_color, color_pair_number); init_pair(color_pair_number, color_pair_number, bg_color_number); color_pair_number++; left++; } color_pair_number--; } attron(COLOR_PAIR(color_pair_number)); if (bg_color_number != -1) bkgd(COLOR_PAIR(color_pair_number)); for (int y = 0; y < *lines; y++) { for (int x = 0; x < *width; x++) { mvaddch(y, x, ' '); } } refresh(); } void change_colors(int cur_height, int tot_height) { tot_height /= gradient_size; if (tot_height < 1) tot_height = 1; cur_height /= tot_height; if (cur_height > gradient_size - 1) cur_height = gradient_size - 1; attron(COLOR_PAIR(cur_height + 16)); } void get_terminal_dim_ncurses(int *width, int *height) { getmaxyx(stdscr, *height, *width); gradient_size = *height; clear(); // clearing in case of resieze } #define TERMINAL_RESIZED -1 int draw_terminal_ncurses(int is_tty, int terminal_height, int terminal_width, int bars_count, int bar_width, int bar_spacing, int rest, const int bars[256], int previous_frame[256], int gradient, int x_axis_info) { const int height = terminal_height - 1; // output: check if terminal has been resized if (!is_tty) { if (x_axis_info) terminal_height++; if (LINES != terminal_height || COLS != terminal_width) { return TERMINAL_RESIZED; if (x_axis_info) terminal_height--; } } // Compute how much of the screen we possibly need to update ahead-of-time. int max_update_y = 0; for (int bar = 0; bar < bars_count; bar++) { max_update_y = max(max_update_y, max(bars[bar], previous_frame[bar])); } max_update_y = (max_update_y + num_bar_heights) / num_bar_heights; for (int y = 0; y < max_update_y; y++) { if (gradient) { change_colors(y, height); } for (int bar = 0; bar < bars_count; bar++) { if (bars[bar] == previous_frame[bar]) { continue; } int cur_col = bar * bar_width + bar * bar_spacing + rest; int f_cell = (bars[bar] - 1) / num_bar_heights; int f_last_cell = (previous_frame[bar] - 1) / num_bar_heights; if (f_cell >= y) { int bar_step; if (f_cell == y) { // The "cap" of the bar occurs at this [y]. bar_step = (bars[bar] - 1) % num_bar_heights; } else if (f_last_cell <= y) { // The bar is full at this [y]. bar_step = num_bar_heights - 1; } else { // No update necessary since last frame. continue; } for (int col = cur_col, i = 0; i < bar_width; i++, col++) { if (is_tty) { mvaddch(height - y, col, 0x41 + bar_step); } else { mvaddwstr(height - y, col, bar_heights[bar_step]); } } } else if (f_last_cell >= y) { // This bar was taller during the last frame than during this frame, so // clear the excess characters. for (int col = cur_col, i = 0; i < bar_width; i++, col++) { mvaddch(height - y, col, ' '); } } } } refresh(); return 0; } // general: cleanup void cleanup_terminal_ncurses(void) { echo(); system("setfont >/dev/null 2>&1"); system("setfont /usr/share/consolefonts/Lat2-Fixed16.psf.gz >/dev/null 2>&1"); system("setterm -blank 10 >/dev/null 2>&1"); /*for(int i = 0; i < gradient_size; ++i) { if(the_color_redefinitions[i].color) { init_color(the_color_redefinitions[i].color, the_color_redefinitions[i].R, the_color_redefinitions[i].G, the_color_redefinitions[i].B); } } */ standend(); endwin(); system("clear"); } cava-0.7.4/output/terminal_ncurses.h000066400000000000000000000011611405100172200175110ustar00rootroot00000000000000void init_terminal_ncurses(char *const fg_color_string, char *const bg_color_string, int predef_fg_color, int predef_bg_color, int gradient, int gradient_count, char **gradient_colors, int *width, int *height); void get_terminal_dim_ncurses(int *width, int *height); int draw_terminal_ncurses(int is_tty, int terminal_height, int terminal_width, int bars_count, int bar_width, int bar_spacing, int rest, const int bars[256], int previous_frame[256], int gradient, int x_axis_info); void cleanup_terminal_ncurses(void); cava-0.7.4/output/terminal_noncurses.c000066400000000000000000000221421405100172200200430ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include wchar_t *frame_buffer; wchar_t *barstring[8]; wchar_t *spacestring; int buf_length; char *ttyframe_buffer; char *ttybarstring[8]; char *ttyspacestring; int ttybuf_length; int setecho(int fd, int onoff) { struct termios t; if (tcgetattr(fd, &t) == -1) return -1; if (onoff == 0) t.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON); else t.c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL | ICANON); if (tcsetattr(fd, TCSANOW, &t) == -1) return -1; return 0; } // general: cleanup void free_terminal_noncurses(void) { free(frame_buffer); free(ttyframe_buffer); free(spacestring); free(ttyspacestring); for (int i = 0; i < 8; i++) { free(barstring[i]); free(ttybarstring[i]); } } int init_terminal_noncurses(int tty, int col, int bgcol, int width, int lines, int bar_width) { free_terminal_noncurses(); if (tty) { ttybuf_length = sizeof(char) * width * lines * 10; ttyframe_buffer = (char *)malloc(ttybuf_length); ttyspacestring = (char *)malloc(sizeof(char) * (bar_width + 1)); // clearing barstrings for (int n = 0; n < 8; n++) { ttybarstring[n] = (char *)malloc(sizeof(char) * (bar_width + 1)); ttybarstring[n][0] = '\0'; } ttyspacestring[0] = '\0'; ttyframe_buffer[0] = '\0'; // creating barstrings for drawing for (int n = 0; n < bar_width; n++) { strcat(ttybarstring[0], "H"); strcat(ttybarstring[1], "A"); strcat(ttybarstring[2], "B"); strcat(ttybarstring[3], "C"); strcat(ttybarstring[4], "D"); strcat(ttybarstring[5], "E"); strcat(ttybarstring[6], "F"); strcat(ttybarstring[7], "G"); strcat(ttyspacestring, " "); } } else if (!tty) { buf_length = sizeof(wchar_t) * width * lines * 10; frame_buffer = (wchar_t *)malloc(buf_length); spacestring = (wchar_t *)malloc(sizeof(wchar_t) * (bar_width + 1)); // clearing barstrings for (int n = 0; n < 8; n++) { barstring[n] = (wchar_t *)malloc(sizeof(wchar_t) * (bar_width + 1)); barstring[n][0] = '\0'; } spacestring[0] = '\0'; frame_buffer[0] = '\0'; // creating barstrings for drawing for (int n = 0; n < bar_width; n++) { wcscat(barstring[0], L"\u2588"); wcscat(barstring[1], L"\u2581"); wcscat(barstring[2], L"\u2582"); wcscat(barstring[3], L"\u2583"); wcscat(barstring[4], L"\u2584"); wcscat(barstring[5], L"\u2585"); wcscat(barstring[6], L"\u2586"); wcscat(barstring[7], L"\u2587"); wcscat(spacestring, L" "); } } col += 30; system("setterm -cursor off"); system("setterm -blank 0"); // output: reset console printf("\033[0m\n"); system("clear"); if (col) printf("\033[%dm", col); // setting color // printf("\033[1m"); // setting "bright" color mode, looks cooler... I think if (bgcol != 0) { bgcol += 40; printf("\033[%dm", bgcol); for (int n = lines; n >= 0; n--) { for (int i = 0; i < width; i++) { printf(" "); // setting backround color } if (n != 0) printf("\n"); else printf("\r"); } printf("\033[%dA", lines); // moving cursor back up } setecho(STDIN_FILENO, 0); return 0; } void get_terminal_dim_noncurses(int *width, int *lines) { struct winsize dim; ioctl(STDOUT_FILENO, TIOCGWINSZ, &dim); *lines = (int)dim.ws_row; *width = (int)dim.ws_col; system("clear"); // clearing in case of resieze } int draw_terminal_noncurses(int tty, int lines, int width, int number_of_bars, int bar_width, int bar_spacing, int rest, int bars[256], int previous_frame[256], int x_axis_info) { int current_cell, prev_cell, same_line, new_line, cx; struct winsize dim; same_line = 0; new_line = 0; cx = 0; if (!tty) { // output: check if terminal has been resized ioctl(STDOUT_FILENO, TIOCGWINSZ, &dim); if (x_axis_info) lines++; if ((int)dim.ws_row != (lines) || (int)dim.ws_col != width) return -1; if (x_axis_info) lines--; } if (tty) ttyframe_buffer[0] = '\0'; else if (!tty) frame_buffer[0] = '\0'; for (int current_line = lines - 1; current_line >= 0; current_line--) { int same_bar = 0; int center_adjusted = 0; for (int i = 0; i < number_of_bars; i++) { current_cell = bars[i] - current_line * 8; prev_cell = previous_frame[i] - current_line * 8; // same as last frame if ((current_cell < 1 && prev_cell < 1) || (current_cell > 7 && prev_cell > 7) || (current_cell == prev_cell)) { same_bar++; } else { if (tty) { if (same_line > 0) { cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[%dB", same_line); // move down new_line += same_line; same_line = 0; } if (same_bar > 0) { cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[%dC", (bar_width + bar_spacing) * same_bar); // move forward same_bar = 0; } if (!center_adjusted && rest) { cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[%dC", rest); center_adjusted = 1; } if (current_cell < 1) cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "%s", ttyspacestring); else if (current_cell > 7) cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "%s", ttybarstring[0]); else cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "%s", ttybarstring[current_cell]); if (bar_spacing) cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\033[%dC", bar_spacing); } else if (!tty) { if (same_line > 0) { cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[%dB", same_line); // move down new_line += same_line; same_line = 0; } if (same_bar > 0) { cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[%dC", (bar_width + bar_spacing) * same_bar); // move forward same_bar = 0; } if (!center_adjusted && rest) { cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[%dC", rest); center_adjusted = 1; } if (current_cell < 1) cx += swprintf(frame_buffer + cx, buf_length - cx, spacestring); else if (current_cell > 7) cx += swprintf(frame_buffer + cx, buf_length - cx, barstring[0]); else cx += swprintf(frame_buffer + cx, buf_length - cx, barstring[current_cell]); if (bar_spacing) cx += swprintf(frame_buffer + cx, buf_length - cx, L"\033[%dC", bar_spacing); } } } if (same_bar != number_of_bars) { if (current_line != 0) { if (tty) cx += snprintf(ttyframe_buffer + cx, ttybuf_length - cx, "\n"); else if (!tty) cx += swprintf(frame_buffer + cx, buf_length - cx, L"\n"); new_line++; } } else { same_line++; } } if (same_line != lines) { if (tty) printf("%s\r\033[%dA", ttyframe_buffer, new_line); else if (!tty) printf("%ls\r\033[%dA", frame_buffer, new_line); fflush(stdout); } return 0; } void cleanup_terminal_noncurses(void) { setecho(STDIN_FILENO, 1); printf("\033[0m\n"); system("setfont >/dev/null 2>&1"); system("setfont /usr/share/consolefonts/Lat2-Fixed16.psf.gz >/dev/null 2>&1"); system("setterm -cursor on"); system("setterm -blank 10"); system("clear"); } cava-0.7.4/output/terminal_noncurses.h000066400000000000000000000006401405100172200200470ustar00rootroot00000000000000int init_terminal_noncurses(int inAtty, int col, int bgcol, int w, int h, int bar_width); void get_terminal_dim_noncurses(int *w, int *h); int draw_terminal_noncurses(int inAtty, int lines, int width, int number_of_bars, int bar_width, int bar_spacing, int rest, int bars[256], int previous_frame[256], int x_axis_info); void cleanup_terminal_noncurses(void); cava-0.7.4/todo000066400000000000000000000003471405100172200133200ustar00rootroot00000000000000TODO ---- * config option print cut-off frequencies on x-axis * config option different color for different threshold amplitude * possibility to save settings to config file * openGL * plug-in api * new demo video * JACK support cava-0.7.4/util.h000066400000000000000000000011561405100172200135550ustar00rootroot00000000000000#pragma once #define max(a, b) \ ({ \ __typeof__(a) _a = (a); \ __typeof__(b) _b = (b); \ _a > _b ? _a : _b; \ }) #define ARRAY_SIZE(x) ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))